1 from rox
import g
, TRUE
, FALSE
2 from gnome2
import canvas
3 from xml
.dom
import Node
4 from constants
import *
7 watch_cursor
= g
.gdk
.Cursor(g
.gdk
.WATCH
)
8 no_cursor
= g
.gdk
.Cursor(g
.gdk
.TCROSS
)
10 def set_busy(widget
, busy
= TRUE
):
15 w
.set_cursor(watch_cursor
)
17 w
.set_cursor(no_cursor
)
21 while len(str) > width
:
22 i
= str[:width
].rfind(' ')
25 ret
= ret
+ str[:i
+ 1] + '\n'
33 #default_font = __main__.default_font
35 class Display(canvas
.Canvas
):
36 def __init__(self
, window
, view
):
37 canvas
.Canvas
.__init
__(self
)
39 self
.parent_window
= window
40 self
.root_group
= None
41 self
.update_timeout
= 0
42 self
.update_nodes
= {} # Set of nodes to update on update_timeout
43 self
.current_attrib
= None # Canvas group
44 self
.node_to_group
= {}
48 s
= self
.get_style().copy()
49 s
.bg
[g
.STATE_NORMAL
] = g
.gdk
.color_parse('old lace')
52 self
.connect('size-allocate', self
.size_allocate
)
53 self
.connect('destroy', self
.destroyed
)
54 self
.connect('button-press-event', self
.bg_event
)
58 #rox.app_options.add_notify(self.options_changed)
60 def size_allocate(self
, canvas
, size
):
61 x
, y
, width
, height
= self
.get_allocation()
62 chains
= self
.parent_window
.list.chains
75 def set_view(self
, view
):
77 self
.view
.remove_display(self
)
79 self
.view
.add_display(self
)
85 (x
, y
, w
, h
) = self
.get_allocation()
89 #self.update_now() # GnomeCanvas bug?
90 min_x
, min_y
, max_x
, max_y
= self
.root().get_bounds()
95 self
.set_scroll_region(min_x
- m
, min_y
- m
, max_x
+ m
, max_y
+ m
)
96 self
.root().move(0, 0) # Magic!
98 def update_record_state(self
):
99 self
.parent_window
.update_title()
101 def update_all(self
, node
= None):
103 node
= self
.view
.model
.doc
.documentElement
105 if node
== self
.view
.root
:
106 self
.update_nodes
= {node
: None}
107 elif node
not in self
.update_nodes
:
108 # Note: we don't eliminate duplicates (parent and child) nodes
109 # here because it takes *ages*
110 self
.update_nodes
[node
] = None
112 if self
.update_timeout
or not self
.visible
:
113 return # Going to update anyway...
115 if self
.view
.running():
116 self
.update_timeout
= g
.timeout_add(2000, self
.update_callback
)
118 self
.update_timeout
= g
.timeout_add(10, self
.update_callback
)
120 def do_update_now(self
):
121 # Update now, if we need to
122 if self
.update_timeout
:
123 g
.timeout_remove(self
.update_timeout
)
124 self
.update_callback()
125 #self.update_timeout = g.timeout_add(10, self.update_callback)
127 def update_callback(self
):
128 print "update_callback"
129 self
.update_timeout
= 0
130 #print "Update...", self.update_nodes
133 for node
in self
.update_nodes
:
134 root
= self
.view
.root
135 if node
is not root
and self
.view
.has_ancestor(node
, root
):
136 # The root is OK - the change is inside...
138 group
= self
.node_to_group
[node
]
139 #if group.flags() & DESTROYED:
140 # print "(group destroyed)"
141 # raise Exception('Group destroyed')
143 # Modified node not created yet.
144 # Don't worry, updating the parent later
146 print "(node missing)"
149 # Can't delete all children, so create a new group
151 parent
= group
.get_property('parent')
152 x
= group
.get_property('x')
153 y
= group
.get_property('y')
154 gr
= parent
.add(canvas
.CanvasGroup
, x
= x
, y
= y
)
156 group
.attrib_to_group
= None
157 self
.node_to_group
[node
] = gr
158 gr
.connect('event', self
.node_event
, node
)
160 self
.create_tree(node
, gr
, cramped
= group
.cramped
)
161 self
.auto_highlight(node
, rec
= 1)
162 self
.child_group_resized(node
)
164 # Need to rebuild everything...
166 self
.root_group
.destroy()
167 self
.node_to_group
= {}
168 self
.root_group
= self
.root().add(canvas
.CanvasGroup
, x
= 0, y
= 0)
169 group
= self
.root_group
170 node
= self
.view
.root
171 group
.connect('event', self
.node_event
, node
)
172 print "creating tree..."
173 self
.create_tree(node
, group
)
174 print "highlighting..."
175 self
.auto_highlight(node
, rec
= 1)
179 if self
.view
.current_nodes
:
180 self
.scroll_to_show(self
.view
.current_nodes
[0])
182 set_busy(self
, FALSE
)
183 self
.update_nodes
= {}
184 #print "<update_callback"
187 def child_group_resized(self
, node
):
188 "The group for this node has changed size. Work up the tree making room for "
189 "it (and put it in the right place)."
191 if node
== self
.view
.root
or node
not in self
.node_to_group
:
193 node
= node
.parentNode
194 if node
not in self
.node_to_group
:
196 for n
in node
.childNodes
:
198 kids
.append(self
.node_to_group
[n
])
201 self
.position_kids(self
.node_to_group
[node
], kids
)
202 self
.child_group_resized(node
)
204 def auto_highlight(self
, node
, rec
= 0):
206 for x
in self
.view
.current_nodes
:
208 cattr
= self
.view
.current_attrib
210 "After creating the tree, everything is highlighted..."
212 self
.highlight(self
.node_to_group
[node
], cattr
== None and node
in a
)
216 map(do
, node
.childNodes
)
219 def options_changed(self
):
220 if default_font
.has_changed
:
223 def destroyed(self
, widget
):
224 self
.view
.remove_display(self
)
225 #rox.app_options.remove_notify(self.options_changed)
227 def create_attribs(self
, attrib
, group
, cramped
, parent
):
228 group
.text
= group
.add(canvas
.CanvasText
, x
= 0, y
= -6, anchor
= g
.ANCHOR_NW
,
229 fill_color
= 'grey40',
230 #font = default_font.value,
231 text
= "%s=%s" % (str(attrib
.name
), str(attrib
.value
)))
232 group
.connect('event', self
.attrib_event
, parent
, attrib
)
234 #self.update_now() # GnomeCanvas bug?
235 (lx
, ly
, hx
, hy
) = group
.text
.get_bounds()
236 group
.rect
= group
.add(canvas
.CanvasRect
,
237 x1
= lx
- 1, y1
= ly
- 1, x2
= hx
+ 1, y2
= hy
+ 1,
239 group
.rect
.lower_to_bottom()
241 def create_tree(self
, node
, group
, cramped
= 0):
242 if node
.nodeType
== Node
.ELEMENT_NODE
:
243 hidden
= node
.hasAttributeNS(None, 'hidden')
248 group
.cramped
= cramped
251 elif node
.nodeType
== Node
.TEXT_NODE
:
255 group
.add(canvas
.CanvasEllipse
, x1
= -4, y1
= -4, x2
= 4, y2
= 4,
256 fill_color
= c
, outline_color
= 'black')
257 text
= self
.get_text(node
)
259 hbox
= node
.nodeName
== 'tr'
261 text
= wrap(text
, 32)
263 text
= wrap(text
, 1000)
264 group
.text
= group
.add(canvas
.CanvasText
, x
= 10 , y
= -6, anchor
= g
.ANCHOR_NW
,
265 #font = default_font.value,
266 fill_color
= 'black', text
= text
)
267 self
.node_to_group
[node
] = group
269 #self.update_now() # GnomeCanvas bug?
270 (lx
, ly
, hx
, hy
) = group
.text
.get_bounds()
271 group
.rect
= group
.add(canvas
.CanvasRect
,
272 x1
= -8 , y1
= ly
- 1, x2
= hx
+ 1, y2
= hy
+ 1,
279 if node
.nodeType
== Node
.ELEMENT_NODE
:
280 group
.attrib_to_group
= {}
286 for key
in node
.attributes
:
287 a
= node
.attributes
[key
]
288 value
= a
.value
or ''
289 l
+= len(a
.name
) + len(value
)
293 for key
in node
.attributes
:
294 a
= node
.attributes
[key
]
295 gr
= group
.add(canvas
.CanvasGroup
, x
= ax
, y
= ay
)
296 self
.create_attribs(a
, gr
, cramped
, node
)
297 #self.update_now() # GnomeCanvas bug?
298 (alx
, aly
, ahx
, ahy
) = gr
.get_bounds()
304 group
.attrib_to_group
[a
] = gr
309 for n
in node
.childNodes
:
310 gr
= group
.add(canvas
.CanvasGroup
, x
= 0, y
= 0)
311 gr
.connect('event', self
.node_event
, n
)
312 self
.create_tree(n
, gr
, cramped
)
315 self
.position_kids(group
, kids
)
316 group
.rect
.lower_to_bottom()
318 def position_kids(self
, group
, kids
):
322 #assert not group.flags() & DESTROYED
324 # assert not k.flags() & DESTROYED
327 indent
= cramped_indent
329 indent
= normal_indent
334 if hasattr(group
, 'lines'):
335 for l
in group
.lines
:
339 if node
.nodeName
!= 'tr':
344 #self.update_now() # GnomeCanvas bug?
345 (lx
, ly
, hx
, hy
) = gr
.get_bounds()
348 gr
.set(x
= indent
, y
= y
)
352 diag
= min(top
, indent
)
355 points
= (4, 4, diag
, diag
, indent
, top
, indent
,
356 min(lowest_child
, top
+ max_segment
))
357 group
.lines
.append(group
.add(canvas
.CanvasLine
,
358 points
= points
, fill_color
= 'black', width_pixels
= 1))
359 group
.lines
[-1].lower_to_bottom()
360 while points
[-1] < lowest_child
:
362 points
= (indent
, old_y
, indent
,
363 min(old_y
+ max_segment
, lowest_child
))
364 group
.lines
.append(group
.add(canvas
.CanvasLine
,
365 points
= points
, fill_color
= 'black', width_pixels
= 1))
366 group
.lines
[-1].lower_to_bottom()
372 #self.update_now() # GnomeCanvas bug?
373 (lx
, ly
, hx
, hy
) = gr
.get_bounds()
375 gr
.set(x
= x
, y
= y
- ly
)
376 group
.lines
.append(group
.add(canvas
.CanvasLine
,
377 points
= (x
, y
- 4, x
, y
- ly
- 4),
378 fill_color
= 'black',
382 group
.lines
.append(group
.add(canvas
.CanvasLine
,
383 points
= (0, 4, 0, y
- 4, right_child
, y
- 4),
384 fill_color
= 'black',
386 group
.lines
[-1].lower_to_bottom()
388 def get_text(self
, node
):
389 if node
.nodeType
== Node
.TEXT_NODE
:
390 return node
.nodeValue
.strip()
391 elif node
.nodeType
== Node
.ELEMENT_NODE
:
393 elif node
.nodeType
== Node
.COMMENT_NODE
:
394 return node
.nodeValue
.strip()
398 return '<noname>' + node
.nodeValue
402 def show_menu(self
, bev
):
405 def bg_event(self
, widget
, event
):
406 if event
.type == g
.gdk
.BUTTON_PRESS
and event
.button
== 3:
407 self
.show_menu(event
)
410 # 'group' and 'node' may be None (for the background)
411 def node_event(self
, group
, event
, node
):
412 if (event
.type == g
.gdk
.BUTTON_PRESS
or event
.type == g
.gdk
._2BUTTON
_PRESS
) and event
.button
== 1:
414 self
.node_clicked(node
, event
)
418 def attrib_event(self
, group
, event
, element
, attrib
):
419 if event
.type != g
.gdk
.BUTTON_PRESS
or event
.button
== 3:
422 self
.attrib_clicked(element
, attrib
, event
)
425 def node_clicked(self
, node
, event
):
428 def attrib_clicked(self
, element
, attrib
, event
):
431 def move_from(self
, old
= []):
432 self
.set_current_attrib(self
.view
.current_attrib
)
434 new
= self
.view
.current_nodes
436 if self
.view
.current_attrib
or n
not in new
:
438 self
.highlight(self
.node_to_group
[n
], FALSE
)
441 if self
.update_timeout
or not self
.visible
:
442 return # We'll highlight on the callback...
443 # We can update without structural problems...
444 if self
.view
.current_nodes
:
445 self
.scroll_to_show(self
.view
.current_nodes
[0])
446 if self
.view
.current_attrib
:
451 self
.highlight(self
.node_to_group
[n
], TRUE
)
453 print "Warning: Node %s not in node_to_group" % n
455 def set_current_attrib(self
, attrib
):
456 "Select 'attrib' attribute node of the current node. None to unselect."
457 if self
.current_attrib
:
458 if self
.current_attrib
.get_property('parent'):
459 self
.current_attrib
.rect
.set(fill_color
= None)
460 self
.current_attrib
.text
.set(fill_color
= 'grey40')
463 group
= self
.node_to_group
[self
.view
.get_current()].attrib_to_group
[attrib
]
464 group
.rect
.set(fill_color
= 'light blue')
465 group
.text
.set(fill_color
= 'grey40')
466 self
.current_attrib
= group
470 self
.current_attrib
= None
472 def marked_changed(self
, nodes
):
473 "nodes is a list of nodes to be rechecked."
474 marked
= self
.view
.marked
477 group
= self
.node_to_group
[n
]
478 group
.rect
.set(outline_color
= (n
in marked
and 'orange') or None)
480 pass # Will regenerate later
482 def highlight(self
, group
, state
):
485 #group.text.set(fill_color = 'white')
491 if nt
== 1: #Node.ELEMENT_NODE:
492 group
.text
.set(fill_color
= 'black')
493 elif nt
== 3: #Node.TEXT_NODE:
494 group
.text
.set(fill_color
= 'blue')
495 elif nt
== 8: #Node.COMMENT_NODE:
496 group
.text
.set(fill_color
= 'darkgreen')
498 group
.text
.set(fill_color
= 'red')
500 if node
in self
.view
.marked
:
504 group
.rect
.set(fill_color
= rfill
, outline_color
= oc
)
506 def world_to_canvas(self
, (x
, y
)):
507 "Canvas routine seems to be broken..."
508 mx
, my
, maxx
, maxy
= self
.get_scroll_region()
509 return (x
- mx
, y
- my
)
511 def scroll_to_show(self
, node
):
513 group
= self
.node_to_group
[node
]
516 #self.update_now() # GnomeCanvas bug?
517 (lx
, ly
, hx
, hy
) = group
.rect
.get_bounds()
518 x
, y
= self
.world_to_canvas(group
.i2w(0, 0))
525 sx
, sy
= self
.get_scroll_offsets()
531 (x
, y
, w
, h
) = self
.get_allocation()
540 self
.scroll_to(sx
, sy
)