]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wxPython/tools/XRCed/tree.py
4036f5d249b077128bef2b3f79742be2c8b24ba9
[wxWidgets.git] / wxPython / wxPython / tools / XRCed / tree.py
1 # Name: tree.py
2 # Purpose: XRC editor, XML_tree class
3 # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
4 # Created: 02.12.2002
5 # RCS-ID: $Id$
6
7 from xxx import * # xxx imports globals and params
8
9 # Icons
10 import images
11
12 class MemoryFile:
13 def __init__(self, name):
14 self.name = name
15 self.buffer = ''
16 def write(self, data):
17 self.buffer += data.encode()
18 def close(self):
19 wxMemoryFSHandler_AddFile(self.name, self.buffer)
20
21 ################################################################################
22
23 # Redefine writing to include encoding
24 class MyDocument(minidom.Document):
25 def __init__(self):
26 minidom.Document.__init__(self)
27 self.encoding = ''
28 def writexml(self, writer, indent="", addindent="", newl="", encoding=""):
29 if encoding: encdstr = 'encoding="%s"' % encoding
30 else: encdstr = ''
31 writer.write('<?xml version="1.0" %s?>\n' % encdstr)
32 for node in self.childNodes:
33 node.writexml(writer, indent, addindent, newl)
34
35 ################################################################################
36
37 # Ids for menu commands
38 class ID_NEW:
39 PANEL = wxNewId()
40 DIALOG = wxNewId()
41 FRAME = wxNewId()
42 TOOL_BAR = wxNewId()
43 TOOL = wxNewId()
44 MENU_BAR = wxNewId()
45 MENU = wxNewId()
46
47 STATIC_TEXT = wxNewId()
48 TEXT_CTRL = wxNewId()
49
50 BUTTON = wxNewId()
51 BITMAP_BUTTON = wxNewId()
52 RADIO_BUTTON = wxNewId()
53 SPIN_BUTTON = wxNewId()
54
55 STATIC_BOX = wxNewId()
56 CHECK_BOX = wxNewId()
57 RADIO_BOX = wxNewId()
58 COMBO_BOX = wxNewId()
59 LIST_BOX = wxNewId()
60
61 STATIC_LINE = wxNewId()
62 STATIC_BITMAP = wxNewId()
63 CHOICE = wxNewId()
64 SLIDER = wxNewId()
65 GAUGE = wxNewId()
66 SCROLL_BAR = wxNewId()
67 TREE_CTRL = wxNewId()
68 LIST_CTRL = wxNewId()
69 CHECK_LIST = wxNewId()
70 NOTEBOOK = wxNewId()
71 HTML_WINDOW = wxNewId()
72 CALENDAR_CTRL = wxNewId()
73 GENERIC_DIR_CTRL = wxNewId()
74 SPIN_CTRL = wxNewId()
75 UNKNOWN = wxNewId()
76
77 BOX_SIZER = wxNewId()
78 STATIC_BOX_SIZER = wxNewId()
79 GRID_SIZER = wxNewId()
80 FLEX_GRID_SIZER = wxNewId()
81 SPACER = wxNewId()
82 TOOL_BAR = wxNewId()
83 TOOL = wxNewId()
84 MENU = wxNewId()
85 MENU_ITEM = wxNewId()
86 SEPARATOR = wxNewId()
87 LAST = wxNewId()
88
89 class PullDownMenu:
90 ID_EXPAND = wxNewId()
91 ID_COLLAPSE = wxNewId()
92 ID_PASTE_SIBLING = wxNewId()
93
94 def __init__(self, parent):
95 self.ID_DELETE = parent.ID_DELETE
96 EVT_MENU_RANGE(parent, ID_NEW.PANEL, ID_NEW.LAST, parent.OnCreate)
97 EVT_MENU(parent, self.ID_COLLAPSE, parent.OnCollapse)
98 EVT_MENU(parent, self.ID_EXPAND, parent.OnExpand)
99 EVT_MENU(parent, self.ID_PASTE_SIBLING, parent.OnPaste)
100 # We connect to tree, but process in frame
101 EVT_MENU_HIGHLIGHT_ALL(g.tree, parent.OnPullDownHighlight)
102
103 # Mapping from IDs to element names
104 self.createMap = {
105 ID_NEW.PANEL: 'wxPanel',
106 ID_NEW.DIALOG: 'wxDialog',
107 ID_NEW.FRAME: 'wxFrame',
108 ID_NEW.TOOL_BAR: 'wxToolBar',
109 ID_NEW.TOOL: 'tool',
110 ID_NEW.MENU_BAR: 'wxMenuBar',
111 ID_NEW.MENU: 'wxMenu',
112 ID_NEW.MENU_ITEM: 'wxMenuItem',
113 ID_NEW.SEPARATOR: 'separator',
114
115 ID_NEW.STATIC_TEXT: 'wxStaticText',
116 ID_NEW.TEXT_CTRL: 'wxTextCtrl',
117
118 ID_NEW.BUTTON: 'wxButton',
119 ID_NEW.BITMAP_BUTTON: 'wxBitmapButton',
120 ID_NEW.RADIO_BUTTON: 'wxRadioButton',
121 ID_NEW.SPIN_BUTTON: 'wxSpinButton',
122
123 ID_NEW.STATIC_BOX: 'wxStaticBox',
124 ID_NEW.CHECK_BOX: 'wxCheckBox',
125 ID_NEW.RADIO_BOX: 'wxRadioBox',
126 ID_NEW.COMBO_BOX: 'wxComboBox',
127 ID_NEW.LIST_BOX: 'wxListBox',
128
129 ID_NEW.STATIC_LINE: 'wxStaticLine',
130 ID_NEW.STATIC_BITMAP: 'wxStaticBitmap',
131 ID_NEW.CHOICE: 'wxChoice',
132 ID_NEW.SLIDER: 'wxSlider',
133 ID_NEW.GAUGE: 'wxGauge',
134 ID_NEW.SCROLL_BAR: 'wxScrollBar',
135 ID_NEW.TREE_CTRL: 'wxTreeCtrl',
136 ID_NEW.LIST_CTRL: 'wxListCtrl',
137 ID_NEW.CHECK_LIST: 'wxCheckList',
138 ID_NEW.NOTEBOOK: 'wxNotebook',
139 ID_NEW.HTML_WINDOW: 'wxHtmlWindow',
140 ID_NEW.CALENDAR_CTRL: 'wxCalendarCtrl',
141 ID_NEW.GENERIC_DIR_CTRL: 'wxGenericDirCtrl',
142 ID_NEW.SPIN_CTRL: 'wxSpinCtrl',
143
144 ID_NEW.BOX_SIZER: 'wxBoxSizer',
145 ID_NEW.STATIC_BOX_SIZER: 'wxStaticBoxSizer',
146 ID_NEW.GRID_SIZER: 'wxGridSizer',
147 ID_NEW.FLEX_GRID_SIZER: 'wxFlexGridSizer',
148 ID_NEW.SPACER: 'spacer',
149 ID_NEW.UNKNOWN: 'unknown',
150 }
151 self.controls = [
152 ['control', 'Various controls',
153 (ID_NEW.STATIC_TEXT, 'Label', 'Create label'),
154 (ID_NEW.STATIC_BITMAP, 'Bitmap', 'Create bitmap'),
155 (ID_NEW.STATIC_LINE, 'Line', 'Create line'),
156 (ID_NEW.TEXT_CTRL, 'TextBox', 'Create text box'),
157 (ID_NEW.CHOICE, 'Choice', 'Create choice'),
158 (ID_NEW.SLIDER, 'Slider', 'Create slider'),
159 (ID_NEW.GAUGE, 'Gauge', 'Create gauge'),
160 (ID_NEW.SPIN_CTRL, 'SpinCtrl', 'Create spin'),
161 (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'),
162 (ID_NEW.TREE_CTRL, 'TreeCtrl', 'Create tree'),
163 (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list'),
164 (ID_NEW.CHECK_LIST, 'CheckList', 'Create check list'),
165 (ID_NEW.HTML_WINDOW, 'HtmlWindow', 'Create HTML window'),
166 (ID_NEW.CALENDAR_CTRL, 'CalendarCtrl', 'Create calendar control'),
167 (ID_NEW.GENERIC_DIR_CTRL, 'GenericDirCtrl', 'Create generic dir control'),
168 (ID_NEW.UNKNOWN, 'Unknown', 'Create custom control placeholder'),
169 ],
170 ['button', 'Buttons',
171 (ID_NEW.BUTTON, 'Button', 'Create button'),
172 (ID_NEW.BITMAP_BUTTON, 'BitmapButton', 'Create bitmap button'),
173 (ID_NEW.RADIO_BUTTON, 'RadioButton', 'Create radio button'),
174 (ID_NEW.SPIN_BUTTON, 'SpinButton', 'Create spin button'),
175 ],
176 ['box', 'Boxes',
177 (ID_NEW.STATIC_BOX, 'StaticBox', 'Create static box'),
178 (ID_NEW.CHECK_BOX, 'CheckBox', 'Create check box'),
179 (ID_NEW.RADIO_BOX, 'RadioBox', 'Create radio box'),
180 (ID_NEW.COMBO_BOX, 'ComboBox', 'Create combo box'),
181 (ID_NEW.LIST_BOX, 'ListBox', 'Create list box'),
182 ],
183 ['container', 'Containers',
184 (ID_NEW.PANEL, 'Panel', 'Create panel'),
185 (ID_NEW.NOTEBOOK, 'Notebook', 'Create notebook control'),
186 (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'),
187 ],
188 ['sizer', 'Sizers',
189 (ID_NEW.BOX_SIZER, 'BoxSizer', 'Create box sizer'),
190 (ID_NEW.STATIC_BOX_SIZER, 'StaticBoxSizer',
191 'Create static box sizer'),
192 (ID_NEW.GRID_SIZER, 'GridSizer', 'Create grid sizer'),
193 (ID_NEW.FLEX_GRID_SIZER, 'FlexGridSizer',
194 'Create flexgrid sizer'),
195 (ID_NEW.SPACER, 'Spacer', 'Create spacer'),
196 ]
197 ]
198 self.menuControls = [
199 (ID_NEW.MENU, 'Menu', 'Create menu'),
200 (ID_NEW.MENU_ITEM, 'MenuItem', 'Create menu item'),
201 (ID_NEW.SEPARATOR, 'Separator', 'Create separator'),
202 ]
203 self.toolBarControls = [
204 (ID_NEW.TOOL, 'Tool', 'Create tool'),
205 (ID_NEW.SEPARATOR, 'Separator', 'Create separator'),
206 ['control', 'Various controls',
207 (ID_NEW.STATIC_TEXT, 'Label', 'Create label'),
208 (ID_NEW.STATIC_BITMAP, 'Bitmap', 'Create bitmap'),
209 (ID_NEW.STATIC_LINE, 'Line', 'Create line'),
210 (ID_NEW.TEXT_CTRL, 'TextBox', 'Create text box'),
211 (ID_NEW.CHOICE, 'Choice', 'Create choice'),
212 (ID_NEW.SLIDER, 'Slider', 'Create slider'),
213 (ID_NEW.GAUGE, 'Gauge', 'Create gauge'),
214 (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'),
215 (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list control'),
216 (ID_NEW.CHECK_LIST, 'CheckList', 'Create check list'),
217 ],
218 ['button', 'Buttons',
219 (ID_NEW.BUTTON, 'Button', 'Create button'),
220 (ID_NEW.BITMAP_BUTTON, 'BitmapButton', 'Create bitmap button'),
221 (ID_NEW.RADIO_BUTTON, 'RadioButton', 'Create radio button'),
222 (ID_NEW.SPIN_BUTTON, 'SpinButton', 'Create spin button'),
223 ],
224 ['box', 'Boxes',
225 (ID_NEW.STATIC_BOX, 'StaticBox', 'Create static box'),
226 (ID_NEW.CHECK_BOX, 'CheckBox', 'Create check box'),
227 (ID_NEW.RADIO_BOX, 'RadioBox', 'Create radio box'),
228 (ID_NEW.COMBO_BOX, 'ComboBox', 'Create combo box'),
229 (ID_NEW.LIST_BOX, 'ListBox', 'Create list box'),
230 ],
231 ]
232
233 ################################################################################
234
235 # Set menu to list items.
236 # Each menu command is a tuple (id, label, help)
237 # submenus are lists [id, label, help, submenu]
238 # and separators are any other type
239 def SetMenu(m, list):
240 for l in list:
241 if type(l) == types.TupleType:
242 apply(m.Append, l)
243 elif type(l) == types.ListType:
244 subMenu = wxMenu()
245 SetMenu(subMenu, l[2:])
246 m.AppendMenu(wxNewId(), l[0], subMenu, l[1])
247 else: # separator
248 m.AppendSeparator()
249
250 ################################################################################
251
252 class HighLightBox:
253 def __init__(self, pos, size):
254 if size.x == -1: size.x = 0
255 if size.y == -1: size.y = 0
256 w = g.testWin.panel
257 l1 = wxWindow(w, -1, pos, wxSize(size.x, 2))
258 l1.SetBackgroundColour(wxRED)
259 l2 = wxWindow(w, -1, pos, wxSize(2, size.y))
260 l2.SetBackgroundColour(wxRED)
261 l3 = wxWindow(w, -1, wxPoint(pos.x + size.x - 2, pos.y), wxSize(2, size.y))
262 l3.SetBackgroundColour(wxRED)
263 l4 = wxWindow(w, -1, wxPoint(pos.x, pos.y + size.y - 2), wxSize(size.x, 2))
264 l4.SetBackgroundColour(wxRED)
265 self.lines = [l1, l2, l3, l4]
266 # Move highlight to a new position
267 def Replace(self, pos, size):
268 if size.x == -1: size.x = 0
269 if size.y == -1: size.y = 0
270 self.lines[0].SetDimensions(pos.x, pos.y, size.x, 2)
271 self.lines[1].SetDimensions(pos.x, pos.y, 2, size.y)
272 self.lines[2].SetDimensions(pos.x + size.x - 2, pos.y, 2, size.y)
273 self.lines[3].SetDimensions(pos.x, pos.y + size.y - 2, size.x, 2)
274 # Remove it
275 def Remove(self):
276 map(wxWindow.Destroy, self.lines)
277 g.testWin.highLight = None
278
279 ################################################################################
280
281 class XML_Tree(wxTreeCtrl):
282 # Constant to define standart window name
283 stdName = '_XRCED_T_W'
284 def __init__(self, parent, id):
285 wxTreeCtrl.__init__(self, parent, id, style = wxTR_HAS_BUTTONS)
286 self.SetBackgroundColour(wxColour(224, 248, 224))
287 EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
288 # One works on Linux, another on Windows
289 if wxPlatform == '__WXGTK__':
290 EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated)
291 else:
292 EVT_LEFT_DCLICK(self, self.OnDClick)
293 EVT_RIGHT_DOWN(self, self.OnRightDown)
294
295 self.needUpdate = False
296 self.pendingHighLight = None
297 self.ctrl = self.shift = False
298 self.dom = None
299 # Create image list
300 il = wxImageList(16, 16, True)
301 self.rootImage = il.AddIcon(images.getTreeRootIcon())
302 xxxObject.image = il.AddIcon(images.getTreeDefaultIcon())
303 xxxPanel.image = il.AddIcon(images.getTreePanelIcon())
304 xxxDialog.image = il.AddIcon(images.getTreeDialogIcon())
305 xxxFrame.image = il.AddIcon(images.getTreeFrameIcon())
306 xxxMenuBar.image = il.AddIcon(images.getTreeMenuBarIcon())
307 xxxMenu.image = il.AddIcon(images.getTreeMenuIcon())
308 xxxMenuItem.image = il.AddIcon(images.getTreeMenuItemIcon())
309 xxxToolBar.image = il.AddIcon(images.getTreeToolBarIcon())
310 xxxTool.image = il.AddIcon(images.getTreeToolIcon())
311 xxxSeparator.image = il.AddIcon(images.getTreeSeparatorIcon())
312 xxxSizer.imageH = il.AddIcon(images.getTreeSizerHIcon())
313 xxxSizer.imageV = il.AddIcon(images.getTreeSizerVIcon())
314 xxxStaticBoxSizer.imageH = il.AddIcon(images.getTreeStaticBoxSizerHIcon())
315 xxxStaticBoxSizer.imageV = il.AddIcon(images.getTreeStaticBoxSizerVIcon())
316 xxxGridSizer.image = il.AddIcon(images.getTreeSizerGridIcon())
317 xxxFlexGridSizer.image = il.AddIcon(images.getTreeSizerFlexGridIcon())
318 self.il = il
319 self.SetImageList(il)
320
321 def RegisterKeyEvents(self):
322 EVT_KEY_DOWN(self, g.tools.OnKeyDown)
323 EVT_KEY_UP(self, g.tools.OnKeyUp)
324 EVT_ENTER_WINDOW(self, g.tools.OnMouse)
325 EVT_LEAVE_WINDOW(self, g.tools.OnMouse)
326
327 def Unselect(self):
328 self.selection = None
329 wxTreeCtrl.Unselect(self)
330 g.tools.UpdateUI()
331
332 def ExpandAll(self, item):
333 if self.ItemHasChildren(item):
334 self.Expand(item)
335 i, cookie = self.GetFirstChild(item, 0)
336 children = []
337 while i.IsOk():
338 children.append(i)
339 i, cookie = self.GetNextChild(item, cookie)
340 for i in children:
341 self.ExpandAll(i)
342 def CollapseAll(self, item):
343 if self.ItemHasChildren(item):
344 i, cookie = self.GetFirstChild(item, 0)
345 children = []
346 while i.IsOk():
347 children.append(i)
348 i, cookie = self.GetNextChild(item, cookie)
349 for i in children:
350 self.CollapseAll(i)
351 self.Collapse(item)
352
353 # Clear tree
354 def Clear(self):
355 self.DeleteAllItems()
356 # Add minimal structure
357 if self.dom: self.dom.unlink()
358 self.dom = MyDocument()
359 self.dummyNode = self.dom.createComment('dummy node')
360 # Create main node
361 self.mainNode = self.dom.createElement('resource')
362 self.dom.appendChild(self.mainNode)
363 self.rootObj = xxxMainNode(self.dom)
364 self.root = self.AddRoot('XML tree', self.rootImage,
365 data=wxTreeItemData(self.rootObj))
366 self.SetItemHasChildren(self.root)
367 self.Expand(self.root)
368 self.Unselect()
369
370 # Clear old data and set new
371 def SetData(self, dom):
372 self.DeleteAllItems()
373 # Add minimal structure
374 if self.dom: self.dom.unlink()
375 self.dom = dom
376 self.dummyNode = self.dom.createComment('dummy node')
377 # Find 'resource' child, add it's children
378 self.mainNode = dom.documentElement
379 self.rootObj = xxxMainNode(self.dom)
380 self.root = self.AddRoot('XML tree', self.rootImage,
381 data=wxTreeItemData(self.rootObj))
382 self.SetItemHasChildren(self.root)
383 nodes = self.mainNode.childNodes[:]
384 for node in nodes:
385 if IsObject(node):
386 self.AddNode(self.root, None, node)
387 else:
388 self.mainNode.removeChild(node)
389 node.unlink()
390 self.Expand(self.root)
391 self.Unselect()
392
393 # Add tree item for given parent item if node is DOM element node with
394 # 'object' tag. xxxParent is parent xxx object
395 def AddNode(self, itemParent, xxxParent, node):
396 # Set item data to current node
397 try:
398 xxx = MakeXXXFromDOM(xxxParent, node)
399 except:
400 print 'ERROR: MakeXXXFromDom(%s, %s)' % (xxxParent, node)
401 raise
402 treeObj = xxx.treeObject()
403 # Append tree item
404 item = self.AppendItem(itemParent, treeObj.treeName(),
405 image=treeObj.treeImage(),
406 data=wxTreeItemData(xxx))
407 # Try to find children objects
408 if treeObj.hasChildren:
409 nodes = treeObj.element.childNodes[:]
410 for n in nodes:
411 if IsObject(n):
412 self.AddNode(item, treeObj, n)
413 elif n.nodeType != minidom.Node.ELEMENT_NODE:
414 treeObj.element.removeChild(n)
415 n.unlink()
416 # Insert new item at specific position
417 def InsertNode(self, itemParent, parent, elem, nextItem):
418 # Insert in XML tree and wxWin
419 xxx = MakeXXXFromDOM(parent, elem)
420 # If nextItem is None, we append to parent, otherwise insert before it
421 if nextItem.IsOk():
422 node = self.GetPyData(nextItem).element
423 parent.element.insertBefore(elem, node)
424 # Inserting before is difficult, se we insert after or first child
425 index = self.ItemIndex(nextItem)
426 newItem = self.InsertItemBefore(itemParent, index,
427 xxx.treeName(), image=xxx.treeImage())
428 self.SetPyData(newItem, xxx)
429 else:
430 parent.element.appendChild(elem)
431 newItem = self.AppendItem(itemParent, xxx.treeName(), image=xxx.treeImage(),
432 data=wxTreeItemData(xxx))
433 # Add children items
434 if xxx.hasChildren:
435 treeObj = xxx.treeObject()
436 for n in treeObj.element.childNodes:
437 if IsObject(n):
438 self.AddNode(newItem, treeObj, n)
439 return newItem
440
441 # Remove leaf of tree, return it's data object
442 def RemoveLeaf(self, leaf):
443 xxx = self.GetPyData(leaf)
444 node = xxx.element
445 parent = node.parentNode
446 parent.removeChild(node)
447 self.Delete(leaf)
448 # Reset selection object
449 self.selection = None
450 return node
451 # Find position relative to the top-level window
452 def FindNodePos(self, item):
453 # Root at (0,0)
454 if item == g.testWin.item: return wxPoint(0, 0)
455 itemParent = self.GetItemParent(item)
456 # Select NB page
457 obj = self.FindNodeObject(item)
458 if self.GetPyData(itemParent).treeObject().__class__ == xxxNotebook:
459 notebook = self.FindNodeObject(itemParent)
460 # Find position
461 for i in range(notebook.GetPageCount()):
462 if notebook.GetPage(i) == obj:
463 if notebook.GetSelection() != i: notebook.SetSelection(i)
464 break
465 # Find first ancestor which is a wxWindow (not a sizer)
466 winParent = itemParent
467 while self.GetPyData(winParent).isSizer:
468 winParent = self.GetItemParent(winParent)
469 parentPos = self.FindNodePos(winParent)
470 # Position (-1,-1) is really (0,0)
471 pos = obj.GetPosition()
472 if pos == (-1,-1): pos = (0,0)
473 return parentPos + pos
474 # Find window (or sizer) corresponding to a tree item.
475 def FindNodeObject(self, item):
476 testWin = g.testWin
477 # If top-level, return testWin (or panel its panel)
478 if item == testWin.item: return testWin.panel
479 itemParent = self.GetItemParent(item)
480 xxx = self.GetPyData(item).treeObject()
481 parentWin = self.FindNodeObject(itemParent)
482 # Top-level sizer? return window's sizer
483 if xxx.isSizer and isinstance(parentWin, wxWindowPtr):
484 return parentWin.GetSizer()
485 # Otherwise get parent's object and it's child
486 child = parentWin.GetChildren()[self.ItemIndex(item)]
487 # Return window or sizer for sizer items
488 if child.GetClassName() == 'wxSizerItem':
489 if child.IsWindow(): child = child.GetWindow()
490 elif child.IsSizer():
491 child = child.GetSizer()
492 # Test for notebook sizers
493 if isinstance(child, wxNotebookSizerPtr):
494 child = child.GetNotebook()
495 return child
496 def OnSelChanged(self, evt):
497 # Apply changes
498 # !!! problem with wxGTK - GetOldItem is Ok if nothing selected
499 #oldItem = evt.GetOldItem()
500 status = ''
501 oldItem = self.selection
502 if oldItem:
503 xxx = self.GetPyData(oldItem)
504 # If some data was modified, apply changes
505 if g.panel.IsModified():
506 self.Apply(xxx, oldItem)
507 #if conf.autoRefresh:
508 if g.testWin:
509 if g.testWin.highLight:
510 g.testWin.highLight.Remove()
511 self.needUpdate = True
512 status = 'Changes were applied'
513 g.frame.SetStatusText(status)
514 # Generate view
515 self.selection = evt.GetItem()
516 if not self.selection.IsOk():
517 self.selection = None
518 return
519 xxx = self.GetPyData(self.selection)
520 # Update panel
521 g.panel.SetData(xxx)
522 # Update tools
523 g.tools.UpdateUI()
524 # Hightlighting is done in OnIdle
525 self.pendingHighLight = self.selection
526 # Check if item is in testWin subtree
527 def IsHighlatable(self, item):
528 if item == g.testWin.item: return False
529 while item != self.root:
530 item = self.GetItemParent(item)
531 if item == g.testWin.item: return True
532 return False
533 # Highlight selected item
534 def HighLight(self, item):
535 self.pendingHighLight = None
536 # Can highlight only with some top-level windows
537 if not g.testWin or self.GetPyData(g.testWin.item).treeObject().__class__ \
538 not in [xxxDialog, xxxPanel, xxxFrame]:
539 return
540 # If a control from another window is selected, remove highlight
541 if not self.IsHighlatable(item):
542 if g.testWin.highLight: g.testWin.highLight.Remove()
543 return
544 # Get window/sizer object
545 obj, pos = self.FindNodeObject(item), self.FindNodePos(item)
546 size = obj.GetSize()
547 # Highlight
548 # Nagative positions are not working wuite well
549 if g.testWin.highLight:
550 g.testWin.highLight.Replace(pos, size)
551 else:
552 g.testWin.highLight = HighLightBox(pos, size)
553 g.testWin.highLight.item = item
554 def ShowTestWindow(self, item):
555 xxx = self.GetPyData(item)
556 if g.panel.IsModified():
557 self.Apply(xxx, item) # apply changes
558 treeObj = xxx.treeObject()
559 if treeObj.className not in ['wxFrame', 'wxPanel', 'wxDialog',
560 'wxMenuBar', 'wxToolBar']:
561 wxLogMessage('No view for this element (yet)')
562 return
563 # Show item in bold
564 if g.testWin: # Reset old
565 self.SetItemBold(g.testWin.item, False)
566 self.CreateTestWin(item)
567 # Maybe an error occured, so we need to test
568 if g.testWin: self.SetItemBold(g.testWin.item)
569 # Double-click on Linux
570 def OnItemActivated(self, evt):
571 if evt.GetItem() != self.root:
572 self.ShowTestWindow(evt.GetItem())
573 # Double-click on Windows
574 def OnDClick(self, evt):
575 item, flags = self.HitTest(evt.GetPosition())
576 if flags in [wxTREE_HITTEST_ONITEMBUTTON, wxTREE_HITTEST_ONITEMLABEL]:
577 if item != self.root: self.ShowTestWindow(item)
578 else:
579 evt.Skip()
580 # (re)create test window
581 def CreateTestWin(self, item):
582 testWin = g.testWin
583 wxBeginBusyCursor()
584 wxYield()
585 # Create a window with this resource
586 xxx = self.GetPyData(item).treeObject()
587 # Close old window, remember where it was
588 highLight = None
589 if testWin:
590 pos = testWin.GetPosition()
591 if item == testWin.item:
592 # Remember highlight if same top-level window
593 if testWin.highLight:
594 highLight = testWin.highLight.item
595 if xxx.className == 'wxPanel':
596 if testWin.highLight:
597 testWin.pendingHighLight = highLight
598 testWin.highLight.Remove()
599 testWin.panel.Destroy()
600 testWin.panel = None
601 else:
602 testWin.Destroy()
603 testWin = g.testWin = None
604 else:
605 testWin.Destroy()
606 testWin = g.testWin = None
607 else:
608 pos = g.testWinPos
609 # Save in memory FS
610 memFile = MemoryFile('xxx.xrc')
611 # Create partial XML file - faster for big files
612
613 dom = MyDocument()
614 mainNode = dom.createElement('resource')
615 dom.appendChild(mainNode)
616
617 # Remove temporarily from old parent
618 elem = xxx.element
619 # Change window id to _XRCED_T_W. This gives some name for
620 # unnamed windows, and for named gives the possibility to
621 # write sawfish scripts.
622 if not xxx.name:
623 name = 'noname'
624 else:
625 name = xxx.name
626 elem.setAttribute('name', self.stdName)
627 parent = elem.parentNode
628 next = elem.nextSibling
629 parent.replaceChild(self.dummyNode, elem)
630 # Append to new DOM, write it
631 mainNode.appendChild(elem)
632 dom.writexml(memFile, encoding=self.rootObj.params['encoding'].value())
633 # Put back in place
634 mainNode.removeChild(elem)
635 dom.unlink()
636 parent.replaceChild(elem, self.dummyNode)
637 # Remove temporary name or restore changed
638 if not xxx.name:
639 elem.removeAttribute('name')
640 else:
641 elem.setAttribute('name', xxx.name)
642 memFile.close() # write to wxMemoryFS
643 res = wxXmlResource('', g.xmlFlags)
644 res.Load('memory:xxx.xrc')
645 if xxx.__class__ == xxxFrame:
646 # Frame can't have many children,
647 # but it's first child possibly can...
648 child = self.GetFirstChild(item, 0)[0]
649 if child.IsOk() and self.GetPyData(child).__class__ == xxxPanel:
650 # Clean-up before recursive call or error
651 wxMemoryFSHandler_RemoveFile('xxx.xrc')
652 wxEndBusyCursor()
653 self.CreateTestWin(child)
654 return
655 # This currently works under GTK, but not under MSW
656 testWin = g.testWin = wxPreFrame()
657 res.LoadOnFrame(testWin, g.frame, self.stdName)
658 # Create status bar
659 testWin.CreateStatusBar()
660 testWin.panel = testWin
661 testWin.SetPosition(pos)
662 testWin.Show(True)
663 elif xxx.__class__ == xxxPanel:
664 # Create new frame
665 if not testWin:
666 testWin = g.testWin = wxFrame(g.frame, -1, 'Panel: ' + name, pos=pos)
667 testWin.panel = res.LoadPanel(testWin, self.stdName)
668 testWin.SetClientSize(testWin.panel.GetSize())
669 testWin.Show(True)
670 elif xxx.__class__ == xxxDialog:
671 testWin = g.testWin = res.LoadDialog(None, self.stdName)
672 testWin.panel = testWin
673 testWin.Layout()
674 testWin.SetPosition(pos)
675 testWin.Show(True)
676 elif xxx.__class__ == xxxMenuBar:
677 testWin = g.testWin = wxFrame(g.frame, -1, 'MenuBar: ' + name, pos=pos)
678 testWin.panel = None
679 # Set status bar to display help
680 testWin.CreateStatusBar()
681 testWin.menuBar = res.LoadMenuBar(self.stdName)
682 testWin.SetMenuBar(testWin.menuBar)
683 testWin.Show(True)
684 elif xxx.__class__ == xxxToolBar:
685 testWin = g.testWin = wxFrame(g.frame, -1, 'ToolBar: ' + name, pos=pos)
686 testWin.panel = None
687 # Set status bar to display help
688 testWin.CreateStatusBar()
689 testWin.toolBar = res.LoadToolBar(testWin, self.stdName)
690 testWin.SetToolBar(testWin.toolBar)
691 testWin.Show(True)
692 wxMemoryFSHandler_RemoveFile('xxx.xrc')
693 testWin.item = item
694 EVT_CLOSE(testWin, self.OnCloseTestWin)
695 EVT_BUTTON(testWin, wxID_OK, self.OnCloseTestWin)
696 EVT_BUTTON(testWin, wxID_CANCEL, self.OnCloseTestWin)
697 testWin.highLight = None
698 if highLight and not self.pendingHighLight:
699 self.HighLight(highLight)
700 wxEndBusyCursor()
701
702 def OnCloseTestWin(self, evt):
703 self.SetItemBold(g.testWin.item, False)
704 g.testWinPos = g.testWin.GetPosition()
705 g.testWin.Destroy()
706 g.testWin = None
707
708 # Return item index in parent
709 def ItemIndex(self, item):
710 n = 0 # index of sibling
711 prev = self.GetPrevSibling(item)
712 while prev.IsOk():
713 prev = self.GetPrevSibling(prev)
714 n += 1
715 return n
716
717 # Full tree index of an item - list of positions
718 def ItemFullIndex(self, item):
719 if not item.IsOk(): return None
720 l = []
721 while item != self.root:
722 l.insert(0, self.ItemIndex(item))
723 item = self.GetItemParent(item)
724 return l
725 # Get item position from full index
726 def ItemAtFullIndex(self, index):
727 if index is None: return wxTreeItemId()
728 item = self.root
729 for i in index:
730 item = self.GetFirstChild(item, 0)[0]
731 for k in range(i): item = self.GetNextSibling(item)
732 return item
733
734 # True if next item should be inserted after current (vs. appended to it)
735 def NeedInsert(self, item):
736 xxx = self.GetPyData(item)
737 if item == self.root: return False # root item
738 if xxx.hasChildren and not self.GetChildrenCount(item, False):
739 return False
740 return not (self.IsExpanded(item) and self.GetChildrenCount(item, False))
741
742 # Pull-down
743 def OnRightDown(self, evt):
744 pullDownMenu = g.pullDownMenu
745 # select this item
746 pt = evt.GetPosition();
747 item, flags = self.HitTest(pt)
748 if item.Ok() and flags & wxTREE_HITTEST_ONITEM:
749 self.SelectItem(item)
750
751 # Setup menu
752 menu = wxMenu()
753
754 item = self.selection
755 if not item:
756 menu.Append(g.pullDownMenu.ID_EXPAND, 'Expand', 'Expand tree')
757 menu.Append(g.pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse tree')
758 else:
759 # self.ctrl = evt.ControlDown() # save Ctrl state
760 # self.shift = evt.ShiftDown() # and Shift too
761 m = wxMenu() # create menu
762 if self.ctrl:
763 needInsert = True
764 else:
765 needInsert = self.NeedInsert(item)
766 if item == self.root or needInsert and self.GetItemParent(item) == self.root:
767 m.Append(ID_NEW.PANEL, 'Panel', 'Create panel')
768 m.Append(ID_NEW.DIALOG, 'Dialog', 'Create dialog')
769 m.Append(ID_NEW.FRAME, 'Frame', 'Create frame')
770 m.AppendSeparator()
771 m.Append(ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar')
772 m.Append(ID_NEW.MENU_BAR, 'MenuBar', 'Create menubar')
773 m.Append(ID_NEW.MENU, 'Menu', 'Create menu')
774 else:
775 xxx = self.GetPyData(item).treeObject()
776 # Check parent for possible child nodes if inserting sibling
777 if needInsert: xxx = xxx.parent
778 if xxx.__class__ == xxxMenuBar:
779 m.Append(ID_NEW.MENU, 'Menu', 'Create menu')
780 elif xxx.__class__ in [xxxToolBar, xxxTool] or \
781 xxx.__class__ == xxxSeparator and xxx.parent.__class__ == xxxToolBar:
782 SetMenu(m, pullDownMenu.toolBarControls)
783 elif xxx.__class__ in [xxxMenu, xxxMenuItem]:
784 SetMenu(m, pullDownMenu.menuControls)
785 else:
786 SetMenu(m, pullDownMenu.controls)
787 if xxx.__class__ == xxxNotebook:
788 m.Enable(m.FindItem('sizer'), False)
789 elif not (xxx.isSizer or xxx.parent and xxx.parent.isSizer):
790 m.Enable(ID_NEW.SPACER, False)
791 # Select correct label for create menu
792 if not needInsert:
793 if self.shift:
794 menu.AppendMenu(wxNewId(), 'Insert Child', m,
795 'Create child object as the first child')
796 else:
797 menu.AppendMenu(wxNewId(), 'Append Child', m,
798 'Create child object as the last child')
799 else:
800 if self.shift:
801 menu.AppendMenu(wxNewId(), 'Create Sibling', m,
802 'Create sibling before selected object')
803 else:
804 menu.AppendMenu(wxNewId(), 'Create Sibling', m,
805 'Create sibling after selected object')
806 menu.AppendSeparator()
807 # Not using standart IDs because we don't want to show shortcuts
808 menu.Append(wxID_CUT, 'Cut', 'Cut to the clipboard')
809 menu.Append(wxID_COPY, 'Copy', 'Copy to the clipboard')
810 if self.ctrl and item != self.root:
811 menu.Append(pullDownMenu.ID_PASTE_SIBLING, 'Paste Sibling',
812 'Paste from the clipboard as a sibling')
813 else:
814 menu.Append(wxID_PASTE, 'Paste', 'Paste from the clipboard')
815 menu.Append(pullDownMenu.ID_DELETE,
816 'Delete', 'Delete object')
817 if self.ItemHasChildren(item):
818 menu.AppendSeparator()
819 menu.Append(pullDownMenu.ID_EXPAND, 'Expand', 'Expand subtree')
820 menu.Append(pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse subtree')
821 self.PopupMenu(menu, evt.GetPosition())
822 menu.Destroy()
823
824 # Apply changes
825 def Apply(self, xxx, item):
826 g.panel.Apply()
827 # Update tree view
828 xxx = xxx.treeObject()
829 if xxx.hasName and self.GetItemText(item) != xxx.name:
830 self.SetItemText(item, xxx.treeName())
831 # Item width may have changed
832 # !!! Tric to update tree width (wxGTK, ??)
833 self.SetIndent(self.GetIndent())
834 # Change tree icon for sizers
835 if isinstance(xxx, xxxBoxSizer):
836 self.SetItemImage(item, xxx.treeImage())
837 # Set global modified state
838 g.frame.modified = True
839