diff pyink/unlink_clone.py @ 1299:6949e2b6cae2

Add unlink clone checker. - Monitor changes of DOM-tree of the document - Unlinking a clone is actually removing the clone and copying nodes from the source. - Copy value of ID of a node to saved_id to track source of copy nodes. - For a new node with 'saved_id' is a copy of another node. - Copy vulae of 'saved_id' to 'ns0:duplicate-src' to keep the source - Change value of 'saved_id' to the value of ID of the node for later copying. - For a new node without 'saved_id' is not a copy of another node. - only set 'saved_id' to the value of its ID.
author Thinker K.F. Li <thinker@codemud.net>
date Sun, 16 Jan 2011 16:13:37 +0800
parents
children 2a35a1cb6cdf
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pyink/unlink_clone.py	Sun Jan 16 16:13:37 2011 +0800
@@ -0,0 +1,109 @@
+import dom_event
+from data_monitor import data_monitor
+
+class unlink_clone_checker(object):
+    __metaclass__ = data_monitor
+    
+    _no_change_attrs = ('ns0:duplicate-src', 'saved_id')
+    
+    def __init__(self, domview_ui):
+        self._domviewui = domview_ui
+        self._locker = domview_ui
+        self._doc = None
+        self._root = None
+        pass
+
+    def _start_check(self):
+        doc = self._doc
+	dom_event.addEventListener(doc, 'DOMNodeInserted',
+                                   self.do_insert_node, None)
+	dom_event.addEventListener(doc, 'DOMAttrModified',
+                                   self.do_attr_modified, None)
+        pass
+
+    def handle_doc_root(self, doc, root):
+        self._doc = doc
+        self._root = root
+
+        self._start_check()
+        pass
+
+    def _handle_unlinked_or_copied_nodes(self, node, child):
+        try:
+            saved_id = child.getAttribute('saved_id')
+        except:                 # Skip it for losting saved_id
+            pass
+        else:
+            child.setAttribute('ns0:duplicate-src', saved_id)
+            pass
+        
+        try:
+            child_id = child.getAttribute('id')
+        except:                 # still have no ID.
+            pass                # Assign saved_id later with attr
+                                # modified event.
+        else:
+            child.setAttribute('saved_id', child_id)
+            pass
+        pass
+
+    def _handle_new_nodes(self, node, child):
+        if child.name() == 'svg:use':
+            return
+
+        try:
+            child_id = child.getAttribute('id')
+        except KeyError:
+            return
+        child.setAttribute('saved_id', child_id)
+        pass
+
+    ## \brief Check inserted node recurisvely.
+    #
+    # Travel the tree in post-order.
+    #
+    def _handle_insert_node_recursive(self, node, child):
+        #
+        # Traveling forest of children.
+        #
+        for cchild in child.childList():
+            self._handle_insert_node_recursive(child, cchild)
+            pass
+        
+        #
+        # Visit the node
+        #
+        try:
+            child_id = child.getAttribute('saved_id')
+        except KeyError:                 # have no saved_id
+            pass
+        else:
+            self._handle_unlinked_or_copied_nodes(node, child)
+            return
+
+        # have no saved_id
+        self._handle_new_nodes(node, child)
+        pass
+
+    def do_insert_node(self, node, child):
+        self._handle_insert_node_recursive(node, child)
+        pass
+
+    def do_attr_modified(self, node, name, old_value, new_value):
+        if name == 'id' and node.name() != 'svg:use':
+            #
+            # The ID of a node may not be assigned when it being
+            # inserted, and be assigned later.  So, we checking
+            # attribute modification event to assign value of
+            # saved_id.
+            #
+            node.setAttribute('saved_id', new_value)
+        elif old_value and (name in self._no_change_attrs):
+            #
+            # Restore to old value for attributes that is not allowed
+            # to be changed by the user.
+            #
+            node.setAttribute(name, old_value)
+            pass
+        pass
+    pass