From acf0e761bf7aacf341ff3a56b3e1359e2070e12f Mon Sep 17 00:00:00 2001 From: bob-white Date: Sun, 13 Aug 2017 00:53:56 -0500 Subject: [PATCH] Adding a filtered view class This creates a view into an ObservableCollection and lets you apply a filter against that view. Each FilteredView can be bound to a different control, but still reference the same underlying collection. When the base collection changes, each view is updated. --- mGui/observable.py | 50 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/mGui/observable.py b/mGui/observable.py index 0db2223..6fdd55c 100644 --- a/mGui/observable.py +++ b/mGui/observable.py @@ -3,7 +3,8 @@ @author: stevetheodore """ import itertools -from collections import MutableSequence, Sequence +from weakref import proxy +from collections import MutableSequence, Sequence, Sized from mGui.bindings import BindableObject from mGui.events import MayaEvent, Event @@ -117,9 +118,11 @@ def reverse(self): self.update_bindings() self.onCollectionChanged(sorted=True) + def __repr__(self): + return '{0.__class__.__name__}({0._internal_collection!r})'.format(self) -class ImmediateObservableCollection(ObservableCollection): +class ImmediateObservableCollection(ObservableCollection): def __init__(self, *items): super(ImmediateObservableCollection, self).__init__(*items) @@ -200,6 +203,49 @@ def __getitem__(self, item): return self.view.__getitem__(item) +class FilteredView(Sized, BindableObject): + """ + Creates a filtered view of an observable. + + This allows us to create multiple views from a single observable collection, + and each view can be bound to a different control. + + """ + + _BIND_SRC = 'view' + _BIND_TGT = None + + def __init__(self, observable, _filter=lambda x: x): + if not isinstance(observable, ObservableCollection): + raise TypeError() + self._observable = proxy(observable) + self._filter = _filter + self._observable.onCollectionChanged += self.update_bindings + + def __len__(self): + return len(self.view) + + @property + def view(self): + if self._observable is None: + return tuple() + return tuple(itertools.ifilter(self._filter, self._observable)) + + @property + def viewCount(self): + return len(self) + + def __repr__(self): + return '{0.__class__.__name__}({0._observable!r}, {0._filter!r})'.format(self) + + def update_filter(self, _filter=lambda x: x): + self._filter = _filter + self.update_bindings() + + def update_bindings(self, *args, **kwargs): + super(FilteredView, self).update_bindings() + + class BoundCollection(Sequence, BindableObject): """ An iterable object which can be bound to a collection. When the source