[Commits] (vajda) - reworked all dirtying code so that it is called only once per change

commits at osafoundation.org commits at osafoundation.org
Thu Aug 19 11:06:33 PDT 2004


Commit by: vajda
Modified files:
chandler/application/Application.py 1.259 1.260
chandler/application/Parcel.py 1.26 1.27
chandler/parcels/osaf/framework/blocks/ContainerBlocks.py 1.124 1.125
chandler/parcels/osaf/framework/blocks/calendar/CalendarBlocks.py 1.27 1.28
chandler/repository/item/Monitors.py None 1.1
chandler/repository/item/Indexes.py 1.3 1.4
chandler/repository/item/Item.py 1.151 1.152
chandler/repository/item/ItemHandler.py 1.43 1.44
chandler/repository/item/ItemRef.py 1.86 1.87
chandler/repository/item/PersistentCollections.py 1.18 1.19
chandler/repository/item/Values.py 1.13 1.14
chandler/repository/packs/schema.pack 1.19 1.20
chandler/repository/packs/schema/model/Items.namespace None 1.1
chandler/repository/packs/schema/model/Monitors.kind None 1.1
chandler/repository/packs/schema/model/Item.kind 1.14 1.15
chandler/repository/packs/schema/model/clouds/Item.cloud 1.1 1.2
chandler/repository/packs/schema/model/items/Monitors.item None 1.1
chandler/repository/persistence/FileRepository.py 1.28 1.29
chandler/repository/persistence/XMLLob.py 1.1 1.2
chandler/repository/persistence/XMLRefDict.py 1.2 1.3
chandler/repository/persistence/XMLRepositoryView.py 1.46 1.47
chandler/repository/schema/Cloud.py 1.13 1.14
chandler/repository/schema/Kind.py 1.81 1.82
chandler/repository/schema/Types.py 1.67 1.68
chandler/repository/tests/TestBZ2.py 1.2 1.3
chandler/repository/tests/TestText.py 1.16 1.17

Log message:
   - reworked all dirtying code so that it is called only once per change
   - implemented attribute value monitors
   - finished implementation of attribute value monitors for sorted indexes
   - fixed bug in Kind.getInitialValues() with PersistentCollection values
   - fixed bug in RefDict._removeRef with removing key from indexes
   - renamed RefDict.removeItem() to remove()


ViewCVS links:
http://cvs.osafoundation.org/index.cgi/chandler/application/Application.py.diff?r1=text&tr1=1.259&r2=text&tr2=1.260
http://cvs.osafoundation.org/index.cgi/chandler/application/Parcel.py.diff?r1=text&tr1=1.26&r2=text&tr2=1.27
http://cvs.osafoundation.org/index.cgi/chandler/parcels/osaf/framework/blocks/ContainerBlocks.py.diff?r1=text&tr1=1.124&r2=text&tr2=1.125
http://cvs.osafoundation.org/index.cgi/chandler/parcels/osaf/framework/blocks/calendar/CalendarBlocks.py.diff?r1=text&tr1=1.27&r2=text&tr2=1.28
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/Monitors.py?rev=1.1&content-type=text/vnd.viewcvs-markup
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/Indexes.py.diff?r1=text&tr1=1.3&r2=text&tr2=1.4
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/Item.py.diff?r1=text&tr1=1.151&r2=text&tr2=1.152
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/ItemHandler.py.diff?r1=text&tr1=1.43&r2=text&tr2=1.44
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/ItemRef.py.diff?r1=text&tr1=1.86&r2=text&tr2=1.87
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/PersistentCollections.py.diff?r1=text&tr1=1.18&r2=text&tr2=1.19
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/Values.py.diff?r1=text&tr1=1.13&r2=text&tr2=1.14
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/schema.pack.diff?r1=text&tr1=1.19&r2=text&tr2=1.20
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/schema/model/Items.namespace?rev=1.1&content-type=text/vnd.viewcvs-markup
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/schema/model/Monitors.kind?rev=1.1&content-type=text/vnd.viewcvs-markup
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/schema/model/Item.kind.diff?r1=text&tr1=1.14&r2=text&tr2=1.15
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/schema/model/clouds/Item.cloud.diff?r1=text&tr1=1.1&r2=text&tr2=1.2
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/schema/model/items/Monitors.item?rev=1.1&content-type=text/vnd.viewcvs-markup
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/FileRepository.py.diff?r1=text&tr1=1.28&r2=text&tr2=1.29
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/XMLLob.py.diff?r1=text&tr1=1.1&r2=text&tr2=1.2
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/XMLRefDict.py.diff?r1=text&tr1=1.2&r2=text&tr2=1.3
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/XMLRepositoryView.py.diff?r1=text&tr1=1.46&r2=text&tr2=1.47
http://cvs.osafoundation.org/index.cgi/chandler/repository/schema/Cloud.py.diff?r1=text&tr1=1.13&r2=text&tr2=1.14
http://cvs.osafoundation.org/index.cgi/chandler/repository/schema/Kind.py.diff?r1=text&tr1=1.81&r2=text&tr2=1.82
http://cvs.osafoundation.org/index.cgi/chandler/repository/schema/Types.py.diff?r1=text&tr1=1.67&r2=text&tr2=1.68
http://cvs.osafoundation.org/index.cgi/chandler/repository/tests/TestBZ2.py.diff?r1=text&tr1=1.2&r2=text&tr2=1.3
http://cvs.osafoundation.org/index.cgi/chandler/repository/tests/TestText.py.diff?r1=text&tr1=1.16&r2=text&tr2=1.17

Index: chandler/application/Parcel.py
diff -u chandler/application/Parcel.py:1.26 chandler/application/Parcel.py:1.27
--- chandler/application/Parcel.py:1.26	Fri Aug 13 08:31:43 2004
+++ chandler/application/Parcel.py	Thu Aug 19 11:06:23 2004
@@ -1559,14 +1559,14 @@
             elif card == "list":
                 # First, see if this is a ref collection, since we handle those
                 # differently; to remove an item from a ref collection, we use
-                # removeItem( ) which takes an item parameter -- therefore we
+                # remove() which takes an item parameter -- therefore we
                 # first need to findUUID() the item.
                 if self.item.getAttributeAspect(attrName, "otherName"):
                     attr = self.item.getAttributeValue(attrName)
                     # value is a UUID -- let's load the associated item and then
                     # remove it from this collection
                     otherItem = self.item.findUUID(value)
-                    attr.removeItem(otherItem)
+                    attr.remove(otherItem)
                     print "Reload: item %s, unassigning %s = '%s'" % \
                      (self.item.itsPath, attrName, otherItem.itsPath)
                     continue

Index: chandler/repository/persistence/XMLRefDict.py
diff -u chandler/repository/persistence/XMLRefDict.py:1.2 chandler/repository/persistence/XMLRefDict.py:1.3
--- chandler/repository/persistence/XMLRefDict.py:1.2	Wed Jul 28 08:38:07 2004
+++ chandler/repository/persistence/XMLRefDict.py	Thu Aug 19 11:06:29 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.2 $"
-__date__      = "$Date: 2004/07/28 15:38:07 $"
+__revision__  = "$Revision: 1.3 $"
+__date__      = "$Date: 2004/08/19 18:06:29 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -45,9 +45,9 @@
 
         return self._getRefs().loadRef(self._key, self._item._version, key)
 
-    def _changeRef(self, key, alias=None):
+    def _changeRef(self, key, alias=None, noMonitors=False):
 
-        super(XMLRefDict, self)._changeRef(key, alias)
+        super(XMLRefDict, self)._changeRef(key, alias, noMonitors)
 
         if not self.view.isLoading():
             self._changedRefs[key] = (0, alias)

Index: chandler/repository/persistence/FileRepository.py
diff -u chandler/repository/persistence/FileRepository.py:1.28 chandler/repository/persistence/FileRepository.py:1.29
--- chandler/repository/persistence/FileRepository.py:1.28	Mon Jun  7 23:59:08 2004
+++ chandler/repository/persistence/FileRepository.py	Thu Aug 19 11:06:29 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.28 $"
-__date__      = "$Date: 2004/06/08 06:59:08 $"
+__revision__  = "$Revision: 1.29 $"
+__date__      = "$Date: 2004/08/19 18:06:29 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -155,7 +155,7 @@
             if item.isDirty():
                 view._saveItem(item, **args)
                 count += 1
-                item.setDirty(0)
+                item.setDirty(0, None)
 
             contents.write(item.itsUUID.str16())
             contents.write('\n')

Index: chandler/repository/tests/TestText.py
diff -u chandler/repository/tests/TestText.py:1.16 chandler/repository/tests/TestText.py:1.17
--- chandler/repository/tests/TestText.py:1.16	Fri Jul 16 08:04:53 2004
+++ chandler/repository/tests/TestText.py	Thu Aug 19 11:06:31 2004
@@ -2,8 +2,8 @@
 Text storage unit tests
 """
 
-__revision__  = "$Revision: 1.16 $"
-__date__      = "$Date: 2004/07/16 15:04:53 $"
+__revision__  = "$Revision: 1.17 $"
+__date__      = "$Date: 2004/08/19 18:06:31 $"
 __copyright__ = "Copyright (c) 2003 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -46,7 +46,6 @@
 
         input.close()
         writer.close()
-        movie.setDirty()
         
         self.rep.logger.info("%s compressed %d bytes to %d",
                              compression, count, len(movie.synopsis._data))
@@ -93,7 +92,6 @@
             data = input.read(548576)
             if len(data) > 0:
                 writer.write(data)
-                movie.setDirty()
                 writer.close()
                 self.rep.commit()
                 writer = movie.synopsis.getWriter(compression=compression,

Index: chandler/repository/packs/schema/model/Item.kind
diff -u chandler/repository/packs/schema/model/Item.kind:1.14 chandler/repository/packs/schema/model/Item.kind:1.15
--- chandler/repository/packs/schema/model/Item.kind:1.14	Thu Aug  5 06:57:37 2004
+++ chandler/repository/packs/schema/model/Item.kind	Thu Aug 19 11:06:27 2004
@@ -25,4 +25,19 @@
     </attribute>
   </item>
 
+  <item withSchema="True">
+    <name>monitors</name>
+    <kind type="path">//Schema/Core/Attribute</kind>
+    <class module="repository.schema.Attribute">Attribute</class>
+    <parent type="path">//Schema/Core/Item</parent>
+
+    <ref name="kinds" otherName="attributes"
+         cardinality="list" otherCard="list">
+      <ref type="path">..</ref>
+    </ref>
+
+    <attribute name="cardinality">single</attribute>
+    <attribute name="otherName">items</attribute>
+  </item>
+
 </items>

Index: chandler/repository/packs/schema/model/clouds/Item.cloud
diff -u chandler/repository/packs/schema/model/clouds/Item.cloud:1.1 chandler/repository/packs/schema/model/clouds/Item.cloud:1.2
--- chandler/repository/packs/schema/model/clouds/Item.cloud:1.1	Mon Aug 16 09:38:37 2004
+++ chandler/repository/packs/schema/model/clouds/Item.cloud	Thu Aug 19 11:06:28 2004
@@ -14,5 +14,4 @@
          type="path">//Schema/Core/Item</ref>
   </item>
 
-
 </items>

Index: chandler/repository/schema/Kind.py
diff -u chandler/repository/schema/Kind.py:1.81 chandler/repository/schema/Kind.py:1.82
--- chandler/repository/schema/Kind.py:1.81	Thu Aug  5 06:57:38 2004
+++ chandler/repository/schema/Kind.py	Thu Aug 19 11:06:30 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.81 $"
-__date__      = "$Date: 2004/08/05 13:57:38 $"
+__revision__  = "$Revision: 1.82 $"
+__date__      = "$Date: 2004/08/19 18:06:30 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -343,7 +343,7 @@
             if name not in values:
                 if isinstance(value, PersistentCollection):
                     value = value._copy(item, name, value._companion,
-                                        {}, 'copy')
+                                        'copy', lambda x, other, z: other)
                 elif isinstance(value, ItemValue):
                     value = value._copy(item, name)
 

Index: chandler/repository/persistence/XMLLob.py
diff -u chandler/repository/persistence/XMLLob.py:1.1 chandler/repository/persistence/XMLLob.py:1.2
--- chandler/repository/persistence/XMLLob.py:1.1	Wed Jul 21 14:32:29 2004
+++ chandler/repository/persistence/XMLLob.py	Thu Aug 19 11:06:29 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.1 $"
-__date__      = "$Date: 2004/07/21 21:32:29 $"
+__revision__  = "$Revision: 1.2 $"
+__date__      = "$Date: 2004/08/19 18:06:29 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -81,7 +81,6 @@
 
         if self._uuid is None:
             self._uuid = UUID()
-            self._setDirty()
 
         return self._uuid
 
@@ -210,7 +209,6 @@
 
         if self._uuid is None:
             self._uuid = UUID()
-            self._setDirty()
 
         return self._uuid
 

Index: chandler/parcels/osaf/framework/blocks/ContainerBlocks.py
diff -u chandler/parcels/osaf/framework/blocks/ContainerBlocks.py:1.124 chandler/parcels/osaf/framework/blocks/ContainerBlocks.py:1.125
--- chandler/parcels/osaf/framework/blocks/ContainerBlocks.py:1.124	Wed Aug 11 06:33:13 2004
+++ chandler/parcels/osaf/framework/blocks/ContainerBlocks.py	Thu Aug 19 11:06:24 2004
@@ -1,5 +1,5 @@
-__version__ = "$Revision: 1.124 $"
-__date__ = "$Date: 2004/08/11 13:33:13 $"
+__version__ = "$Revision: 1.125 $"
+__date__ = "$Date: 2004/08/19 18:06:24 $"
 __copyright__ = "Copyright (c) 2003 Open Source Applications Foundation"
 __license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -183,7 +183,7 @@
             newSize = self.GetSize()
             self.blockItem.size.width = newSize.width
             self.blockItem.size.height = newSize.height
-            self.blockItem.setDirty()   # Temporary repository hack -- DJA
+            self.blockItem.setDirty(self.blockItem.VDIRTY, 'size')   # Temporary repository hack -- DJA
             
             if self.blockItem.orientationEnum == "Horizontal":
                 distance = self.blockItem.size.height

Index: chandler/repository/persistence/XMLRepositoryView.py
diff -u chandler/repository/persistence/XMLRepositoryView.py:1.46 chandler/repository/persistence/XMLRepositoryView.py:1.47
--- chandler/repository/persistence/XMLRepositoryView.py:1.46	Tue Jul 27 12:46:45 2004
+++ chandler/repository/persistence/XMLRepositoryView.py	Thu Aug 19 11:06:29 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.46 $"
-__date__      = "$Date: 2004/07/27 19:46:45 $"
+__revision__  = "$Revision: 1.47 $"
+__date__      = "$Date: 2004/08/19 18:06:29 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -60,7 +60,7 @@
                 del self._deletedRegistry[item.itsUUID]
                 item._status &= ~Item.DELETED
             else:
-                item.setDirty(0)
+                item.setDirty(0, None)
                 item._unloadItem()
 
         for item in self._log:

Index: chandler/parcels/osaf/framework/blocks/calendar/CalendarBlocks.py
diff -u chandler/parcels/osaf/framework/blocks/calendar/CalendarBlocks.py:1.27 chandler/parcels/osaf/framework/blocks/calendar/CalendarBlocks.py:1.28
--- chandler/parcels/osaf/framework/blocks/calendar/CalendarBlocks.py:1.27	Tue Aug  3 17:40:35 2004
+++ chandler/parcels/osaf/framework/blocks/calendar/CalendarBlocks.py	Thu Aug 19 11:06:24 2004
@@ -1,8 +1,8 @@
 """ Calendar Blocks
 """
 
-__version__ = "$Revision: 1.27 $"
-__date__ = "$Date: 2004/08/04 00:40:35 $"
+__version__ = "$Revision: 1.28 $"
+__date__ = "$Date: 2004/08/19 18:06:24 $"
 __copyright__ = "Copyright (c) 2003 Open Source Applications Foundation"
 __license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -234,7 +234,7 @@
             newSize = self.GetSize()
             self.blockItem.size.width = newSize.width
             self.blockItem.size.height = newSize.height
-            self.blockItem.setDirty()   # Temporary repository hack -- DJA
+            self.blockItem.setDirty(self.blockItem.VDIRTY, 'size')   # Temporary repository hack -- DJA
             self.SetVirtualSize(newSize)
             self.displayItems()                        
             self._positionNavigationButtons()

Index: chandler/repository/tests/TestBZ2.py
diff -u chandler/repository/tests/TestBZ2.py:1.2 chandler/repository/tests/TestBZ2.py:1.3
--- chandler/repository/tests/TestBZ2.py:1.2	Sun May 30 12:29:00 2004
+++ chandler/repository/tests/TestBZ2.py	Thu Aug 19 11:06:31 2004
@@ -2,8 +2,8 @@
 Text blocked read of appended storage compression unit tests
 """
 
-__revision__  = "$Revision: 1.2 $"
-__date__      = "$Date: 2004/05/30 19:29:00 $"
+__revision__  = "$Revision: 1.3 $"
+__date__      = "$Date: 2004/08/19 18:06:31 $"
 __copyright__ = "Copyright (c) 2003 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -43,7 +43,6 @@
             data = input.read(54857)
             if len(data) > 0:
                 writer.write(data)
-                movie.setDirty()
                 writer.close()
                 self.rep.commit()
                 writer = movie.synopsis.getWriter(compression=compression,

Index: chandler/repository/schema/Cloud.py
diff -u chandler/repository/schema/Cloud.py:1.13 chandler/repository/schema/Cloud.py:1.14
--- chandler/repository/schema/Cloud.py:1.13	Thu Aug  5 06:57:38 2004
+++ chandler/repository/schema/Cloud.py	Thu Aug 19 11:06:30 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.13 $"
-__date__      = "$Date: 2004/08/05 13:57:38 $"
+__revision__  = "$Revision: 1.14 $"
+__date__      = "$Date: 2004/08/19 18:06:30 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -317,9 +317,8 @@
             method = self.getAttributeValue('method', default=None,
                                             _attrDict=self._values)
             if method is not None:
-                results.extend(getattr(type(item), method)(item, items,
-                                                           references,
-                                                           cloudAlias))
+                results.extend(getattr(item, method)(items, references,
+                                                     cloudAlias))
 
         else:
             raise NotImplementedError, policy

Index: chandler/application/Application.py
diff -u chandler/application/Application.py:1.259 chandler/application/Application.py:1.260
--- chandler/application/Application.py:1.259	Sat Aug 14 17:03:05 2004
+++ chandler/application/Application.py	Thu Aug 19 11:06:23 2004
@@ -1,5 +1,5 @@
-__version__ = "$Revision: 1.259 $"
-__date__ = "$Date: 2004/08/15 00:03:05 $"
+__version__ = "$Revision: 1.260 $"
+__date__ = "$Date: 2004/08/19 18:06:23 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -107,7 +107,7 @@
         if not Globals.wxApplication.ignoreSynchronizeWidget:
             Globals.mainView.size.width = self.GetSize().x
             Globals.mainView.size.height = self.GetSize().y
-            Globals.mainView.setDirty()   # Temporary repository hack -- DJA
+            Globals.mainView.setDirty(Globals.mainView.VDIRTY, 'size')   # Temporary repository hack -- DJA
         event.Skip()
 
 

Index: chandler/repository/schema/Types.py
diff -u chandler/repository/schema/Types.py:1.67 chandler/repository/schema/Types.py:1.68
--- chandler/repository/schema/Types.py:1.67	Wed Jul 28 13:40:39 2004
+++ chandler/repository/schema/Types.py	Thu Aug 19 11:06:30 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.67 $"
-__date__      = "$Date: 2004/07/28 20:40:39 $"
+__revision__  = "$Revision: 1.68 $"
+__date__      = "$Date: 2004/08/19 18:06:30 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -776,15 +776,17 @@
         generator.startElement('values', {})
         for key, val in value._iteritems():
             ItemHandler.xmlValue(repository,
-                                 key, val, 'value', None, 'single', None, 0,
+                                 key, val, 'value', None, 'single', None, {},
                                  generator, withSchema)
         generator.endElement('values')
 
     def makeValue(self, data):
-        """Make a dict of string key/value pairs from comma separated pairs.
+        """
+        Make a dict of string key/value pairs from comma separated pairs.
 
         The implementation is very cheap, using split, so spaces are part of
-        the dict's elements and the strings cannot contain spaces or colons."""
+        the dict's elements and the strings cannot contain spaces or colons.
+        """
 
         result = {}
         if data:
@@ -820,15 +822,17 @@
         generator.startElement('values', {})
         for val in value._itervalues():
             ItemHandler.xmlValue(repository,
-                                 None, val, 'value', None, 'single', None, 0,
+                                 None, val, 'value', None, 'single', None, {},
                                  generator, withSchema)
         generator.endElement('values')
 
     def makeValue(self, data):
-        """Make a list of strings from comma separated strings.
+        """
+        Make a list of strings from comma separated strings.
 
         The implementation is very cheap, using split, so spaces are part of
-        the list's elements and the strings cannot contain spaces."""
+        the list's elements and the strings cannot contain spaces.
+        """
 
         if data:
             return data.split(',')

Index: chandler/repository/item/Indexes.py
diff -u chandler/repository/item/Indexes.py:1.3 chandler/repository/item/Indexes.py:1.4
--- chandler/repository/item/Indexes.py:1.3	Wed Jul 28 13:40:38 2004
+++ chandler/repository/item/Indexes.py	Thu Aug 19 11:06:25 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.3 $"
-__date__      = "$Date: 2004/07/28 20:40:38 $"
+__revision__  = "$Revision: 1.4 $"
+__date__      = "$Date: 2004/08/19 18:06:25 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -168,14 +168,14 @@
 
     def afterKey(self, key):
 
-        pos = lo = 0;
-        hi = len(self._index) - 1;
+        pos = lo = 0
+        hi = len(self._index) - 1
         afterKey = None
         
         while lo <= hi:
             pos = (lo + hi) >> 1
             afterKey = self.getKey(pos)
-            diff = self.compare(key, afterKey);
+            diff = self.compare(key, afterKey)
 
             if diff == 0:
                 return afterKey
@@ -184,7 +184,7 @@
                 hi = pos - 1
             else:
                 pos += 1
-                lo = pos;
+                lo = pos
 
         if pos == 0:
             return None
@@ -194,10 +194,14 @@
     def insertKey(self, key, afterKey):
 
         self._index.insertKey(key, self.afterKey(key))
+
+    def removeKey(self, key):
+
+        self._index.removeKey(key)
             
     def moveKey(self, key, afterKey):
 
-        self.removeKey(key)
+        self._index.removeKey(key)
         self._index.insertKey(key, self.afterKey(key))
 
 
@@ -227,6 +231,16 @@
 
         return 0
 
+    def insertKey(self, key, afterKey):
+
+        self._valueMap[key].addMonitor(self._attribute)
+        super(AttributeIndex, self).insertKey(key, afterKey)
+
+    def removeKey(self, key):
+
+        self._valueMap[key].removeMonitor(self._attribute)
+        super(AttributeIndex, self).removeKey(key)
+            
     def _xmlValues(self, generator, version, attrs, mode):
 
         attrs['attribute'] = self._attribute

Index: chandler/repository/item/ItemHandler.py
diff -u chandler/repository/item/ItemHandler.py:1.43 chandler/repository/item/ItemHandler.py:1.44
--- chandler/repository/item/ItemHandler.py:1.43	Tue Jul 27 10:46:19 2004
+++ chandler/repository/item/ItemHandler.py	Thu Aug 19 11:06:25 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.43 $"
-__date__      = "$Date: 2004/07/27 17:46:19 $"
+__revision__  = "$Revision: 1.44 $"
+__date__      = "$Date: 2004/08/19 18:06:25 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -105,11 +105,15 @@
             flags = attrs.get('flags', None)
             if flags is not None:
                 flags = int(flags)
-                self.values._setFlags(name, flags)
+                self.references._setFlags(name, flags)
                 readOnly = flags & Values.READONLY
             else:
                 readOnly = False
 
+            monitors = attrs.get('monitors', None)
+            if monitors is not None:
+                self.references._addMonitor(name, int(monitors))
+
             cardinality = self.getCardinality(attribute, attrs)
 
             if cardinality != 'single':
@@ -420,6 +424,10 @@
                 elif isinstance(value, ItemValue):
                     value._setReadOnly()
 
+        monitors = attrs.get('monitors', None)
+        if monitors is not None:
+            self.values._addMonitor(attrs['name'], int(monitors))
+
     def valueEnd(self, itemHandler, attrs, **kwds):
 
         if kwds.has_key('value'):
@@ -444,10 +452,10 @@
         name = attrs.get('name')
 
         if name is None:
-            self.collections[-1].append(value)
+            self.collections[-1].append(value, False)
         else:
             name = self.makeValue(attrs.get('nameType', 'str'), name)
-            self.collections[-1][name] = value
+            self.collections[-1].__setitem__(name, value, False)
 
     def getCardinality(self, attribute, attrs):
 
@@ -567,12 +575,9 @@
 
         return cls.typeHandler(repository, value).makeString(value)
     
-    def xmlValue(cls, repository, name, value, tag,
-                 attrType, attrCard, attrId, flags,
-                 generator, withSchema):
+    def xmlValue(cls, repository, name, value, tag, attrType, attrCard, attrId,
+                 attrs, generator, withSchema):
 
-        attrs = {}
-            
         if name is not None:
             if not isinstance(name, str) and not isinstance(name, unicode):
                 attrs['nameType'] = cls.typeName(repository, name)
@@ -598,9 +603,6 @@
         else:
             attrs['cardinality'] = attrCard
 
-        if flags:
-            attrs['flags'] = str(flags)
-
         generator.startElement(tag, attrs)
 
         if attrCard == 'single':
@@ -622,13 +624,13 @@
             for val in value._itervalues():
                 cls.xmlValue(repository,
                              None, val, 'value', attrType, 'single',
-                             None, 0, generator, withSchema)
+                             None, {}, generator, withSchema)
 
         elif attrCard == 'dict':
             for key, val in value._iteritems():
                 cls.xmlValue(repository,
                              key, val, 'value', attrType, 'single',
-                             None, 0, generator, withSchema)
+                             None, {}, generator, withSchema)
         else:
             raise ValueError, attrCard
 

Index: chandler/repository/item/Values.py
diff -u chandler/repository/item/Values.py:1.13 chandler/repository/item/Values.py:1.14
--- chandler/repository/item/Values.py:1.13	Sun Aug  1 04:14:40 2004
+++ chandler/repository/item/Values.py	Thu Aug 19 11:06:25 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.13 $"
-__date__      = "$Date: 2004/08/01 11:14:40 $"
+__revision__  = "$Revision: 1.14 $"
+__date__      = "$Date: 2004/08/19 18:06:25 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -53,9 +53,6 @@
         if self._getFlags(key) & Values.READONLY:
             raise AttributeError, 'Value for %s on %s is read-only' %(key, self._item.itsPath)
 
-        if self._item is not None:
-            self._item.setDirty(attribute=key)
-
         return super(Values, self).__setitem__(key, value)
 
     def __delitem__(self, key):
@@ -63,9 +60,6 @@
         if self._getFlags(key) & Values.READONLY:
             raise AttributeError, 'Value for %s on %s is read-only' %(key, self._item.itsPath)
 
-        if self._item is not None:
-            self._item.setDirty(attribute=key)
-
         return super(Values, self).__delitem__(key)
 
     def _unload(self):
@@ -111,6 +105,36 @@
 
         self._flags[key] &= ~Values.TRANSIENT
 
+    def _addMonitor(self, key, count=1):
+
+        if '_monitors' in self.__dict__:
+            self._monitors[key] += count
+        else:
+            self._monitors = { key: count }
+
+    def _hasMonitors(self, key):
+
+        return '_monitors' in self.__dict__ and key in self._monitors
+        #return True
+
+    def _removeMonitor(self, key):
+
+        monitors = self._getMonitors(key)
+
+        if monitors:
+            self._monitors[key] = monitors - 1
+        else:
+            raise AttributeError, 'no monitors on attribute %s' %(key)
+
+    def _getMonitors(self, key):
+
+        try:
+            return self._monitors[key]
+        except AttributeError:
+            return 0
+        except KeyError:
+            return 0
+
     def _xmlValues(self, generator, withSchema, version, mode):
 
         from repository.item.ItemHandler import ItemHandler
@@ -131,7 +155,8 @@
                 persist = True
 
             if persist:
-                persist = self._getFlags(key) & self.TRANSIENT == 0
+                flags = self._getFlags(key)
+                persist = flags & self.TRANSIENT == 0
 
             if persist:
                 if attribute is not None:
@@ -144,15 +169,21 @@
                     attrCard = 'single'
                     attrId = None
 
+                monitors = self._getMonitors(key)
+                attrs = {}
+                if flags:
+                    attrs['flags'] = str(flags)
+                if monitors:
+                    attrs['monitors'] = str(monitors)
+
                 try:
                     ItemHandler.xmlValue(repository, key, value, 'attribute',
-                                         attrType, attrCard, attrId,
-                                         self._getFlags(key), generator,
-                                         withSchema)
+                                         attrType, attrCard, attrId, attrs,
+                                         generator, withSchema)
                 except Exception, e:
                     e.args = ("while saving attribute '%s' of item %s, %s" %(key, item.itsPath, e.args[0]),)
                     raise
-            
+
 
     READONLY = 0x0001          # value is read-only
     TRANSIENT = 0x0002         # value is transient
@@ -180,10 +211,6 @@
             policy = copyPolicy or item.getAttributeAspect(name, 'copyPolicy')
             value._copy(self, orig._item, item, name, policy, copyFn)
 
-    def __setitem__(self, key, value, *args):
-
-        super(References, self).__setitem__(key, value)
-
     def _unload(self):
 
         for value in self.itervalues():
@@ -195,8 +222,19 @@
 
         for key, value in self.iteritems():
             if item.getAttributeAspect(key, 'persist', default=True):
+                flags = self._getFlags(key)
+                monitors = self._getMonitors(key)
+                attrs = {}
+                if flags:
+                    attrs['flags'] = str(flags)
+                if monitors:
+                    attrs['monitors'] = str(monitors)
                 value._xmlValue(key, item, generator, withSchema, version,
-                                self._getFlags(key), mode)
+                                attrs, mode)
+
+    def _isRefDict(self):
+
+        return False
 
 
 class ItemValue(object):
@@ -215,9 +253,6 @@
             raise ValueError, 'item attribute value %s is already owned by another item %s' %(self, self._item)
         
         self._item = item
-        if self._dirty:
-            item.setDirty()
-
         self._attribute = attribute
 
     def _setReadOnly(self, readOnly=True):
@@ -241,11 +276,10 @@
         if self._isReadOnly():
             raise AttributeError, 'Value for %s on %s is read-only' %(self._attribute, self._item.itsPath)
 
-        if not self._dirty:
-            self._dirty = True
-            item = self._item
-            if item is not None:
-                item.setDirty(attribute=self._attribute, dirty=item.VDIRTY)
+        self._dirty = True
+        item = self._item
+        if item is not None:
+            item.setDirty(item.VDIRTY, self._attribute, item._values)
 
     def _copy(self, item, attribute):
 

Index: chandler/repository/packs/schema.pack
diff -u chandler/repository/packs/schema.pack:1.19 chandler/repository/packs/schema.pack:1.20
--- chandler/repository/packs/schema.pack:1.19	Mon Aug 16 09:38:37 2004
+++ chandler/repository/packs/schema.pack	Thu Aug 19 11:06:27 2004
@@ -23,6 +23,7 @@
       <item file="Cloud.kind" />
       <item file="Endpoint.kind" />
       <item file="Principal.kind" />
+      <item file="Monitors.kind" />
 
       <item file="Clouds.namespace" cwd="clouds">
         <item file="Kind.cloud" />
@@ -31,6 +32,10 @@
       </item>
 
       <item file="Mixins.namespace" />
+
+      <item file="Items.namespace" cwd="items">
+        <item file="Monitors.item" />
+      </item>
     </item>
   </item>
 

Index: chandler/repository/item/Item.py
diff -u chandler/repository/item/Item.py:1.151 chandler/repository/item/Item.py:1.152
--- chandler/repository/item/Item.py:1.151	Thu Aug  5 06:57:37 2004
+++ chandler/repository/item/Item.py	Thu Aug 19 11:06:25 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.151 $"
-__date__      = "$Date: 2004/08/05 13:57:37 $"
+__revision__  = "$Revision: 1.152 $"
+__date__      = "$Date: 2004/08/19 18:06:25 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -310,7 +310,7 @@
         return kwds.get('default', None)
         
     def setAttributeValue(self, name, value=None, setAliases=False,
-                          _attrDict=None):
+                          _attrDict=None, setDirty=True):
         """
         Set a value on a Chandler attribute.
 
@@ -366,7 +366,8 @@
                         if old is not NoneRef:
                             # reattaching on original endpoint
                             old.reattach(self, name, old.other(self), value,
-                                         self._kind.getOtherName(name))
+                                         self._kind.getOtherName(name),
+                                         setDirty=setDirty)
                             return value
                     elif isRef:
                         # reattaching on other endpoint,
@@ -382,8 +383,6 @@
                 else:
                     raise TypeError, type(old)
 
-        self.setDirty(attribute=name)
-        
         if isItem:
             otherName = self._kind.getOtherName(name, default=None)
             card = self.getAttributeAspect(name, 'cardinality',
@@ -394,13 +393,16 @@
 
             if otherName is None:
                 self._values[name] = value = SingleRef(value.itsUUID)
-
+                
             else:
                 value = ItemRef(self, name, value, otherName)
                 self._references[name] = value
 
+            dirty = Item.VDIRTY
+            
         elif isRef:
             self._references[name] = value
+            dirty = Item.VDIRTY
 
         elif isinstance(value, list):
             if _attrDict is self._references:
@@ -409,13 +411,17 @@
                 else:
                     assert isinstance(old, RefDict)
                     refDict = old
+
                 refDict.extend(value)
                 value = refDict
+                setDirty = False
             else:
                 companion = self.getAttributeAspect(name, 'companion',
                                                     default=None)
-                value = PersistentList(self, name, companion, value)
-                self._values[name] = value
+                attrValue = PersistentList(self, name, companion)
+                self._values[name] = attrValue
+                attrValue.extend(value)
+                setDirty = False
 
         elif isinstance(value, dict):
             if _attrDict is self._references:
@@ -424,23 +430,96 @@
                 else:
                     assert isinstance(old, RefDict)
                     refDict = old
+
                 refDict.update(value, setAliases)
                 value = refDict
+                setDirty = False
             else:
                 companion = self.getAttributeAspect(name, 'companion',
                                                     default=None)
-                value = PersistentDict(self, name, companion, value)
-                self._values[name] = value
+                attrValue = PersistentDict(self, name, companion)
+                self._values[name] = attrValue
+                attrValue.update(value)
+                setDirty = False
             
         elif isinstance(value, ItemValue):
             value._setItem(self, name)
             self._values[name] = value
+            dirty = Item.VDIRTY
             
         else:
             self._values[name] = value
+            dirty = Item.VDIRTY
 
+        if setDirty:
+            self.setDirty(dirty, name, _attrDict)
+        
         return value
 
+    def _invokeMonitors(self, name, attrDict):
+
+        if attrDict._hasMonitors(name):
+            from repository.item.Monitors import Monitors
+            Monitors.invoke('set', self, name)
+
+    def _reIndex(self, op, item, attrName, collectionName, indexName):
+
+        if op == 'set':
+            refDict = self.getAttributeValue(collectionName, default=None,
+                                             _attrDict=self._references)
+            if refDict is not None and item._uuid in refDict:
+                refDict.placeItem(item, None, indexName)
+
+    def addMonitor(self, name, _attrDict=None):
+
+        if _attrDict is None:
+            if self._values.has_key(name):
+                _attrDict = self._values
+            elif self._references.has_key(name):
+                _attrDict = self._references
+            elif self._kind.getOtherName(name, default=None) is not None:
+                _attrDict = self._references
+            else:
+                redirect = self.getAttributeAspect(name, 'redirectTo',
+                                                   default=None)
+                if redirect is not None:
+                    item = self
+                    names = redirect.split('.')
+                    for i in xrange(len(names) - 1):
+                        item = item.getAttributeValue(names[i])
+
+                    return item.addMonitor(name)
+
+                else:
+                    _attrDict = self._values
+
+        _attrDict._addMonitor(name)
+
+    def removeMonitor(self, name, _attrDict=None):
+
+        if _attrDict is None:
+            if self._values.has_key(name):
+                _attrDict = self._values
+            elif self._references.has_key(name):
+                _attrDict = self._references
+            elif self._kind.getOtherName(name, default=None) is not None:
+                _attrDict = self._references
+            else:
+                redirect = self.getAttributeAspect(name, 'redirectTo',
+                                                   default=None)
+                if redirect is not None:
+                    item = self
+                    names = redirect.split('.')
+                    for i in xrange(len(names) - 1):
+                        item = item.getAttributeValue(names[i])
+
+                    return item.removeMonitor(name)
+
+                else:
+                    _attrDict = self._values
+
+        _attrDict._removeMonitor(name)
+
     def getAttributeValue(self, name, _attrDict=None, **kwds):
         """
         Return a Chandler attribute value.
@@ -545,8 +624,6 @@
         @return: C{None}
         """
 
-        self.setDirty(attribute=name)
-
         if _attrDict is None:
             if self._values.has_key(name):
                 _attrDict = self._values
@@ -555,6 +632,7 @@
 
         if _attrDict is self._values:
             del _attrDict[name]
+            dirty = Item.VDIRTY
         elif _attrDict is self._references:
             value = _attrDict[name]
 
@@ -562,12 +640,17 @@
                 value.detach(self, name,
                              value.other(self), self._kind.getOtherName(name))
                 del _attrDict[name]
+                dirty = Item.VDIRTY
             elif isinstance(value, RefDict):
                 value.clear()
                 del _attrDict[name]
+                dirty = None
             else:
                 raise TypeError, (type(value), value)
 
+        if dirty is not None:
+            self.setDirty(dirty, name)
+
     def hasChild(self, name, load=True):
         """
         Tell whether this item has a child of that name.
@@ -878,8 +961,6 @@
         isItem = isinstance(value, Item)
         attrValue = _attrDict.get(attribute, Item.Nil)
             
-        self.setDirty(attribute=attribute)
-
         if attrValue is Item.Nil:
             card = self.getAttributeAspect(attribute, 'cardinality',
                                            default='single')
@@ -894,8 +975,9 @@
                     companion = self.getAttributeAspect(attribute, 'companion',
                                                         default=None)
                     attrValue = PersistentDict(self, attribute, companion)
-                    attrValue[key] = value
                     _attrDict[attribute] = attrValue
+                    attrValue[key] = value
+                    
                     return attrValue
 
             elif card == 'list':
@@ -908,8 +990,9 @@
                     companion = self.getAttributeAspect(attribute, 'companion',
                                                         default=None)
                     attrValue = PersistentList(self, attribute, companion)
-                    attrValue.append(value)
                     _attrDict[attribute] = attrValue
+                    attrValue.append(value)
+
                     return attrValue
 
             else:
@@ -978,22 +1061,19 @@
         if attrValue is Item.Nil:
             return self.setValue(attribute, value, key, alias, _attrDict)
 
-        else:
-            self.setDirty(attribute=attribute)
-
-            if isinstance(attrValue, RefDict):
-                if isinstance(value, Item):
-                    attrValue.append(value, alias)
-                else:
-                    raise TypeError, type(value)
-            elif isinstance(attrValue, dict):
-                attrValue[key] = value
-            elif isinstance(attrValue, list):
-                attrValue.append(value)
+        elif isinstance(attrValue, RefDict):
+            if isinstance(value, Item):
+                attrValue.append(value, alias)
             else:
-                return self.setAttributeValue(attribute, value, _attrDict)
+                raise TypeError, type(value)
+        elif isinstance(attrValue, dict):
+            attrValue[key] = value
+        elif isinstance(attrValue, list):
+            attrValue.append(value)
+        else:
+            return self.setAttributeValue(attribute, value, _attrDict)
 
-            return attrValue
+        return attrValue
 
     def hasKey(self, attribute, key=None, alias=None, _attrDict=None):
         """
@@ -1118,8 +1198,6 @@
         else:
             raise KeyError, 'No value for attribute %s' %(attribute)
 
-        self.setDirty(attribute=attribute)
-
     def _removeRef(self, name):
 
         del self._references[name]
@@ -1245,16 +1323,16 @@
 
         return self._status & Item.DIRTY
 
-    def setDirty(self, dirty=None, attribute=None):
+    def setDirty(self, dirty, attribute, attrDict=None):
         """
         Mark this item to get committed with the current transaction.
 
         Returns C{True} if the dirty bit was changed from unset to set.
         Returns C{False} otherwise.
 
-        If C{attribute} is used and denotes a transient attribute (whose
-        C{persist} aspect is C{False}), then this method has no effect and
-        returns C{False}.
+        If C{attribute} denotes a transient attribute (whose C{persist}
+        aspect is C{False}), then this method has no effect and returns
+        C{False}.
 
         @param dirty: one of L{Item.VDIRTY <VDIRTY>},
         L{Item.RDIRTY <RDIRTY>}, L{Item.CDIRTY <CDIRTY>},
@@ -1268,8 +1346,13 @@
         @return: C{True} or C{False}
         """
 
-        if dirty is None:
-            dirty = Item.VDIRTY
+        if self._status & Item.NODIRTY:
+            return False
+
+        if attrDict is not None:
+            assert attribute is not None
+            assert attrDict is not None
+            self._invokeMonitors(attribute, attrDict)
 
         if dirty:
             self._lastAccess = Item._countAccess()
@@ -1367,9 +1450,13 @@
 
         if copyFn is None:
             copyFn = copyOther
+
+        item._status |= Item.NODIRTY
         item._values._copy(self._values, copyPolicy, copyFn)
         item._references._copy(self._references, copyPolicy, copyFn)
-
+        item._status &= ~Item.NODIRTY
+        item.setDirty(Item.DIRTY, None)
+        
         if hasattr(cls, 'onItemCopy'):
             item.onItemCopy(self)
 
@@ -1399,7 +1486,7 @@
             if not recursive and self.hasChildren():
                 raise ValueError, 'item %s has children, delete must be recursive' %(self)
 
-            self.setDirty()
+            self.setDirty(Item.DIRTY, None)
             self._status |= Item.DELETING
             others = []
 
@@ -1525,7 +1612,7 @@
                 if newRepository is not None:
                     newRepository._registerItem(self)
 
-                    self.setDirty()
+                    self.setDirty(Item.CDIRTY, None)
 
             for child in self.iterChildren(load=False):
                 child._setRoot(root)
@@ -1549,7 +1636,7 @@
     def __setKind(self, kind):
 
         if kind is not self._kind:
-            self.setDirty()
+            self.setDirty(Item.DIRTY, None)
 
             if self._kind is not None:
                 if kind is None:
@@ -1749,7 +1836,7 @@
                 parent._removeItem(self)
                 self._name = name or self._uuid.str64()
                 parent._addItem(self)
-                self.setDirty(dirty=Item.SDIRTY)
+                self.setDirty(Item.SDIRTY, None)
                 
             if not '_origName' in self.__dict__:
                 self.__dict__['_origName'] = (parent.itsUUID, origName)
@@ -2304,9 +2391,10 @@
     SAVED      = 0x1000
     ADIRTY     = 0x2000           # acl(s) changed
     PINNED     = 0x4000           # auto-refresh, don't stale
-
+    NODIRTY    = 0x8000           # turn off dirtying
+    
     VRDIRTY    = VDIRTY | RDIRTY
-    DIRTY      = VDIRTY | SDIRTY | CDIRTY | RDIRTY | ADIRTY
+    DIRTY      = VDIRTY | SDIRTY | CDIRTY | RDIRTY
 
     __access__ = 0L
 
@@ -2408,9 +2496,9 @@
     def linkChanged(self, link, key):
 
         if key is None:
-            self._item.setDirty(dirty=Item.CDIRTY)
+            self._item.setDirty(Item.CDIRTY, None)
         else:
-            link._value.setDirty(dirty=Item.SDIRTY)
+            link._value.setDirty(Item.SDIRTY, None)
     
     def __repr__(self):
 

Index: chandler/repository/item/PersistentCollections.py
diff -u chandler/repository/item/PersistentCollections.py:1.18 chandler/repository/item/PersistentCollections.py:1.19
--- chandler/repository/item/PersistentCollections.py:1.18	Sun Aug  1 04:14:40 2004
+++ chandler/repository/item/PersistentCollections.py	Thu Aug 19 11:06:25 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.18 $"
-__date__      = "$Date: 2004/08/01 11:14:40 $"
+__revision__  = "$Revision: 1.19 $"
+__date__      = "$Date: 2004/08/19 18:06:25 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -60,20 +60,25 @@
         if self._readOnly:
             raise ReadOnlyError, 'collection is read-only'
 
-        if self._item:
-            self._item.setDirty()
+        item = self._item
+        if item is not None:
+            item.setDirty(item.VDIRTY, self._attribute, item._values)
 
-    def _prepareValue(self, value):
+    def _prepareValue(self, value, setDirty=True):
 
         if isinstance(value, PersistentCollection):
             value = value._copy(self._item, self._attribute, self._companion,
                                 'copy', lambda x, other, z: other)
         elif isinstance(value, list):
-            value = PersistentList(self._item, self._attribute,
-                                   self._companion, value)
+            persistentValue = PersistentList(self._item, self._attribute,
+                                             self._companion)
+            persistentValue.extend(value, setDirty)
+            value = persistentValue
         elif isinstance(value, dict):
-            value = PersistentDict(self._item, self._attribute,
-                                   self._companion, value)
+            persistentValue = PersistentDict(self._item, self._attribute,
+                                             self._companion)
+            persistentValue.update(value, setDirty)
+            value = persistentValue
         elif isinstance(value, repository.item.Item.Item):
             value = SingleRef(value._uuid)
         elif isinstance(value, repository.item.Values.ItemValue):
@@ -123,14 +128,11 @@
 class PersistentList(list, PersistentCollection):
     'A persistence aware list, tracking changes into a dirty bit.'
 
-    def __init__(self, item, attribute, companion, initialValues=None):
+    def __init__(self, item, attribute, companion):
 
         list.__init__(self)
         PersistentCollection.__init__(self, item, attribute, companion)
 
-        if initialValues is not None:
-            self.extend(initialValues)
-
     def _copy(self, item, attribute, companion, copyPolicy, copyFn):
 
         copy = type(self)(item, attribute, companion)
@@ -141,12 +143,12 @@
             if isinstance(value, repository.item.Item.Item):
                 value = copyFn(item, value, policy)
                 if value is not None:
-                    copy.append(value)
+                    copy.append(value, False)
             elif isinstance(value, PersistentCollection):
                 copy.append(value._copy(item, attribute, companion,
-                                        copyPolicy, copyFn))
+                                        copyPolicy, copyFn), False)
             else:
-                copy.append(value)
+                copy.append(value, False)
 
         return copy
 
@@ -154,86 +156,87 @@
 
         self._storeValue(value)
         value = self._prepareValue(value)
-        self._setDirty()
         super(PersistentList, self).__setitem__(index, value)
+        self._setDirty()
 
     def __delitem__(self, index):
 
-        self._setDirty()
         super(PersistentList, self).__delitem__(index)        
+        self._setDirty()
 
     def __setslice__(self, start, end, value):
 
         for v in value:
             self._storeValue(v)
         value = [self._prepareValue(v) for v in value]
-        self._setDirty()
         super(PersistentList, self).__setslice__(start, end, value)
+        self._setDirty()
 
     def __delslice__(self, start, end):
 
-        self._setDirty()
         super(PersistentList, self).__delslice__(start, end)
+        self._setDirty()
 
     def __iadd__(self, value):
 
         for v in value:
             self._storeValue(v)
         value = [self._prepareValue(v) for v in value]
-        self._setDirty()
         super(PersistentList, self).__iadd__(value)
+        self._setDirty()
 
     def __imul__(self, value):
 
-        self._setDirty()
         super(PersistentList, self).__imul__(value)
+        self._setDirty()
 
-    def append(self, value):
+    def append(self, value, setDirty=True):
 
         self._storeValue(value)
         value = self._prepareValue(value)
-        self._setDirty()
         super(PersistentList, self).append(value)
 
+        if setDirty:
+            self._setDirty()
+
     def insert(self, index, value):
 
         self._storeValue(value)
         value = self._prepareValue(value)
-        self._setDirty()
         super(PersistentList, self).insert(index, value)
+        self._setDirty()
 
-    def pop(self, index = -1):
+    def pop(self, index=-1):
 
-        self._setDirty()
         value = super(PersistentList, self).pop(index)
         value = self._restoreValue(value)
+        self._setDirty()
 
         return value
 
     def remove(self, value):
 
         value = self._prepareValue(value)
-        self._setDirty()
         super(PersistentList, self).remove(value)
+        self._setDirty()
 
     def reverse(self):
 
-        self._setDirty()
         super(PersistentList, self).reverse()
+        self._setDirty()
 
     def sort(self, *args):
 
-        self._setDirty()
         super(PersistentList, self).sort(*args)
+        self._setDirty()
 
-    def extend(self, value):
+    def extend(self, value, setDirty=True):
 
-        values = []
         for v in value:
             self._storeValue(v)
-            values.append(self._prepareValue(v))
-        self._setDirty()
-        super(PersistentList, self).extend(values)
+            self.append(self._prepareValue(v, False), False)
+        if setDirty:
+            self._setDirty()
 
     def __getitem__(self, key):
 
@@ -266,14 +269,11 @@
 class PersistentDict(dict, PersistentCollection):
     'A persistence aware dict, tracking changes into a dirty bit.'
 
-    def __init__(self, item, attribute, companion, initialValues=None):
+    def __init__(self, item, attribute, companion):
 
         dict.__init__(self)
         PersistentCollection.__init__(self, item, attribute, companion)
 
-        if initialValues is not None:
-            self.update(initialValues)
-
     def _copy(self, item, attribute, companion, copyPolicy, copyFn):
 
         copy = type(self)(item, attribute, companion)
@@ -284,40 +284,41 @@
             if isinstance(value, repository.item.Item.Item):
                 value = copyFn(item, value, policy)
                 if value is not None:
-                    copy[key] = value
+                    copy.__setitem__(key, value, False)
             elif isinstance(value, PersistentCollection):
-                copy[key] = value._copy(item, attribute, companion,
-                                        copyPolicy, copyFn)
+                copy.__setitem__(key, value._copy(item, attribute, companion,
+                                                  copyPolicy, copyFn), False)
             else:
-                copy[key] = value
+                copy.__setitem__(key, value, False)
 
         return copy
 
     def __delitem__(self, key):
 
-        self._setDirty()
         super(PersistentDict, self).__delitem__(key)
+        self._setDirty()
 
-    def __setitem__(self, key, value):
+    def __setitem__(self, key, value, setDirty=True):
 
         self._storeValue(value)
         value = self._prepareValue(value)
-        self._setDirty()
         super(PersistentDict, self).__setitem__(key, value)
 
+        if setDirty:
+            self._setDirty()
+
     def clear(self):
 
-        self._setDirty()
         super(PersistentDict, self).clear()
+        self._setDirty()
 
-    def update(self, value):
+    def update(self, value, setDirty=True):
 
-        values = {}
         for k, v in value.iteritems():
             self._storeValue(v)
-            values[k] = self._prepareValue(v)
-        self._setDirty()
-        super(PersistentDict, self).update(values)
+            self.__setitem__(k, self._prepareValue(v, False), False)
+        if setDirty:
+            self._setDirty()
 
     def setdefault(self, key, value=None):
 
@@ -331,11 +332,10 @@
 
     def popitem(self):
 
-        self._setDirty()
-
         value = super(PersistentDict, self).popitem()
         value = (value[0], self._restoreValue(value[1]))
-        
+        self._setDirty()
+
         return value
 
     def __getitem__(self, key):

Index: chandler/repository/item/ItemRef.py
diff -u chandler/repository/item/ItemRef.py:1.86 chandler/repository/item/ItemRef.py:1.87
--- chandler/repository/item/ItemRef.py:1.86	Wed Aug  4 14:44:17 2004
+++ chandler/repository/item/ItemRef.py	Thu Aug 19 11:06:25 2004
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.86 $"
-__date__      = "$Date: 2004/08/04 21:44:17 $"
+__revision__  = "$Revision: 1.87 $"
+__date__      = "$Date: 2004/08/19 18:06:25 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -15,11 +15,12 @@
     'A wrapper around a bi-directional link between two items.'
     
     def __init__(self, item, name, other, otherName,
-                 otherCard=None, otherPersist=None, otherAlias=None):
+                 otherCard=None, otherPersist=None, otherAlias=None,
+                 setDirty=True):
 
         super(ItemRef, self).__init__()
         self.attach(item, name, other, otherName,
-                    otherCard, otherPersist, otherAlias)
+                    otherCard, otherPersist, otherAlias, setDirty)
 
     def _copy(self, references, item, copyItem, name, policy, copyFn):
 
@@ -59,7 +60,8 @@
         raise DanglingRefError, '%s <-> %s' %(self._item, self._other)
 
     def attach(self, item, name, other, otherName,
-               otherCard=None, otherPersist=None, otherAlias=None):
+               otherCard=None, otherPersist=None, otherAlias=None,
+               setDirty=True):
 
         assert item is not None, 'item is None'
         assert other is not None, 'other is None'
@@ -71,7 +73,11 @@
             if other.hasAttributeValue(otherName):
                 old = other.getAttributeValue(otherName)
                 if isinstance(old, RefDict):
-                    old.__setitem__(item._uuid, self, alias=otherAlias)
+                    try:
+                        sd = old._setFlag(old.SETDIRTY, setDirty)
+                        old.__setitem__(item._uuid, self, alias=otherAlias)
+                    finally:
+                        old._setFlag(old.SETDIRTY, sd)
                     return
             else:
                 if otherCard is None:
@@ -81,11 +87,16 @@
                 if otherCard != 'single':
                     old = other._refDict(otherName, name, otherPersist)
                     other._references[otherName] = old
-                    old.__setitem__(item._uuid, self, alias=otherAlias)
+                    try:
+                        sd = old._setFlag(old.SETDIRTY, setDirty)
+                        old.__setitem__(item._uuid, self, alias=otherAlias)
+                    finally:
+                        old._setFlag(old.SETDIRTY, sd)
                     return
             
             other.setAttributeValue(otherName, self,
-                                    _attrDict=other._references)
+                                    _attrDict=other._references,
+                                    setDirty=setDirty)
 
     def detach(self, item, name, other, otherName):
 
@@ -95,15 +106,15 @@
             old._removeRef(item._uuid)
         else:
             other._removeRef(otherName)
+            other.setDirty(item.VDIRTY, otherName)
 
-        other.setDirty(attribute=otherName, dirty=item.RDIRTY)
-
-    def reattach(self, item, name, old, new, otherName):
+    def reattach(self, item, name, old, new, otherName, setDirty=True):
 
         if old is not new:
             self.detach(item, name, old, otherName)
             self.attach(item, name, new, otherName)
-            item.setDirty(attribute=name)
+            if setDirty:
+                item.setDirty(item.VDIRTY, name, item._values)
 
     def _unload(self, item):
 
@@ -167,7 +178,7 @@
 
         return 1
 
-    def _xmlValue(self, name, item, generator, withSchema, version, flags,
+    def _xmlValue(self, name, item, generator, withSchema, version, attrs,
                   mode, previous=None, next=None, alias=None):
 
         def addAttr(attrs, attr, value):
@@ -183,16 +194,13 @@
                                                                 type(value))
 
         other = self.other(item)
-        attrs = { 'type': 'uuid' }
+        attrs['type'] = 'uuid'
 
         addAttr(attrs, 'name', name)
         addAttr(attrs, 'previous', previous)
         addAttr(attrs, 'next', next)
         addAttr(attrs, 'alias', alias)
 
-        if flags:
-            attrs['flags'] = str(flags)
-
         if withSchema:
             attrs['otherName'] = item._kind.getOtherName(name)
 
@@ -213,7 +221,8 @@
         return self
 
     def attach(self, item, name, other, otherName,
-               otherCard=None, otherPersist=None, otherAlias=None):
+               otherCard=None, otherPersist=None, otherAlias=None,
+               setDirty=True):
         pass
 
     def detach(self, item, name, other, otherName):
@@ -240,12 +249,12 @@
     def _refCount(self):
         return 0
 
-    def _xmlValue(self, name, item, generator, withSchema, version, flags,
+    def _xmlValue(self, name, item, generator, withSchema, version, attrs,
                   mode, previous=None, next=None, alias=None):
 
-        attrs = { 'name': name, 'type': 'none' }
-        if flags:
-            attrs['flags'] = str(flags)
+        attrs['name'] = name
+        attrs['type'] = 'none'
+
         generator.startElement('ref', attrs)
         generator.endElement('ref')
 
@@ -364,45 +373,64 @@
             self.ref = ItemRef(item, self.attrName,
                                ItemStub(item, self), self.otherName,
                                otherCard = self.otherCard,
-                               otherAlias = self.otherAlias)
+                               otherAlias = self.otherAlias,
+                               setDirty=False)
             repository._addStub(self.ref)
-            self.valueDict.__setitem__(self.refName, self.ref, 
-                                       self.previous, self.next, self.alias,
-                                       False)
+
+            vd = self.valueDict
+            if vd._isRefDict():
+                try:
+                    setDirty = vd._setFlag(RefDict.SETDIRTY, False)
+                    vd.__setitem__(self.refName, self.ref, 
+                                   self.previous, self.next,
+                                   self.alias, False)
+                finally:
+                    vd._setFlag(RefDict.SETDIRTY, setDirty)
+            else:
+                vd[self.refName] = self.ref
 
         return None
 
     def _attach(self, item, other):
         
         value = other._references.get(self.otherName)
+
+        def setDict(vd):
+            if vd._isRefDict():
+                try:
+                    sd = vd._setFlag(RefDict.SETDIRTY, False)
+                    vd.__setitem__(self.refName, value,
+                                   self.previous, self.next,
+                                   self.alias, False)
+                finally:
+                    vd._setFlag(RefDict.SETDIRTY, sd)
+            else:
+                vd[self.refName] = value
         
         if value is None or value is NoneRef:
             if self.ref is not None:
                 self.ref.attach(item, self.attrName,
                                 other, self.otherName,
                                 otherCard=self.otherCard,
-                                otherAlias=self.otherAlias)
+                                otherAlias=self.otherAlias,
+                                setDirty=False)
             else:
                 value = ItemRef(item, self.attrName,
                                 other, self.otherName,
                                 otherCard=self.otherCard,
-                                otherAlias=self.otherAlias)
-                self.valueDict.__setitem__(self.refName, value,
-                                           self.previous, self.next,
-                                           self.alias, False)
+                                otherAlias=self.otherAlias,
+                                setDirty=False)
+                setDict(self.valueDict)
 
         elif isinstance(value, ItemRef):
             if isinstance(value._other, Stub):
                 value._other = item
-                self.valueDict.__setitem__(self.refName, value,
-                                           self.previous, self.next,
-                                           self.alias, False)
+                setDict(self.valueDict)
 
             elif isinstance(value._item, Stub):
                 value._item = item
-                self.valueDict.__setitem__(self.refName, value,
-                                           self.previous, self.next,
-                                           self.alias, False)
+                setDict(self.valueDict)
+
             else:
                 return value
 
@@ -412,15 +440,12 @@
                 value = value._getRef(otherRefName)
                 if isinstance(value._other, Stub):
                     value._other = item
-                    self.valueDict.__setitem__(self.refName, value,
-                                               self.previous, self.next,
-                                               self.alias, False)
+                    setDict(self.valueDict)
 
                 elif isinstance(value._item, Stub):
                     value._item = item
-                    self.valueDict.__setitem__(self.refName, value,
-                                               self.previous, self.next,
-                                               self.alias, False)
+                    setDict(self.valueDict)
+
                 else:
                     return value
 
@@ -429,15 +454,15 @@
                     self.ref.attach(item, self.attrName,
                                     other, self.otherName,
                                     otherCard=self.otherCard,
-                                    otherAlias=self.otherAlias)
+                                    otherAlias=self.otherAlias,
+                                    setDirty=False)
                 else:
                     value = ItemRef(item, self.attrName,
                                     other, self.otherName,
                                     otherCard=self.otherCard,
-                                    otherAlias=self.otherAlias)
-                    self.valueDict.__setitem__(self.refName, value,
-                                               self.previous, self.next,
-                                               self.alias, False)
+                                    otherAlias=self.otherAlias,
+                                    setDirty=False)
+                    setDict(self.valueDict)
 
         else:
             raise ValueError, value
@@ -477,9 +502,37 @@
         self._aliases = None
         self._readOnly = readOnly
         self._indexes = None
+        self._flags = RefDict.SETDIRTY
         
         super(RefDict, self).__init__()
 
+    def _isRefDict(self):
+
+        return True
+    
+    def _setFlag(self, flag, on):
+
+        old = self._flags & flag != 0
+        if on:
+            self._flags |= flag
+        else:
+            self._flags &= ~flag
+
+        return old
+
+    def _getFlag(self, flag):
+
+        return self._flags & flag != 0
+
+    def _setDirty(self, noMonitors=False):
+
+        if self._getFlag(RefDict.SETDIRTY):
+            item = self._item
+            if noMonitors:
+                item.setDirty(item.RDIRTY, self._name)
+            else:
+                item.setDirty(item.RDIRTY, self._name, item._references)
+
     def _copy(self, references, item, copyItem, name, policy, copyFn):
 
         try:
@@ -588,7 +641,12 @@
 
         if not self._getRepository().isLoading():
             self.fillIndex(index)
-            self._item.setDirty(attribute=self._name, dirty=self._item.RDIRTY)
+            self._setDirty(noMonitors=True)
+
+            if indexType == 'attribute':
+                from repository.item.Monitors import Monitors
+                Monitors.attach(self._item, '_reIndex',
+                                'set', kwds['attribute'], self._name, name)
 
     def _createIndex(self, indexType, **kwds):
 
@@ -608,7 +666,7 @@
     def removeIndex(self, name):
 
         del self._indexes[name]
-        self._item.setDirty(attribute=self._name, dirty=self._item.RDIRTY)
+        self._setDirty(noMonitors=True)
 
     def fillIndex(self, index):
 
@@ -630,8 +688,14 @@
         list to this ref collection.
         """
         
-        for value in valueList:
-            self.append(value)
+        try:
+            sd = self._setFlag(RefDict.SETDIRTY, False)
+            for value in valueList:
+                self.append(value, None)
+        finally:
+            self._setFlag(RefDict.SETDIRTY, sd)
+
+        self._setDirty()
 
     def update(self, dictionary, setAliases=False):
         """
@@ -644,12 +708,18 @@
         @type setAliases: boolean
         """
 
-        if setAliases:
-            for alias, value in dictionary.iteritems():
-                self.append(value, alias)
-        else:
-            for value in dictionary.itervalues():
-                self.append(value)
+        try:
+            sd = self._setFlag(RefDict.SETDIRTY, False)
+            if setAliases:
+                for alias, value in dictionary.iteritems():
+                    self.append(value, alias)
+            else:
+                for value in dictionary.itervalues():
+                    self.append(value, None)
+        finally:
+            self._setFlag(RefDict.SETDIRTY, sd)
+
+        self._setDirty()
 
     def append(self, item, alias=None):
         """
@@ -667,13 +737,19 @@
         """
         Remove all references from this ref collection.
         """
-        
-        key = self.firstKey()
-        while key is not None:
-            nextKey = self.nextKey(key)
-            del self[key]
-            key = nextKey
 
+        try:
+            sd = self._setFlag(RefDict.SETDIRTY, False)
+            key = self.firstKey()
+            while key is not None:
+                nextKey = self.nextKey(key)
+                del self[key]
+                key = nextKey
+        finally:
+            self._setFlag(RefDict.SETDIRTY, sd)
+
+        self._setDirty()
+            
     def dir(self):
         """
         Debugging: print all items referenced in this ref collection.
@@ -691,14 +767,15 @@
                     load=True):
 
         loading = self._getRepository().isLoading()
-        if loading and previousKey is None and nextKey is None:
-            ref = self._loadRef(key)
-            if ref is not None:
-                previousKey, nextKey, alias = ref
+        if loading:
+            if previousKey is None and nextKey is None:
+                ref = self._loadRef(key)
+                if ref is not None:
+                    previousKey, nextKey, alias = ref
         
         old = super(RefDict, self).get(key, None, load)
         if not loading:
-            self._changeRef(key)
+            self._changeRef(key, None)
 
         if old is not None:
             item = self._getItem()
@@ -764,9 +841,9 @@
             super(RefDict, self).place(key, afterKey)
         else:
             self._indexes[indexName].moveKey(key, afterKey)
-            self._item.setDirty(attribute=self._name, dirty=self._item.RDIRTY)
+            self._setDirty()
 
-    def removeItem(self, item):
+    def remove(self, item):
         """
         Remove a referenced item from this reference collection.
 
@@ -780,18 +857,22 @@
 
         self._removeRef(key, True)
 
-    def _changeRef(self, key, alias=None):
+    def _changeRef(self, key, alias=None, noMonitors=False):
 
         if self._readOnly:
             raise AttributeError, 'Value for %s on %s is read-only' %(self._name, self._item.itsPath)
 
-        self._item.setDirty(attribute=self._name, dirty=self._item.RDIRTY)
+        self._setDirty(noMonitors)
 
     def _removeRef(self, key, _detach=False):
 
         if self._readOnly:
             raise AttributeError, 'Value for %s on %s is read-only' %(self._name, self._item.itsPath)
 
+        if self._indexes:
+            for index in self._indexes.itervalues():
+                index.removeKey(key)
+
         value = self._getRef(key)
 
         if _detach:
@@ -803,9 +884,6 @@
             del self._aliases[link._alias]
             
         self._count -= 1
-        if self._indexes:
-            for index in self._indexes.itervalues():
-                index.removeKey(key)
 
         return link
 
@@ -845,7 +923,7 @@
     def linkChanged(self, link, key):
 
         if key is not None:
-            self._changeRef(key)
+            self._changeRef(key, noMonitors=True)
 
     def _getRef(self, key, load=True):
 
@@ -986,13 +1064,13 @@
         """
 
         self._indexes[indexName].setEntryValue(item._uuid, value)
-        self._item.setDirty(attribute=self._name, dirty=self._item.RDIRTY)
+        self._setDirty()
 
     def _refCount(self):
 
         return len(self)
 
-    def _xmlValue(self, name, item, generator, withSchema, version, flags,
+    def _xmlValue(self, name, item, generator, withSchema, version, attrs,
                   mode):
 
         def addAttr(attrs, attr, value):
@@ -1007,7 +1085,7 @@
                     raise NotImplementedError, "%s, type: %s" %(value,
                                                                 type(value))
 
-        attrs = { 'name': name }
+        attrs['name'] = name
         
         if withSchema:
             attrs['cardinality'] = 'list'
@@ -1017,9 +1095,6 @@
         addAttr(attrs, 'last', self._lastKey)
         attrs['count'] = str(self._count)
 
-        if flags:
-            attrs['flags'] = str(flags)
-
         generator.startElement('ref', attrs)
         self._xmlValues(generator, version, mode)
         generator.endElement('ref')
@@ -1029,7 +1104,7 @@
         for key in self.iterkeys():
             link = self._get(key)
             link._value._xmlValue(key, self._item,
-                                  generator, False, version, 0, mode,
+                                  generator, False, version, {}, mode,
                                   previous=link._previousKey,
                                   next=link._nextKey,
                                   alias=link._alias)
@@ -1189,6 +1264,8 @@
 
         return True
 
+    SETDIRTY = 0x0001
+
 
 class TransientRefDict(RefDict):
     """
@@ -1198,7 +1275,7 @@
     def linkChanged(self, link, key):
         pass
     
-    def _changeRef(self, key, alias=None):
+    def _changeRef(self, key, alias=None, noMonitors=False):
         pass
 
     def check(self, item, name):



More information about the Commits mailing list