1 # All changes go through here so we can undo...
4 from xml
.dom
import Node
6 # Which undo list operations will affect.
7 # Normal ops add to the undo list.
8 # Undo ops add to the redo list.
9 # Redo ops add to the undo list, but don't clear the redo list.
10 undo_state
= '__dom_undo'
13 # This value is stored with each undo record.
14 # The caller may use this to indicate whether several operations
15 # should be considered as one.
18 # These actually modifiy the DOM
19 def set_name(node
, namespaceURI
, qname
):
21 tmp
= node
.ownerDocument
.createElementNS(namespaceURI
, qname
)
22 add_undo(node
, lambda node
= node
, ns
= node
.namespaceURI
, name
= node
.nodeName
:
23 set_name(node
, ns
, name
))
24 node
.__dict
__['__nodeName'] = tmp
.__dict
__['__nodeName']
25 node
.__dict
__['__namespaceURI'] = tmp
.__dict
__['__namespaceURI']
26 node
.__dict
__['__prefix'] = tmp
.__dict
__['__prefix']
27 node
.__dict
__['__localName'] = tmp
.__dict
__['__localName']
29 def insert_before(node
, new
, parent
):
30 "Insert 'new' before 'node'. If 'node' is None then insert at the end"
31 "of parent's children."
32 if new
.nodeType
== Node
.DOCUMENT_FRAGMENT_NODE
:
33 raise Exception("insert_before() can't take a fragment!")
34 parent
.insertBefore(new
, node
)
35 add_undo(parent
, lambda new
= new
: delete(new
))
38 next
= node
.nextSibling
39 parent
= node
.parentNode
40 parent
.removeChild(node
)
42 lambda parent
= parent
, next
= next
, node
= node
:
43 insert_before(next
, node
, parent
= parent
))
45 def replace_node(old
, new
):
46 old
.parentNode
.replaceChild(new
, old
)
47 add_undo(new
.parentNode
,
48 lambda old
= old
, new
= new
:
49 replace_node(new
, old
))
51 def set_data(node
, new
):
55 lambda node
= node
, old
= old
:
58 def set_attrib(node
, namespaceURI
, localName
, value
= None):
59 #print "set_attrib", `namespaceURI`, `localName`, `value`
60 if node
.hasAttributeNS(namespaceURI
, localName
):
61 old
= node
.getAttributeNS(namespaceURI
, localName
)
67 node
.setAttributeNS(namespaceURI
, localName
, value
)
69 node
.removeAttributeNS(namespaceURI
, localName
)
71 add_undo(node
, lambda node
= node
, namespaceURI
= namespaceURI
, localName
= localName
, old
= old
: \
72 set_attrib(node
, namespaceURI
, localName
, old
))
78 def newest_change(node
, history
):
79 "Return the most recent (node,time) change to the 'history' list."
82 best_node
, best_time
= node
, getattr(node
, history
)[-1][0]
84 best_node
, best_time
= None, 0
86 for k
in node
.childNodes
:
87 n
, t
= newest_change(k
, history
)
88 if n
and (best_node
== None or t
> best_time
):
89 best_node
, best_time
= n
, t
90 return best_node
, best_time
93 n
, t
= newest_change(node
, '__dom_undo')
97 n
, t
= newest_change(node
, '__dom_redo')
100 # Undo and redo stuff
101 # XXX: Undo/redo need to check locking
102 def add_undo(node
, fn
):
103 "Attempting to undo changes to 'node' will call this fn."
108 if not hasattr(node
, undo_state
):
109 setattr(node
, undo_state
, [])
110 getattr(node
, undo_state
).append((op
, fn
, user_op
))
111 if undo_clear
and hasattr(node
, '__dom_redo'):
114 def do_undo(node
, user_op
= None):
115 "Undo changes to this node (including descendants)."
116 "Returns the node containing the undone node, and the user_op."
117 "If 'user_op' is given, only undo if it matches, else return None."
118 node
, time
= newest_change(node
, '__dom_undo')
121 op
, fn
, uop
= node
.__dom
_undo
[-1]
122 if user_op
and user_op
!= uop
:
124 parent
= node
.parentNode
126 del node
.__dom
_undo
[-1]
128 global undo_state
, undo_clear
129 undo_state
= '__dom_redo'
133 undo_state
= '__dom_undo'
137 def do_redo(node
, user_op
= None):
138 "Redo undos on this node (including descendants)."
139 "Returns the node containing the redone node, and the user_op."
140 "If 'user_op' is given, only redo if it matches, else return None."
141 node
, time
= newest_change(node
, '__dom_redo')
144 op
, fn
, uop
= node
.__dom
_redo
[-1]
145 if user_op
and user_op
!= uop
:
147 parent
= node
.parentNode
149 del node
.__dom
_redo
[-1]
151 global undo_state
, undo_clear