- Revision
- 11099
- Author
- vajda
- Date
- 2006-07-08 09:26:57 -0700 (Sat, 08 Jul 2006)
Log Message
- moved DelegatingIndex to C
- upgraded build to chandlerdb 0.6-29
- fixed bug in MultiIntersection of 1, made it behave as an empty set
- refactored collections code to support dynamic source changes and deletion
- fixed bug 6210 (http://bugzilla.osafoundation.org/show_bug.cgi?id=6210)
- upgraded build to chandlerdb 0.6-29
- fixed bug in MultiIntersection of 1, made it behave as an empty set
- refactored collections code to support dynamic source changes and deletion
- fixed bug 6210 (http://bugzilla.osafoundation.org/show_bug.cgi?id=6210)
Modified Paths
Diff
Modified: trunk/chandler/Makefile (11098 => 11099)
--- trunk/chandler/Makefile 2006-07-08 16:09:33 UTC (rev 11098) +++ trunk/chandler/Makefile 2006-07-08 16:26:57 UTC (rev 11099) @@ -66,7 +66,7 @@ # these get installed into release or debug ARCHIVES=$(CHANDLERARCHIVES)/Launchers-$(SNAP)-0.8-$(BP)8.tar.gz \ - $(CHANDLERARCHIVES)/chandlerdb-$(SNAP)-0.6-$(BP)28.tar.gz \ + $(CHANDLERARCHIVES)/chandlerdb-$(SNAP)-0.6-$(BP)29.tar.gz \ $(CHANDLERARCHIVES)/db-$(SNAP)-4.4.20-$(BP)5.tar.gz \ $(CHANDLERARCHIVES)/python-$(SNAP)-2.4.3-$(BP)3.tar.gz \ $(CHANDLERARCHIVES)/epydoc-$(SNAP)-2.1-$(BP)9.tar.gz \
Modified: trunk/chandler/application/Utility.py (11098 => 11099)
--- trunk/chandler/application/Utility.py 2006-07-08 16:09:33 UTC (rev 11098) +++ trunk/chandler/application/Utility.py 2006-07-08 16:26:57 UTC (rev 11099) @@ -33,7 +33,7 @@ # with your name (and some helpful text). The comment's really there just to # cause Subversion to warn you of a conflict when you update, in case someone # else changes it at the same time you do (that's why it's on the same line). -SCHEMA_VERSION = "215" # John: added bufferedDraw to BoxContainer +SCHEMA_VERSION = "216" #vajda: refactored collections for dynamic source changes logger = None # initialized in initLogging()
Modified: trunk/chandler/parcels/osaf/pim/collections.py (11098 => 11099)
--- trunk/chandler/parcels/osaf/pim/collections.py 2006-07-08 16:09:33 UTC (rev 11098) +++ trunk/chandler/parcels/osaf/pim/collections.py 2006-07-08 16:26:57 UTC (rev 11099) @@ -22,7 +22,7 @@ from chandlerdb.item.c import Default from repository.item.Sets import \ Set, MultiUnion, Union, MultiIntersection, Intersection, Difference, \ - KindSet, ExpressionFilteredSet, MethodFilteredSet + KindSet, ExpressionFilteredSet, MethodFilteredSet, EmptySet from repository.item.Collection import Collection from osaf.pim.items import ContentItem @@ -31,7 +31,6 @@ DEBUG = logger.getEffectiveLevel() <= logging.DEBUG - class ContentCollection(ContentItem, Collection): """ The base class for Chandler Collection types. @@ -107,7 +106,7 @@ invitees, byRef=['contentsOwner', 'subscribers'] ), - sharing = schema.Cloud( none = ["displayName"] ), + sharing = schema.Cloud(none=["displayName"]), ) def __str__(self): @@ -163,9 +162,7 @@ set = schema.One(schema.TypeReference('//Schema/Core/AbstractSet')) - schema.kindInfo( - displayName=u"KindCollection" - ) + schema.kindInfo(displayName=u"KindCollection") kind = schema.One(schema.TypeReference('//Schema/Core/Kind')) recursive = schema.One(schema.Boolean, defaultValue=False) @@ -199,13 +196,9 @@ item.delete(True) -class DifferenceCollection(ContentCollection): +class WrapperCollection(ContentCollection): """ - A ContentCollection containing the set theoretic difference of two - ContentCollections. - - The C{sources} attribute (a list) contains the ContentCollection - instances to be differenced. + A class for collections wrapping other collections """ __metaclass__ = schema.CollectionClass @@ -213,48 +206,15 @@ set = schema.One(schema.TypeReference('//Schema/Core/AbstractSet')) - schema.kindInfo( - displayName=u"DifferenceCollection" - ) + sources = schema.Sequence(ContentCollection, otherName='sourceFor', + doc="the collections being wrapped", + initialValue=[]) + schema.addClouds(copying=schema.Cloud(byCloud=[sources])) - sources = schema.Sequence(ContentCollection, otherName='sourceFor') - - schema.addClouds( - copying = schema.Cloud(byCloud=[sources]), - ) - def __init__(self, *args, **kwds): - super(DifferenceCollection, self).__init__(*args, **kwds) + super(WrapperCollection, self).__init__(*args, **kwds) - a, b = self.sources - setattr(self, self.__collection__, Difference(a, b)) - - -class MultiCollection(ContentCollection): - """ - A ContentCollection containing the set theoretic union or intersection - of at least two ContentCollections. - - The C{sources} attribute (a ref collection) contains the ContentCollection - instances to be combined and can be changed. - """ - - __metaclass__ = schema.CollectionClass - __collection__ = 'set' - - set = schema.One(schema.TypeReference('//Schema/Core/AbstractSet')) - - sources = schema.Sequence(ContentCollection, - otherName='sourceFor', initialValue=[]) - - schema.kindInfo(displayName=u"UnionCollection") - schema.addClouds(copying = schema.Cloud(byCloud=[sources])) - - def __init__(self, *args, **kwds): - - super(MultiCollection, self).__init__(*args, **kwds) - self._sourcesChanged_() self.watchCollection(self, 'sources', '_sourcesChanged') @@ -267,7 +227,7 @@ if op == 'add': set = self._sourcesChanged_() sourceChanged = set.sourceChanged - actualSource = set.findSource(source.itsUUID) + actualSource = set.findSource(sourceId) assert actualSource is not None for uuid in source.iterkeys(): view._notifyChange(sourceChanged, 'add', 'collection', @@ -276,7 +236,7 @@ elif op == 'remove': set = getattr(self, self.__collection__) sourceChanged = set.sourceChanged - actualSource = set.findSource(source.itsUUID) + actualSource = set.findSource(sourceId) assert actualSource is not None for uuid in source.iterkeys(): view._notifyChange(sourceChanged, 'remove', 'collection', @@ -295,12 +255,81 @@ self.sources.remove(source) -class UnionCollection(MultiCollection): +class SingleSourceWrapperCollection(WrapperCollection): """ + A class for collections wrapping another collection + """ + + def _getSource(self): + sources = self.sources + if sources: + return sources.first() + return None + def _setSource(self, source): + sources = self.sources + if sources and sources.first() is not source: + sources.clear() + if source is not None: + sources.append(source) + def _delSource(self): + self.sources.clear() + source = property(_getSource, _setSource, _delSource) + + def __init__(self, *args, **kwds): + + source = kwds.pop('source', None) + if source is not None: + kwds['sources'] = [source] + + super(SingleSourceWrapperCollection, self).__init__(*args, **kwds) + + +class DifferenceCollection(WrapperCollection): + """ + A ContentCollection containing the set theoretic difference of two + ContentCollections. + + The C{sources} attribute (a list) contains the ContentCollection + instances to be differenced. + """ + + schema.kindInfo(displayName=u"DifferenceCollection") + + def _sourcesChanged_(self): + + sources = self.sources + sourceCount = len(sources) + + if sourceCount == 0: + set = EmptySet() + elif sourceCount == 1: + set = getattr(self, self.__collection__) + source = sources.first() + if instance(set, Difference): + if set._left[0] == source.itsUUID: + set = Set(source) + else: + set = EmptySet() + else: + set = Set(source) + elif sourceCount == 2: + a, b = self.sources + set = Difference(a, b) + else: + raise ValueError, 'too many sources' + + setattr(self, self.__collection__, set) + return set + + +class UnionCollection(WrapperCollection): + """ A ContentCollection containing the set theoretic union of at least two ContentCollections. """ + schema.kindInfo(displayName=u"UnionCollection") + def _sourcesChanged_(self): sources = self.sources @@ -308,11 +337,12 @@ # For now, when we join collections with Union, we pull trash # out of the equation with withoutTrash() - if sourceCount == 1: + if sourceCount == 0: + set = EmptySet() + elif sourceCount == 1: set = Set(sources.first().withoutTrash()) elif sourceCount == 2: - left = sources.first() - right = sources.next(left) + left, right = sources set = Union(left.withoutTrash(), right.withoutTrash()) else: set = MultiUnion(*(source.withoutTrash() @@ -322,12 +352,14 @@ return set -class IntersectionCollection(MultiCollection): +class IntersectionCollection(WrapperCollection): """ A ContentCollection containing the set theoretic intersection of at least two ContentCollections. """ + schema.kindInfo(displayName=u"IntersectionCollection") + def _sourcesChanged_(self): sources = self.sources @@ -335,11 +367,10 @@ # For now, when we join collections with Intersection, we pull trash # out of the equation with withoutTrash() - if sourceCount == 1: - set = Set(sources.first().withoutTrash()) + if sourceCount < 2: + set = EmptySet() elif sourceCount == 2: - left = sources.first() - right = sources.next(left) + left, right = sources set = Intersection(left.withoutTrash(), right.withoutTrash()) else: set = MultiIntersection(*(source.withoutTrash() @@ -349,7 +380,7 @@ return set -class FilteredCollection(ContentCollection): +class FilteredCollection(SingleSourceWrapperCollection): """ A ContentCollection which is the result of applying a boolean predicate to every item of another ContentCollection. @@ -366,49 +397,33 @@ Failure to provide this list will result in missing notifications. """ - __metaclass__ = schema.CollectionClass - __collection__ = 'set' + schema.kindInfo(displayName=u"FilteredCollection") - set = schema.One(schema.TypeReference('//Schema/Core/AbstractSet')) - - schema.kindInfo( - displayName=u"FilteredCollection" - ) - - sources = schema.Sequence(ContentCollection, otherName='sourceFor') - filterExpression = schema.One(schema.Text) filterMethod = schema.One(schema.Tuple) filterAttributes = schema.Sequence(schema.Symbol, initialValue=[]) - schema.addClouds( - copying = schema.Cloud(byCloud=[sources]), - ) + def _sourcesChanged_(self): - def __init__(self, *args, **kwds): + source = self.source + if source is None: + s = EmptySet() + else: + attrTuples = set() + for name in self.filterAttributes: + attrTuples.add((name, "set")) + attrTuples.add((name, "remove")) + attrs = tuple(attrTuples) - source = kwds.pop('source', None) - if source is not None: - kwds['sources'] = [source] + if hasattr(self, 'filterExpression'): + s = ExpressionFilteredSet(source, self.filterExpression, attrs) + else: + s = MethodFilteredSet(source, self.filterMethod, attrs) - super(FilteredCollection, self).__init__(*args, **kwds) + setattr(self, self.__collection__, s) + return s - attrTuples = set() - for i in self.filterAttributes: - attrTuples.add((i, "set")) - attrTuples.add((i, "remove")) - source = self.sources.first() - attrs = tuple(attrTuples) - - if 'filterExpression' in kwds: - setattr(self, self.__collection__, - ExpressionFilteredSet(source, self.filterExpression, attrs)) - else: - setattr(self, self.__collection__, - MethodFilteredSet(source, self.filterMethod, attrs)) - - class AppCollection(ContentCollection): """ AppCollections implement inclusions, exclusions, source, @@ -626,35 +641,33 @@ pass -class IndexedSelectionCollection(ContentCollection): +class IndexedSelectionCollection(SingleSourceWrapperCollection): """ A collection that adds an index, e.g. for sorting items, a selection and visibility attribute to another source collection. """ - __metaclass__ = schema.CollectionClass - __collection__ = 'set' + indexName = schema.One(schema.Symbol, initialValue="__adhoc__") - set = schema.One(schema.TypeReference('//Schema/Core/AbstractSet')) + def _sourcesChanged_(self): + + source = self.source + trash = schema.ns('osaf.pim', self.itsView).trashCollection - indexName = schema.One(schema.Text, initialValue="__adhoc__") - source = schema.One(ContentCollection, defaultValue=None) - - def __init__(self, *args, **kwds): - - super(IndexedSelectionCollection, self).__init__(*args, **kwds) - - trash = schema.ns('osaf.pim', self.itsView).trashCollection - if (isinstance(self.source, MultiCollection) and - trash not in self.source.sources): + if source is None: + set = EmptySet() + elif (isinstance(source, WrapperCollection) and + trash not in source.sources): # bug 5899 - alpha2 workaround: When SmartCollections are # wrapped with IntersectionCollection/UnionCollection, # they drop the trash. So we artificially insert it back - sourceMinusTrash = Difference(self.source, trash) - setattr(self, self.__collection__, sourceMinusTrash) + set = Difference(source, trash) else: - setattr(self, self.__collection__, Set(self.source)) + set = Set(self.source) + setattr(self, self.__collection__, set) + return set + def getCollectionIndex(self, indexName=None): """ Get the index. If it doesn't exist, create. Also create a RangeSet @@ -716,7 +729,6 @@ self.setDescending (currentIndexName, not self.isDescending(currentIndexName)) self.setSelectionRanges(newRanges) - def __len__(self): return len(self.getCollectionIndex()) @@ -748,7 +760,7 @@ # Range-based selection methods # - def getSelectionRanges (self): + def getSelectionRanges(self): """ Return the ranges associated with the current index as an array of tuples, where each tuple represents a start and @@ -756,7 +768,7 @@ """ return self.getCollectionIndex().getRanges() - def setSelectionRanges (self, ranges): + def setSelectionRanges(self, ranges): """ Sets the ranges associated with the current index with C{ranges} which should be an array of tuples, where each @@ -765,7 +777,7 @@ """ self.setRanges(self.indexName, ranges) - def isSelected (self, range): + def isSelected(self, range): """ Returns C{True} if the C{range} is completely inside the selected ranges of the index. C{range} may be a tuple: (start, end) or @@ -774,7 +786,7 @@ """ return self.getCollectionIndex().isInRanges(range) - def addSelectionRange (self, range): + def addSelectionRange(self, range): """ Selects a C{range} of indexes. C{range} may be a tuple: (start, end) or an integer index, where negative indexing @@ -782,7 +794,7 @@ """ self.addRange(self.indexName, range) - def removeSelectionRange (self, range): + def removeSelectionRange(self, range): """ Unselects a C{range} of indexes. C{range} may be a tuple: (start, end) or an integer index, where negative indexing @@ -793,14 +805,14 @@ # Item-based selection methods # - def setSelectionToItem (self, item): + def setSelectionToItem(self, item): """ Sets the entire selection to include only the C{item}. """ index = self.index (item) self.setRanges(self.indexName, [(index, index)]) - def getFirstSelectedItem (self): + def getFirstSelectedItem(self): """ Returns the first selected item in the index or C{None} if there is no selection. @@ -827,13 +839,13 @@ for idx in range(start,end+1): yield self[idx] - def selectItem (self, item): + def selectItem(self, item): """ Selects an C{item} in the index. """ self.addSelectionRange (self.index (item)) - def unselectItem (self, item): + def unselectItem(self, item): """ Unselects an C{item} in the index. """ @@ -843,7 +855,7 @@ # index-based methods # - def __getitem__ (self, index): + def __getitem__(self, index): """ Support indexing using []. """ @@ -852,7 +864,7 @@ self.getCollectionIndex() return self.getByIndex(self.indexName, index) - def index (self, item): + def index(self, item): """ Return the position of item in the index. """ @@ -863,7 +875,6 @@ self.getCollectionIndex() return self.positionInIndex(self.indexName, item) - def add(self, item): self.source.add(item)
Modified: trunk/chandler/repository/item/Indexed.py (11098 => 11099)
--- trunk/chandler/repository/item/Indexed.py 2006-07-08 16:09:33 UTC (rev 11098) +++ trunk/chandler/repository/item/Indexed.py 2006-07-08 16:26:57 UTC (rev 11099) @@ -451,7 +451,7 @@ def iterindexkeys(self, indexName, first=None, last=None): - for key in self.getIndex(indexName).__iter__(first, last): + for key in self.getIndex(indexName).iterkeys(first, last): yield key def iterindexvalues(self, indexName, first=None, last=None): @@ -614,7 +614,7 @@ def _checkIndexes(self, logger, item, attribute): result = True - + if self._indexes: try: indexes = self._indexes
Modified: trunk/chandler/repository/item/Indexes.py (11098 => 11099)
--- trunk/chandler/repository/item/Indexes.py 2006-07-08 16:09:33 UTC (rev 11098) +++ trunk/chandler/repository/item/Indexes.py 2006-07-08 16:26:57 UTC (rev 11099) @@ -16,7 +16,7 @@ from struct import pack, unpack from itertools import izip -from chandlerdb.item.c import Nil +from chandlerdb.item.c import Nil, DelegatingIndex from chandlerdb.util.c import SkipList, CLinkedMap from PyICU import Collator, Locale @@ -30,7 +30,7 @@ super(Index, self).__init__() self._count = 0 - def __iter__(self, firstKey=None, lastKey=None, backwards=False): + def iterkeys(self, firstKey=None, lastKey=None, backwards=False): if backwards: getFirstKey = self.getLastKey @@ -49,6 +49,9 @@ if lastKey is not None: yield lastKey + def __iter__(self): + return self.iterkeys() + def clear(self): self._count = 0 @@ -311,36 +314,6 @@ return offset -class DelegatingIndex(object): - - def __init__(self, index, **kwds): - self._index = index - - def __repr__(self): - return '<%s: %d>' %(type(self).__name__, self._count) - - def __len__(self): - return len(self._index) - - def __iter__(self, firstKey=None, lastKey=None, backwards=False): - return self._index.__iter__(firstKey, lastKey, backwards) - - def __getattr__(self, name): - return getattr(self._index, name) - - def __contains__(self, key): - return key in self._index - - def has_key(self, key): - return key in self._index - - def _writeValue(self, itemWriter, buffer, version): - self._index._writeValue(itemWriter, buffer, version) - - def _readValue(self, itemReader, offset, data): - return self._index._readValue(itemReader, offset, data) - - class SortedIndex(DelegatingIndex): def __init__(self, valueMap, index, **kwds): @@ -353,12 +326,12 @@ if not kwds.get('loading', False): self._descending = str(kwds.pop('descending', 'False')) == 'True' - def __iter__(self, firstKey=None, lastKey=None, backwards=False): + def iterkeys(self, firstKey=None, lastKey=None, backwards=False): if self._descending: backwards = not backwards - return self._index.__iter__(firstKey, lastKey, backwards) + return self._index.iterkeys(firstKey, lastKey, backwards) def getInitKeywords(self): @@ -476,7 +449,7 @@ def _writeValue(self, itemWriter, buffer, version): - super(SortedIndex, self)._writeValue(itemWriter, buffer, version) + self._index._writeValue(itemWriter, buffer, version) itemWriter.writeBoolean(buffer, self._descending) if self._subIndexes: itemWriter.writeShort(buffer, len(self._subIndexes)) @@ -489,7 +462,7 @@ def _readValue(self, itemReader, offset, data): - offset = super(SortedIndex, self)._readValue(itemReader, offset, data) + offset = self._index._readValue(itemReader, offset, data) offset, self._descending = itemReader.readBoolean(offset, data) offset, count = itemReader.readShort(offset, data)
Modified: trunk/chandler/repository/item/Sets.py (11098 => 11099)
--- trunk/chandler/repository/item/Sets.py 2006-07-08 16:09:33 UTC (rev 11098) +++ trunk/chandler/repository/item/Sets.py 2006-07-08 16:26:57 UTC (rev 11099) @@ -100,7 +100,7 @@ index = self._anIndex() if index is not None: - return index.__iter__() + return index.iterkeys() return self._iterkeys() @@ -1092,7 +1092,7 @@ def _iterkeys(self): sources = self._sources - if sources: + if len(sources) > 1: source = sources[0] for key in self._iterSourceKeys(source): everywhere = True @@ -1108,7 +1108,7 @@ def _itervalues(self): sources = self._sources - if sources: + if len(sources) > 1: source = sources[0] for item in self._iterSource(source): everywhere = True @@ -1124,17 +1124,18 @@ def _op(self, ops, other): sources = self._sources - for op, source in izip(ops, sources): - if op is not None: - everywhere = True - for src in sources: - if src is source: - continue - if not self._sourceContains(other, src): - everywhere = False - break - if everywhere: - return op + if len(sources) > 1: + for op, source in izip(ops, sources): + if op is not None: + everywhere = True + for src in sources: + if src is source: + continue + if not self._sourceContains(other, src): + everywhere = False + break + if everywhere: + return op return None
_______________________________________________ Commits mailing list [email protected] http://lists.osafoundation.org/mailman/listinfo/commits
