2 # Purpose: XRC editor, main module
3 # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
7 from wxPython
.wx
import *
8 from wxPython
.xrc
import *
9 from wxPython
.html
import *
10 import wxPython
.lib
.wxpTag
11 from xml
.dom
import minidom
19 faceColour
= wxSystemSettings_GetSystemColour(wxSYS_COLOUR_3DFACE
)
20 # Stange wxHtmlWindow behavior: when bgcolor is exact, it turns white
21 bgcolor
= (faceColour
.Red()-1, faceColour
.Green()-1, faceColour
.Blue()-1)
22 htmlHeader
= '<html><body bgcolor="#%02x%02x%02x">\n' % bgcolor
23 htmlFooter
= '</body></html>\n'
32 testWinPos
= wxDefaultPosition
34 # 1 adds CMD command to Help menu
41 # Set menu to list items.
42 # Each menu command is a tuple (id, label, help)
43 # submenus are lists [id, label, help, submenu]
44 # and separators are any other type
47 if type(l
) == types
.TupleType
:
49 elif type(l
) == types
.ListType
:
51 SetMenu(subMenu
, l
[2:])
52 m
.AppendMenu(wxNewId(), l
[0], subMenu
, l
[1])
56 ################################################################################
58 # Properties panel containing notebook
59 class Panel(wxNotebook
):
60 def __init__(self
, parent
, id = -1):
61 wxNotebook
.__init
__(self
, parent
, id, style
=wxNB_BOTTOM
)
62 #self.SetBackgroundColour(wxColour(bgcolor))
63 sys
.modules
['params'].panel
= self
64 self
.page1
= HtmlPage(self
)
65 self
.AddPage(self
.page1
, 'Properties')
67 def SetData(self
, xxx
):
68 self
.page1
.SetPageData(xxx
)
69 # Replace/remove style page
73 if xxx
and xxx
.treeObject().hasStyle
:
74 self
.page2
= StylePage(self
, xxx
.treeObject())
75 self
.AddPage(self
.page2
, 'Style')
84 # If some parameter on some page has changed
86 return self
.page1
.IsModified() or self
.page2
and self
.page2
.IsModified()
87 def SetModified(self
, value
):
88 self
.page1
.SetModified(value
)
90 self
.page2
.SetModified(value
)
92 ################################################################################
94 # General class for notebook pages
97 # Register event handlers
98 for id in paramIDs
.values():
99 EVT_CHECKBOX(self
, id, self
.OnCheckParams
)
100 def OnCheckParams(self
, evt
):
101 selected
= tree
.GetSelection()
102 xxx
= tree
.GetPyData(selected
)
103 winName
= evt
.GetEventObject().GetName()
105 if winName
[0] == '_':
109 if xxx
.hasChild
: xxx
= xxx
.child
113 w
= self
.FindWindowByName('_data_' + param
)
115 w
= self
.FindWindowByName('data_' + param
)
118 # Ad new text node in order of allParams
119 w
.SetValue('') # set empty (default) value
120 # For font element, we have to create another object
123 textElem
= tree
.dom
.createElement('font')
124 font
= xxxFont(xxx
, textElem
)
125 xxx
.params
['font'] = font
127 textElem
= tree
.dom
.createElement(param
)
128 textNode
= tree
.dom
.createTextNode('')
129 textElem
.appendChild(textNode
)
130 xxx
.params
[param
] = textNode
131 # Find place to put new element: first present element after param
133 paramStyles
= xxx
.allParams
+ xxx
.styles
134 for p
in paramStyles
[paramStyles
.index(param
) + 1:]:
135 # Content params don't have same type
136 if xxx
.params
.has_key(p
) and p
!= 'content':
140 nextTextElem
= xxx
.params
[p
].parentNode
141 elem
.insertBefore(textElem
, nextTextElem
)
143 elem
.appendChild(textElem
)
145 # Remove parameter element and following text node
146 textElem
= xxx
.params
[param
].parentNode
147 newline
= textElem
.nextSibling
148 if newline
and newline
.nodeType
== minidom
.Node
.TEXT_NODE
:
149 elem
.removeChild(newline
)
150 elem
.removeChild(textElem
)
151 del xxx
.params
[param
]
153 w
.Enable(evt
.IsChecked())
155 self
.SetModified(true
)
158 ################################################################################
160 # Properties panel notebook page
161 class HtmlPage(wxHtmlWindow
, ParamPage
):
162 def __init__(self
, parent
, id = -1):
163 wxHtmlWindow
.__init
__(self
, parent
, id)
164 ParamPage
.__init
__(self
)
166 if wxGetOsVersion()[1] == 1:
167 self
.SetFonts('', '', [8, 10, 12, 14, 16, 19, 24])
169 self
.SetFonts("", "", [7, 8, 10, 12, 16, 22, 30])
170 self
.modified
= false
172 self
.SetPage(htmlHeader
+ 'select a tree item on the left' + htmlFooter
)
173 def SetPageData(self
, xxx
):
175 self
.SetPage(htmlHeader
+ 'this item has no properties' + htmlFooter
)
177 self
.SetPage(htmlHeader
+ xxx
.generateHtml() + htmlFooter
)
178 # Set values, checkboxes to false, disable defaults
179 if xxx
.hasChild
: prefix
= '_'
181 for param
in xxx
.allParams
:
182 if xxx
.params
.has_key(param
):
183 if param
== 'content':
185 for text
in xxx
.params
[param
]:
186 value
.append(str(text
.data
)) # convert from unicode
188 value
= xxx
.params
[param
].data
189 self
.FindWindowByName(prefix
+ 'data_' + param
).SetValue(value
)
190 if not param
in xxx
.required
:
191 self
.FindWindowByName(prefix
+ 'check_' + param
).SetValue(true
)
193 self
.FindWindowByName(prefix
+ 'data_' + param
).Enable(false
)
194 # Same for the child of sizeritem
197 for param
in xxx
.allParams
:
198 if xxx
.params
.has_key(param
):
199 if param
== 'content':
201 for text
in xxx
.params
[param
]:
202 value
.append(str(text
.data
)) # convert from unicode
204 value
= xxx
.params
[param
].data
205 self
.FindWindowByName('data_' + param
).SetValue(value
)
206 if not param
in xxx
.required
:
207 self
.FindWindowByName('check_' + param
).SetValue(true
)
209 self
.FindWindowByName('data_' + param
).Enable(false
)
210 # If some parameter has changed
211 def IsModified(self
):
213 def SetModified(self
, value
):
214 self
.modified
= value
216 ################################################################################
218 # Style notebook page
219 class StylePage(wxPanel
, ParamPage
):
220 def __init__(self
, parent
, xxx
):
221 wxPanel
.__init
__(self
, parent
, -1)
222 ParamPage
.__init
__(self
)
223 if wxGetOsVersion()[1] == 1:
224 self
.SetFont(wxFont(12, wxDEFAULT
, wxNORMAL
, wxNORMAL
))
226 self
.SetFont(wxFont(10, wxDEFAULT
, wxNORMAL
, wxNORMAL
))
227 topSizer
= wxBoxSizer(wxVERTICAL
)
228 sizer
= wxFlexGridSizer(len(xxx
.styles
), 2, 0, 1)
229 self
.controls
= {} # save python objects
230 for param
in xxx
.styles
:
231 present
= param
in xxx
.params
.keys()
232 check
= wxCheckBox(self
, paramIDs
[param
],
233 param
+ ':', name
= 'check_' + param
)
234 check
.SetValue(present
)
235 control
= paramDict
[param
](self
, -1, '', (-1, -1),
238 control
.SetValue(xxx
.params
[param
].data
)
241 control
.Enable(present
)
242 sizer
.AddMany([ (check
, 0, 0),
244 self
.controls
[param
] = control
245 topSizer
.Add(sizer
, 1, wxALL
, 5)
246 self
.SetAutoLayout(true
)
247 self
.SetSizer(topSizer
)
249 self
.modified
= false
251 # If some parameter has changed
252 def IsModified(self
):
254 def SetModified(self
, value
):
255 self
.modified
= value
257 ################################################################################
260 def __init__(self
, pos
, size
):
262 l1
= wxWindow(w
, -1, pos
, wxSize(size
.x
, 2))
263 l1
.SetBackgroundColour(wxRED
)
264 l2
= wxWindow(w
, -1, pos
, wxSize(2, size
.y
))
265 l2
.SetBackgroundColour(wxRED
)
266 l3
= wxWindow(w
, -1, wxPoint(pos
.x
+ size
.x
- 2, pos
.y
), wxSize(2, size
.y
))
267 l3
.SetBackgroundColour(wxRED
)
268 l4
= wxWindow(w
, -1, wxPoint(pos
.x
, pos
.y
+ size
.y
- 2), wxSize(size
.x
, 2))
269 l4
.SetBackgroundColour(wxRED
)
270 self
.lines
= [l1
, l2
, l3
, l4
]
271 # Move highlight to a new position
272 def Replace(self
, pos
, size
):
273 self
.lines
[0].SetDimensions(pos
.x
, pos
.y
, size
.x
, 2, wxSIZE_ALLOW_MINUS_ONE
)
274 self
.lines
[1].SetDimensions(pos
.x
, pos
.y
, 2, size
.y
, wxSIZE_ALLOW_MINUS_ONE
)
275 self
.lines
[2].SetDimensions(pos
.x
+ size
.x
- 2, pos
.y
, 2, size
.y
,
276 wxSIZE_ALLOW_MINUS_ONE
)
277 self
.lines
[3].SetDimensions(pos
.x
, pos
.y
+ size
.y
- 2, size
.x
, 2,
278 wxSIZE_ALLOW_MINUS_ONE
)
281 map(wxWindow
.Destroy
, self
.lines
)
282 testWin
.highLight
= None
284 ################################################################################
287 def __init__(self
, name
):
290 def write(self
, data
):
291 self
.buffer = self
.buffer + data
.encode()
293 f
= open(self
.name
, 'w')
296 # !!! memory FS will work someday
297 #self.file = wxMemoryFSHandler_AddFile(self.name, self.buffer)
299 class XML_Tree(wxTreeCtrl
):
300 def __init__(self
, parent
, id):
301 wxTreeCtrl
.__init
__(self
, parent
, id,
302 style
=wxTR_HAS_BUTTONS | wxTR_LINES_AT_ROOT
)
303 self
.SetBackgroundColour(wxColour(224, 248, 224))
304 EVT_TREE_SEL_CHANGED(self
, self
.GetId(), self
.OnSelChanged
)
305 EVT_TREE_ITEM_ACTIVATED(self
, self
.GetId(), self
.OnItemActivated
)
306 EVT_RIGHT_DOWN(self
, self
.OnRightDown
)
307 self
.needUpdate
= false
308 self
.pendingHighLight
= None
312 il
= wxImageList(16, 16, true
)
313 self
.rootImage
= il
.AddIcon(wxIconFromXPMData(images
.getTreeRootData()))
314 xxxObject
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeDefaultData()))
315 xxxPanel
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreePanelData()))
316 xxxDialog
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeDialogData()))
317 xxxFrame
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeFrameData()))
318 xxxMenuBar
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeMenuBarData()))
319 xxxMenu
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeMenuData()))
320 xxxSizer
.imageH
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerHData()))
321 xxxSizer
.imageV
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerVData()))
322 xxxStaticBoxSizer
.imageH
= il
.AddIcon(wxIconFromXPMData(images
.getTreeStaticBoxSizerHData()))
323 xxxStaticBoxSizer
.imageV
= il
.AddIcon(wxIconFromXPMData(images
.getTreeStaticBoxSizerVData()))
324 xxxGridSizer
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerGridData()))
325 xxxFlexGridSizer
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerFlexGridData()))
327 self
.SetImageList(il
)
329 # !!! temporary solution for GetOldItem problem
331 self
.selection
= wxTreeItemId()
332 wxTreeCtrl
.Unselect(self
)
333 def GetSelection(self
):
334 return self
.selection
336 def ExpandAll(self
, item
):
337 if self
.ItemHasChildren(item
):
339 i
, cookie
= self
.GetFirstChild(item
, 0)
343 i
, cookie
= self
.GetNextChild(item
, cookie
)
347 def SetData(self
, dom
):
349 # Find 'resource' child, add it's children
350 self
.mainNode
= dom
.getElementsByTagName('resource')[0]
351 nodes
= self
.mainNode
.childNodes
[:]
354 self
.AddNode(self
.GetRootItem(), None, node
)
356 self
.mainNode
.removeChild(node
)
360 # Add tree item for given parent item if node is DOM element node with
361 # 'object' tag. xxxParent is parent xxx object
362 def AddNode(self
, itemParent
, xxxParent
, node
):
363 # Set item data to current node
364 xxx
= MakeXXXFromDOM(xxxParent
, node
)
365 treeObj
= xxx
.treeObject()
367 item
= self
.AppendItem(itemParent
, treeObj
.treeName(),
368 image
=treeObj
.treeImage(),
369 data
=wxTreeItemData(xxx
))
370 # Try to find children objects
371 if treeObj
.hasChildren
:
372 nodes
= treeObj
.element
.childNodes
[:]
375 self
.AddNode(item
, treeObj
, n
)
376 elif n
.nodeType
!= minidom
.Node
.ELEMENT_NODE
:
377 treeObj
.element
.removeChild(n
)
381 # Remove leaf of tree, return it's data object
382 def RemoveLeaf(self
, leaf
):
383 xxx
= self
.GetPyData(leaf
)
385 parent
= node
.parentNode
386 parent
.removeChild(node
)
389 #if testWin and self.GetItemAncestor(leaf) == testWin.item:
390 # if testWin.highLight:
391 # testWin.highLight.Remove()
392 # self.needUpdate = true
395 # Find position relative to the top-level window
396 def FindNodePos(self
, item
):
397 itemParent
= self
.GetItemParent(item
)
398 if itemParent
== self
.GetRootItem(): return wxPoint(0, 0)
399 obj
= self
.FindNodeObject(item
)
400 # Find first ancestor which is a wxWindow (not a sizer)
401 winParent
= itemParent
402 while self
.GetPyData(winParent
).isSizer
:
403 winParent
= self
.GetItemParent(winParent
)
404 parentPos
= self
.FindNodePos(winParent
)
405 return parentPos
+ obj
.GetPosition()
407 # Find window (or sizer) corresponding to a tree item.
408 def FindNodeObject(self
, item
):
409 itemParent
= self
.GetItemParent(item
)
410 # If top-level, return testWin (or panel if wxFrame)
411 if itemParent
== self
.GetRootItem(): return testWin
.panel
412 xxx
= self
.GetPyData(item
).treeObject()
413 parentWin
= self
.FindNodeObject(itemParent
)
414 # Top-level sizer? return window's sizer
415 if xxx
.isSizer
and isinstance(parentWin
, wxWindowPtr
):
416 return parentWin
.GetSizer()
417 # Otherwise get parent's object and it's child
418 n
= 0 # index of sibling
419 prev
= self
.GetPrevSibling(item
)
421 prev
= self
.GetPrevSibling(prev
)
423 child
= parentWin
.GetChildren()[n
]
424 # Return window or sizer for sizer items
425 if child
.GetClassName() == 'wxSizerItem':
426 if child
.IsWindow(): child
= child
.GetWindow()
427 elif child
.IsSizer():
428 child
= child
.GetSizer()
429 # Test for notebook sizers
430 if isinstance(child
, wxNotebookSizerPtr
):
431 child
= child
.GetNotebook()
434 def OnSelChanged(self
, evt
):
436 # !!! problem with wxGTK
437 #oldItem = evt.GetOldItem()
438 oldItem
= self
.selection
440 xxx
= self
.GetPyData(oldItem
)
441 # If some data was modified, apply changes
443 if panel
.IsModified():
444 self
.Apply(xxx
, oldItem
)
445 #if conf.autoRefresh:
446 if testWin
and testWin
.highLight
:
447 testWin
.highLight
.Remove()
448 self
.needUpdate
= true
451 self
.selection
= item
# !!! fix
452 xxx
= self
.GetPyData(item
)
456 if not xxx
and testWin
and testWin
.highLight
:
457 testWin
.highLight
.Remove()
460 panel
.SetModified(false
)
461 # Hightlighting is done in OnIdle
462 tree
.pendingHighLight
= item
464 # Find top-level parent
465 def GetItemAncestor(self
, item
):
466 while self
.GetItemParent(item
) != self
.GetRootItem():
467 item
= self
.GetItemParent(item
)
470 # Highlight selected item
471 def HighLight(self
, item
):
472 self
.pendingHighLight
= None
473 if not testWin
or self
.GetPyData(testWin
.item
).className \
474 not in ['wxDialog', 'wxPanel', 'wxFrame']:
476 # Top-level does not have highlight
477 if item
== testWin
.item
:
478 if testWin
.highLight
: testWin
.highLight
.Remove()
480 # If a control from another window is selected, remove highlight
481 if self
.GetItemAncestor(item
) != testWin
.item
and testWin
.highLight
:
482 testWin
.highLight
.Remove()
484 # Get window/sizer object
485 obj
, pos
= self
.FindNodeObject(item
), self
.FindNodePos(item
)
487 # For notebook, select item's page.
488 # For children of page, nothing happens (too much work)
489 if isinstance(self
.GetPyData(item
).parent
, xxxNotebook
):
490 notebook
= self
.FindNodeObject(self
.GetItemParent(item
))
493 prev
= self
.GetPrevSibling(item
)
496 prev
= self
.GetPrevSibling(prev
)
497 notebook
.SetSelection(n
)
499 try: # finally I use exceptions
500 testWin
.highLight
.Replace(pos
, size
)
501 except AttributeError:
502 testWin
.highLight
= HightLightBox(pos
, size
)
503 testWin
.highLight
.item
= item
506 def OnItemActivated(self
, evt
):
508 xxx
= self
.GetPyData(item
)
509 if not xxx
: return # if root selected, do nothing
510 if panel
.IsModified():
511 self
.Apply(xxx
, item
) # apply changes
512 self
.CreateTestWin(item
)
514 # (re)create test window
515 def CreateTestWin(self
, node
):
517 # Create a window with this resource
518 xxx
= self
.GetPyData(node
).treeObject()
519 if not xxx
: return # if root selected, do nothing
520 # If noname element, display error
521 if not xxx
.hasName
or not xxx
.name
:
522 wxLogError("Can't display a noname element")
524 # Close old window, remember where it was
527 pos
= testWin
.GetPosition()
528 if node
== testWin
.item
:
529 # Remember highlight if same top-level window
530 if testWin
.highLight
:
531 highLight
= testWin
.highLight
.item
532 # !!! if 0 is removed, refresh is broken (notebook not deleted?)
533 if 0 and xxx
.className
== 'wxPanel':
534 if testWin
.highLight
:
535 testWin
.pendingHighLight
= highLight
536 testWin
.highLight
.Remove()
537 testWin
.panel
.Destroy()
547 # Save in temporary file before activating
548 memFile
= MemoryFile(tempfile
.mktemp('xrc'))
549 #memFile = MemoryFile('core.xrc') # to write debug file
550 # Create partial XML file - faster for big files
552 dom
= minidom
.Document()
553 mainNode
= dom
.createElement('resource')
554 dom
.appendChild(mainNode
)
556 # Remove temporarily from old parent
558 parent
= elem
.parentNode
559 next
= elem
.nextSibling
560 parent
.replaceChild(self
.dummyNode
, elem
)
561 # Append to new DOM, write it
562 mainNode
.appendChild(elem
)
563 dom
.writexml(memFile
)
565 mainNode
.removeChild(elem
)
567 parent
.replaceChild(elem
, self
.dummyNode
)
569 memFile
.close() # write to wxMemoryFS
570 res
= wxXmlResource('')
571 res
.Load(memFile
.name
)
572 if xxx
.className
== 'wxFrame':
574 testWin
= wxPreFrame()
575 res
.LoadFrame(testWin
, frame
, xxx
.name
)
576 testWin
.panel
= testWin
577 testWin
.SetPosition(pos
)
579 elif xxx
.className
== 'wxPanel':
582 testWin
= wxFrame(frame
, -1, 'Panel: ' + xxx
.name
, pos
=pos
)
583 testWin
.panel
= res
.LoadPanel(testWin
, xxx
.name
)
584 testWin
.SetSize(testWin
.panel
.GetSize())
586 elif xxx
.className
== 'wxDialog':
588 testWin
= res
.LoadDialog(None, xxx
.name
)
589 testWin
.panel
= testWin
590 testWin
.SetPosition(pos
)
592 elif xxx
.className
== 'wxMenuBar':
593 testWin
= wxFrame(frame
, -1, 'MenuBar: ' + xxx
.name
, pos
=pos
)
594 # Set status bar to display help
595 testWin
.CreateStatusBar()
596 testWin
.menuBar
= res
.LoadMenuBar(xxx
.name
)
597 testWin
.SetMenuBar(testWin
.menuBar
)
600 wxLogMessage('No view for this element yet')
602 os
.unlink(memFile
.name
) # remove tmp file
604 testWin
.Connect(testWin
.GetId(), -1, wxEVT_CLOSE_WINDOW
, self
.OnCloseTestWin
)
605 testWin
.highLight
= None
606 if highLight
and not tree
.pendingHighLight
:
607 self
.HighLight(highLight
)
609 def OnCloseTestWin(self
, evt
):
610 global testWin
, testWinPos
611 testWinPos
= testWin
.GetPosition()
616 # True if next item should be inserted after current (vs. appended to it)
617 def NeedInsert(self
, item
):
618 xxx
= self
.GetPyData(item
)
619 if not xxx
: return false
# root item
620 if self
.ctrl
: return true
# if Ctrl pressed, always insert
621 if xxx
.hasChildren
and not self
.ItemHasChildren(item
):
623 return not (self
.IsExpanded(item
) and self
.ItemHasChildren(item
))
626 def OnRightDown(self
, evt
):
630 item
= self
.GetSelection()
632 menu
.Append(pullDownMenu
.ID_EXPAND
, 'Expand', 'Expand tree')
634 self
.ctrl
= evt
.ControlDown() # save Ctrl state
635 m
= wxMenu() # create menu
636 if item
!= self
.GetRootItem(): needInsert
= self
.NeedInsert(item
)
637 if item
== self
.GetRootItem() or \
638 self
.GetItemParent(item
) == self
.GetRootItem() and needInsert
:
639 m
.Append(pullDownMenu
.ID_NEW_PANEL
, 'Panel', 'Create panel')
640 m
.Append(pullDownMenu
.ID_NEW_DIALOG
, 'Dialog', 'Create dialog')
641 m
.Append(pullDownMenu
.ID_NEW_FRAME
, 'Frame', 'Create frame')
643 m
.Append(pullDownMenu
.ID_NEW_MENU_BAR
, 'MenuBar', 'Create menu bar')
644 m
.Append(pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu')
646 xxx
= self
.GetPyData(item
)
647 if xxx
.__class
__ == xxxMenuBar
:
648 m
.Append(pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu')
649 elif xxx
.__class
__ in [xxxMenu
, xxxMenuItem
]:
650 SetMenu(m
, pullDownMenu
.menuControls
)
652 SetMenu(m
, pullDownMenu
.controls
)
653 if not (xxx
.isSizer
or \
654 xxx
.parent
and xxx
.parent
.isSizer
):
655 m
.Enable(pullDownMenu
.ID_NEW_SPACER
, false
)
656 # Select correct label for create menu
657 if item
== self
.GetRootItem():
658 menu
.AppendMenu(wxNewId(), 'Create', m
, 'Create top-level object')
661 menu
.AppendMenu(wxNewId(), 'Create child', m
,
662 'Create child object')
664 menu
.AppendMenu(wxNewId(), 'Create Sibling', m
,
665 'Create sibling of selected object')
666 menu
.AppendSeparator()
667 menu
.Append(wxID_CUT
, 'Cut', 'Cut to the clipboard')
668 menu
.Append(wxID_COPY
, 'Copy', 'Copy to the clipboard')
669 menu
.Append(wxID_PASTE
, 'Paste', 'Paste from the clipboard')
670 menu
.Append(pullDownMenu
.ID_DELETE
,
671 'Delete', 'Delete object')
672 if item
.IsOk() and self
.ItemHasChildren(item
):
673 menu
.AppendSeparator()
674 menu
.Append(pullDownMenu
.ID_EXPAND
, 'Expand', 'Expand subtree')
675 self
.PopupMenu(menu
, evt
.GetPosition())
680 self
.DeleteAllItems()
681 # Add minimal structure
682 root
= self
.AddRoot('XML tree', self
.rootImage
)
684 if self
.dom
: self
.dom
.unlink()
685 self
.dom
= minidom
.Document()
686 self
.dummyNode
= self
.dom
.createComment('dummy node')
688 self
.mainNode
= self
.dom
.createElement('resource')
689 self
.dom
.appendChild(self
.mainNode
)
692 def Apply(self
, xxx
, item
):
695 if xxx
.undo
: xxx
.undo
.unlink()
696 xxx
.undo
= xxx
.element
.cloneNode(false
)
698 name
= panel
.page1
.FindWindowByName('data_name').GetValue()
701 xxx
.element
.setAttribute('name', name
)
702 self
.SetItemText(item
, xxx
.treeName())
703 if xxx
.hasChild
: prefix
= '_'
705 for param
, data
in xxx
.params
.items():
706 value
= panel
.FindWindowByName(prefix
+ 'data_' + param
).GetValue()
707 if param
== 'content':
708 # If number if items is not the same, recreate children
709 if len(value
) != len(data
):
710 elem
= xxx
.element
.getElementsByTagName('content')[0]
711 for n
in elem
.childNodes
:
715 itemElem
= tree
.dom
.createElement('item')
716 itemText
= tree
.dom
.createTextNode(str)
717 itemElem
.appendChild(itemText
)
718 elem
.appendChild(itemElem
)
719 data
.append(itemText
)
720 xxx
.params
[param
] = data
722 for i
in range(len(value
)):
723 data
[i
].data
= value
[i
]
724 elif param
== 'font':
725 data
.updateXML(value
)
729 self
.Apply(xxx
.child
, item
)
731 # Change tree icon for sizers
732 if isinstance(xxx
, xxxBoxSizer
):
733 self
.SetItemImage(item
, xxx
.treeImage())
734 # Set global modified state
735 frame
.modified
= true
738 ID_NEW_PANEL
= wxNewId()
739 ID_NEW_DIALOG
= wxNewId()
740 ID_NEW_FRAME
= wxNewId()
741 ID_NEW_MENU_BAR
= wxNewId()
742 ID_NEW_MENU
= wxNewId()
744 ID_NEW_STATIC_TEXT
= wxNewId()
745 ID_NEW_TEXT_CTRL
= wxNewId()
747 ID_NEW_BUTTON
= wxNewId()
748 ID_NEW_BITMAP_BUTTON
= wxNewId()
749 ID_NEW_RADIO_BUTTON
= wxNewId()
750 ID_NEW_SPIN_BUTTON
= wxNewId()
752 ID_NEW_STATIC_BOX
= wxNewId()
753 ID_NEW_CHECK_BOX
= wxNewId()
754 ID_NEW_RADIO_BOX
= wxNewId()
755 ID_NEW_COMBO_BOX
= wxNewId()
756 ID_NEW_LIST_BOX
= wxNewId()
758 ID_NEW_STATIC_LINE
= wxNewId()
759 ID_NEW_CHOICE
= wxNewId()
760 ID_NEW_SLIDER
= wxNewId()
761 ID_NEW_GAUGE
= wxNewId()
762 ID_NEW_SCROLL_BAR
= wxNewId()
763 ID_NEW_TREE_CTRL
= wxNewId()
764 ID_NEW_LIST_CTRL
= wxNewId()
765 ID_NEW_CHECK_LIST
= wxNewId()
766 ID_NEW_NOTEBOOK
= wxNewId()
767 ID_NEW_HTML_WINDOW
= wxNewId()
768 ID_NEW_CALENDAR
= wxNewId()
770 ID_NEW_BOX_SIZER
= wxNewId()
771 ID_NEW_STATIC_BOX_SIZER
= wxNewId()
772 ID_NEW_GRID_SIZER
= wxNewId()
773 ID_NEW_FLEX_GRID_SIZER
= wxNewId()
774 ID_NEW_SPACER
= wxNewId()
775 ID_NEW_MENU
= wxNewId()
776 ID_NEW_MENU_ITEM
= wxNewId()
777 ID_NEW_SEPARATOR
= wxNewId()
778 ID_NEW_LAST
= wxNewId()
779 ID_EXPAND
= wxNewId()
781 def __init__(self
, parent
):
782 self
.ID_DELETE
= parent
.ID_DELETE
783 EVT_MENU_RANGE(parent
, self
.ID_NEW_PANEL
,
784 self
.ID_NEW_LAST
, parent
.OnCreate
)
785 EVT_MENU(parent
, self
.ID_EXPAND
, parent
.OnExpand
)
786 # We connect to tree, but process in frame
787 EVT_MENU_HIGHLIGHT_ALL(tree
, parent
.OnPullDownHighlight
)
789 class Frame(wxFrame
):
790 def __init__(self
, size
):
791 wxFrame
.__init
__(self
, None, -1, '', size
=size
)
792 self
.CreateStatusBar()
793 self
.SetIcon(wxIconFromXPMData(images
.getIconData()))
796 menuBar
= wxMenuBar()
799 menu
.Append(wxID_NEW
, '&New\tCtrl-N', 'New file')
800 menu
.Append(wxID_OPEN
, '&Open...\tCtrl-O', 'Open XRC file')
801 menu
.Append(wxID_SAVE
, '&Save\tCtrl-S', 'Save XRC file')
802 menu
.Append(wxID_SAVEAS
, 'Save &As...', 'Save XRC file under different name')
803 menu
.AppendSeparator()
804 menu
.Append(wxID_EXIT
, '&Quit\tCtrl-Q', 'Exit application')
805 menuBar
.Append(menu
, '&File')
808 menu
.Append(wxID_UNDO
, '&Undo\tCtrl-Z', 'Undo')
809 menu
.Append(wxID_REDO
, '&Redo\tCtrl-R', 'Redo')
810 menu
.AppendSeparator()
811 menu
.Append(wxID_CUT
, 'Cut\tCtrl-X', 'Cut to the clipboard')
812 menu
.Append(wxID_COPY
, '&Copy\tCtrl-C', 'Copy to the clipboard')
813 menu
.Append(wxID_PASTE
, '&Paste\tCtrl-V', 'Paste from the clipboard')
814 self
.ID_DELETE
= wxNewId()
815 menu
.Append(self
.ID_DELETE
, '&Delete\tCtrl-D', 'Delete object')
816 menuBar
.Append(menu
, '&Edit')
819 self
.ID_REFRESH
= wxNewId()
820 menu
.Append(self
.ID_REFRESH
, '&Refresh\tCtrl-R', 'Refresh view')
821 self
.ID_AUTO_REFRESH
= wxNewId()
822 menu
.Append(self
.ID_AUTO_REFRESH
, '&Auto-refresh\tCtrl-A',
823 'Toggle auto-refresh mode', true
)
824 menu
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
825 menuBar
.Append(menu
, '&View')
828 menu
.Append(wxID_ABOUT
, 'About...', 'About XCRed')
830 self
.ID_DEBUG_CMD
= wxNewId()
831 menu
.Append(self
.ID_DEBUG_CMD
, 'CMD', 'Python command line')
832 EVT_MENU(self
, self
.ID_DEBUG_CMD
, self
.OnDebugCMD
)
833 menuBar
.Append(menu
, '&Help')
835 self
.menuBar
= menuBar
836 self
.SetMenuBar(menuBar
)
839 tb
= self
.CreateToolBar(wxTB_HORIZONTAL | wxNO_BORDER | wxTB_FLAT
)
840 tb
.SetToolBitmapSize((24, 23))
841 tb
.AddSimpleTool(wxID_NEW
, images
.getNewBitmap(), 'New', 'New file')
842 tb
.AddSimpleTool(wxID_OPEN
, images
.getOpenBitmap(), 'Open', 'Open file')
843 tb
.AddSimpleTool(wxID_SAVE
, images
.getSaveBitmap(), 'Save', 'Save file')
845 tb
.AddSimpleTool(wxID_CUT
, images
.getCutBitmap(), 'Cut', 'Cut')
846 tb
.AddSimpleTool(wxID_COPY
, images
.getCopyBitmap(), 'Copy', 'Copy')
847 tb
.AddSimpleTool(wxID_PASTE
, images
.getPasteBitmap(), 'Paste', 'Paste')
849 tb
.AddSimpleTool(self
.ID_REFRESH
, images
.getRefreshBitmap(),
850 'Refresh', 'Refresh view')
851 tb
.AddSimpleTool(self
.ID_AUTO_REFRESH
, images
.getAutoRefreshBitmap(),
852 'Auto-refresh', 'Toggle auto-refresh mode', true
)
853 tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
858 EVT_MENU(self
, wxID_NEW
, self
.OnNew
)
859 EVT_MENU(self
, wxID_OPEN
, self
.OnOpen
)
860 EVT_MENU(self
, wxID_SAVE
, self
.OnSaveOrSaveAs
)
861 EVT_MENU(self
, wxID_SAVEAS
, self
.OnSaveOrSaveAs
)
862 EVT_MENU(self
, wxID_EXIT
, self
.OnExit
)
864 EVT_MENU(self
, wxID_UNDO
, self
.OnUndo
)
865 EVT_MENU(self
, wxID_REDO
, self
.OnRedo
)
866 EVT_MENU(self
, wxID_CUT
, self
.OnCut
)
867 EVT_MENU(self
, wxID_COPY
, self
.OnCopy
)
868 EVT_MENU(self
, wxID_PASTE
, self
.OnPaste
)
869 EVT_MENU(self
, self
.ID_DELETE
, self
.OnDelete
)
871 EVT_MENU(self
, self
.ID_REFRESH
, self
.OnRefresh
)
872 EVT_MENU(self
, self
.ID_AUTO_REFRESH
, self
.OnAutoRefresh
)
874 EVT_MENU(self
, wxID_ABOUT
, self
.OnAbout
)
877 EVT_UPDATE_UI(self
, wxID_CUT
, self
.OnUpdateUI
)
878 EVT_UPDATE_UI(self
, wxID_COPY
, self
.OnUpdateUI
)
879 EVT_UPDATE_UI(self
, wxID_PASTE
, self
.OnUpdateUI
)
880 EVT_UPDATE_UI(self
, self
.ID_DELETE
, self
.OnUpdateUI
)
883 sizer
= wxBoxSizer(wxVERTICAL
)
884 sizer
.Add(wxStaticLine(self
, -1), 0, wxEXPAND
)
885 splitter
= wxSplitterWindow(self
, -1, style
=wxSP_3DSASH
)
886 splitter
.SetMinimumPaneSize(100)
889 tree
= XML_Tree(splitter
, -1)
890 sys
.modules
['xxx'].tree
= tree
891 # Create panel for parameters
893 panel
= Panel(splitter
)
894 # Set plitter windows
895 splitter
.SplitVertically(tree
, panel
, 200)
896 sizer
.Add(splitter
, 1, wxEXPAND
)
897 self
.SetAutoLayout(true
)
900 # Init pull-down menu data
902 pullDownMenu
= PullDownMenu(self
)
903 # Mapping from IDs to element names
905 pullDownMenu
.ID_NEW_PANEL
: 'wxPanel',
906 pullDownMenu
.ID_NEW_DIALOG
: 'wxDialog',
907 pullDownMenu
.ID_NEW_FRAME
: 'wxFrame',
908 pullDownMenu
.ID_NEW_MENU_BAR
: 'wxMenuBar',
909 pullDownMenu
.ID_NEW_MENU
: 'wxMenu',
911 pullDownMenu
.ID_NEW_STATIC_TEXT
: 'wxStaticText',
912 pullDownMenu
.ID_NEW_TEXT_CTRL
: 'wxTextCtrl',
914 pullDownMenu
.ID_NEW_BUTTON
: 'wxButton',
915 pullDownMenu
.ID_NEW_BITMAP_BUTTON
: 'wxBitmapButton',
916 pullDownMenu
.ID_NEW_RADIO_BUTTON
: 'wxRadioButton',
917 pullDownMenu
.ID_NEW_SPIN_BUTTON
: 'wxSpinButton',
919 pullDownMenu
.ID_NEW_STATIC_BOX
: 'wxStaticBox',
920 pullDownMenu
.ID_NEW_CHECK_BOX
: 'wxCheckBox',
921 pullDownMenu
.ID_NEW_RADIO_BOX
: 'wxRadioBox',
922 pullDownMenu
.ID_NEW_COMBO_BOX
: 'wxComboBox',
923 pullDownMenu
.ID_NEW_LIST_BOX
: 'wxListBox',
925 pullDownMenu
.ID_NEW_STATIC_LINE
: 'wxStaticLine',
926 pullDownMenu
.ID_NEW_CHOICE
: 'wxChoice',
927 pullDownMenu
.ID_NEW_SLIDER
: 'wxSlider',
928 pullDownMenu
.ID_NEW_GAUGE
: 'wxGauge',
929 pullDownMenu
.ID_NEW_SCROLL_BAR
: 'wxScrollBar',
930 pullDownMenu
.ID_NEW_TREE_CTRL
: 'wxTreeCtrl',
931 pullDownMenu
.ID_NEW_LIST_CTRL
: 'wxListCtrl',
932 pullDownMenu
.ID_NEW_CHECK_LIST
: 'wxCheckList',
933 pullDownMenu
.ID_NEW_NOTEBOOK
: 'wxNotebook',
934 pullDownMenu
.ID_NEW_HTML_WINDOW
: 'wxHtmlWindow',
935 pullDownMenu
.ID_NEW_CALENDAR
: 'wxCalendar',
937 pullDownMenu
.ID_NEW_BOX_SIZER
: 'wxBoxSizer',
938 pullDownMenu
.ID_NEW_STATIC_BOX_SIZER
: 'wxStaticBoxSizer',
939 pullDownMenu
.ID_NEW_GRID_SIZER
: 'wxGridSizer',
940 pullDownMenu
.ID_NEW_FLEX_GRID_SIZER
: 'wxFlexGridSizer',
941 pullDownMenu
.ID_NEW_SPACER
: 'spacer',
942 pullDownMenu
.ID_NEW_MENU
: 'wxMenu',
943 pullDownMenu
.ID_NEW_MENU_ITEM
: 'wxMenuItem',
944 pullDownMenu
.ID_NEW_SEPARATOR
: 'separator',
946 pullDownMenu
.controls
= [
947 ['control', 'Various controls',
948 (pullDownMenu
.ID_NEW_STATIC_TEXT
, 'Label', 'Create static label'),
949 (pullDownMenu
.ID_NEW_STATIC_LINE
, 'Line', 'Create static line'),
950 (pullDownMenu
.ID_NEW_TEXT_CTRL
, 'TextBox', 'Create text box control'),
951 (pullDownMenu
.ID_NEW_CHOICE
, 'Choice', 'Create choice control'),
952 (pullDownMenu
.ID_NEW_SLIDER
, 'Slider', 'Create slider control'),
953 (pullDownMenu
.ID_NEW_GAUGE
, 'Gauge', 'Create gauge control'),
954 (pullDownMenu
.ID_NEW_SCROLL_BAR
, 'ScrollBar', 'Create scroll bar'),
955 (pullDownMenu
.ID_NEW_TREE_CTRL
, 'TreeCtrl', 'Create tree control'),
956 (pullDownMenu
.ID_NEW_LIST_CTRL
, 'ListCtrl', 'Create list control'),
957 (pullDownMenu
.ID_NEW_CHECK_LIST
, 'CheckList', 'Create check list control'),
958 (pullDownMenu
.ID_NEW_HTML_WINDOW
, 'HtmlWindow', 'Create HTML window'),
959 (pullDownMenu
.ID_NEW_CALENDAR
, 'Calendar', 'Create calendar control'),
960 (pullDownMenu
.ID_NEW_PANEL
, 'Panel', 'Create panel'),
961 (pullDownMenu
.ID_NEW_NOTEBOOK
, 'Notebook', 'Create notebook control'),
963 ['button', 'Buttons',
964 (pullDownMenu
.ID_NEW_BUTTON
, 'Button', 'Create button'),
965 (pullDownMenu
.ID_NEW_BITMAP_BUTTON
, 'BitmapButton', 'Create bitmap button'),
966 (pullDownMenu
.ID_NEW_RADIO_BUTTON
, 'RadioButton', 'Create radio button'),
967 (pullDownMenu
.ID_NEW_SPIN_BUTTON
, 'SpinButton', 'Create spin button'),
970 (pullDownMenu
.ID_NEW_STATIC_BOX
, 'StaticBox', 'Create static box'),
971 (pullDownMenu
.ID_NEW_CHECK_BOX
, 'CheckBox', 'Create check box'),
972 (pullDownMenu
.ID_NEW_RADIO_BOX
, 'RadioBox', 'Create radio box'),
973 (pullDownMenu
.ID_NEW_COMBO_BOX
, 'ComboBox', 'Create combo box'),
974 (pullDownMenu
.ID_NEW_LIST_BOX
, 'ListBox', 'Create list box'),
977 (pullDownMenu
.ID_NEW_BOX_SIZER
, 'BoxSizer', 'Create box sizer'),
978 (pullDownMenu
.ID_NEW_STATIC_BOX_SIZER
, 'StaticBoxSizer',
979 'Create static box sizer'),
980 (pullDownMenu
.ID_NEW_GRID_SIZER
, 'GridSizer', 'Create grid sizer'),
981 (pullDownMenu
.ID_NEW_FLEX_GRID_SIZER
, 'FlexGridSizer',
982 'Create flexgrid sizer'),
983 (pullDownMenu
.ID_NEW_SPACER
, 'Spacer', 'Create spacer'),
986 pullDownMenu
.menuControls
= [
987 (pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu'),
988 (pullDownMenu
.ID_NEW_MENU_ITEM
, 'MenuItem', 'Create menu item'),
989 (pullDownMenu
.ID_NEW_SEPARATOR
, 'Separator', 'Create separator'),
996 EVT_IDLE(self
, self
.OnIdle
)
997 EVT_CLOSE(self
, self
.OnCloseWindow
)
999 def OnNew(self
, evt
):
1002 def OnOpen(self
, evt
):
1003 if not self
.AskSave(): return
1004 dlg
= wxFileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
),
1005 '', '*.xrc', wxOPEN | wxCHANGE_DIR
)
1006 if dlg
.ShowModal() == wxID_OK
:
1007 path
= dlg
.GetPath()
1008 self
.SetStatusText('Loading...')
1013 self
.SetStatusText('Ready')
1016 def OnSaveOrSaveAs(self
, evt
):
1017 if evt
.GetId() == wxID_SAVEAS
or not self
.dataFile
:
1018 if self
.dataFile
: defaultName
= ''
1019 else: defaultName
= 'UNTITLED.xrc'
1020 dlg
= wxFileDialog(self
, 'Save As', os
.path
.dirname(self
.dataFile
),
1021 defaultName
, '*.xrc',
1022 wxSAVE | wxOVERWRITE_PROMPT | wxCHANGE_DIR
)
1023 if dlg
.ShowModal() == wxID_OK
:
1024 path
= dlg
.GetPath()
1030 path
= self
.dataFile
1031 self
.SetStatusText('Saving...')
1035 self
.dataFile
= path
1037 self
.SetStatusText('Ready')
1039 def OnExit(self
, evt
):
1042 def OnUndo(self
, evt
):
1043 print '*** being implemented'
1044 print self
.lastOp
, self
.undo
1045 if self
.lastOp
== 'DELETE':
1046 parent
, prev
, elem
= self
.undo
1048 xxx
= MakeXXXFromDOM(tree
.GetPyData(parent
).treeObject(), elem
)
1049 item
= tree
.InsertItem( parent
, prev
, xxx
.treeObject().className
,
1050 data
=wxTreeItemData(xxx
) )
1052 def OnRedo(self
, evt
):
1053 print '*** being implemented'
1055 def OnCut(self
, evt
):
1056 selected
= tree
.GetSelection()
1059 self
.undo
= [tree
.GetItemParent(selected
), tree
.GetPrevSibling(selected
)]
1063 # If deleting top-level item, delete testWin
1064 if selected
== testWin
.item
:
1068 # Remove highlight, update testWin
1069 if tree
.GetItemAncestor(selected
) == testWin
.item
:
1070 if testWin
.highLight
: testWin
.highLight
.Remove()
1071 tree
.needUpdate
= true
1072 self
.clipboard
= tree
.RemoveLeaf(selected
)
1073 tree
.pendingHighLight
= None
1076 self
.modified
= true
1078 def OnCopy(self
, evt
):
1079 selected
= tree
.GetSelection()
1080 xxx
= tree
.GetPyData(selected
)
1081 self
.clipboard
= xxx
.element
.cloneNode(true
)
1083 def OnPaste(self
, evt
):
1084 selected
= tree
.GetSelection()
1085 appendChild
= not tree
.NeedInsert(selected
)
1086 xxx
= tree
.GetPyData(selected
)
1088 # If has next item, insert, else append to parent
1089 nextItem
= tree
.GetNextSibling(selected
)
1091 # Insert before nextItem
1092 parentLeaf
= tree
.GetItemParent(selected
)
1093 else: # last child: change selected to parent
1095 selected
= tree
.GetItemParent(selected
)
1096 # Expanded container (must have children)
1097 elif tree
.IsExpanded(selected
) and tree
.ItemHasChildren(selected
):
1099 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
1100 parentLeaf
= selected
1101 # Parent should be tree element or None
1103 parent
= tree
.GetPyData(selected
)
1105 parent
= tree
.GetPyData(parentLeaf
)
1106 if parent
and parent
.hasChild
: parent
= parent
.child
1108 # Create a copy of clipboard element
1109 elem
= self
.clipboard
.cloneNode(true
)
1110 # Tempopary xxx object to test things
1111 xxx
= MakeXXXFromDOM(parent
, elem
)
1112 className
= xxx
.treeObject().className
1113 # Check parent and child relationships
1114 # Parent is sizer or notebook, child is of wrong class or
1115 # parent is normal window, child is child container: detach child
1116 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
1117 if not parent
and isChildContainer
or \
1118 (parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
1119 (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
1120 (not parent
.isSizer
and not isinstance(parent
, xxxNotebook
) and \
1122 if isChildContainer
:
1123 elem
.removeChild(xxx
.child
.element
) # detach child
1124 elem
.unlink() # delete child container
1125 elem
= xxx
.child
.element
# replace
1126 # This should help garbage collection (!!! maybe not needed?)
1127 xxx
.child
.parent
= None
1130 # Parent is sizer or notebook, child is not child container
1131 if parent
.isSizer
and not isChildContainer
and \
1132 not isinstance(xxx
, xxxSpacer
):
1133 # Create sizer item element
1134 sizerItemElem
= MakeEmptyDOM('sizeritem')
1135 sizerItemElem
.appendChild(elem
)
1136 elem
= sizerItemElem
1137 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
1138 pageElem
= MakeEmptyDOM('notebookpage')
1139 pageElem
.appendChild(elem
)
1141 xxx
= MakeXXXFromDOM(parent
, elem
)
1142 # Figure out if we must append a new child or sibling
1144 if parent
: node
= parent
.element
1145 else: node
= tree
.mainNode
1146 node
.appendChild(elem
)
1147 newItem
= tree
.AppendItem(selected
, xxx
.treeName(), image
=xxx
.treeImage(),
1148 data
=wxTreeItemData(xxx
))
1150 node
= tree
.GetPyData(nextItem
).element
1152 elemParent
= parent
.element
1154 elemParent
= tree
.mainNode
1155 elemParent
.insertBefore(elem
, node
)
1156 # Inserting before is difficult, se we insert after or first child
1157 newItem
= tree
.InsertItem(parentLeaf
, selected
, xxx
.treeName(),
1158 image
=xxx
.treeImage(), data
=wxTreeItemData(xxx
))
1159 # Add children items
1161 treeObj
= xxx
.treeObject()
1162 for n
in treeObj
.element
.childNodes
:
1164 tree
.AddNode(newItem
, treeObj
, n
)
1165 # Scroll to show new item
1166 tree
.EnsureVisible(newItem
)
1167 tree
.SelectItem(newItem
)
1168 if not tree
.IsVisible(newItem
):
1169 tree
.ScrollTo(newItem
)
1172 if testWin
and tree
.GetItemAncestor(newItem
) == testWin
.item
:
1173 if conf
.autoRefresh
:
1174 tree
.needUpdate
= true
1175 tree
.pendingHighLight
= newItem
1177 tree
.pendingHighLight
= None
1178 self
.modified
= true
1180 def OnDelete(self
, evt
):
1181 selected
= tree
.GetSelection()
1183 self
.lastOp
= 'DELETE'
1184 self
.undo
= [tree
.GetItemParent(selected
), tree
.GetPrevSibling(selected
)]
1188 # If deleting top-level item, delete testWin
1189 if selected
== testWin
.item
:
1193 # Remove highlight, update testWin
1194 if tree
.GetItemAncestor(selected
) == testWin
.item
:
1195 if testWin
.highLight
: testWin
.highLight
.Remove()
1196 tree
.needUpdate
= true
1197 xnode
= tree
.RemoveLeaf(selected
)
1198 self
.undo
.append(xnode
.cloneNode(true
))
1200 tree
.pendingHighLight
= None
1203 self
.modified
= true
1205 def OnRefresh(self
, evt
):
1206 # If modified, apply first
1207 selection
= tree
.GetSelection()
1208 if selection
.IsOk():
1209 xxx
= tree
.GetPyData(selection
)
1210 if xxx
and panel
.IsModified():
1211 tree
.Apply(xxx
, selection
)
1214 tree
.CreateTestWin(testWin
.item
)
1215 tree
.needUpdate
= false
1217 def OnAutoRefresh(self
, evt
):
1218 conf
.autoRefresh
= evt
.IsChecked()
1219 self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1220 self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1222 def OnAbout(self
, evt
):
1223 wxMessageDialog(self
, '%s %s\n\nRoman Rolinsky <rolinsky@mema.ucl.ac.be>' % \
1224 (progname
, version
),
1225 'About %s' % progname
, wxOK | wxCENTRE
).ShowModal()
1227 # Simple emulation of python command line
1228 def OnDebugCMD(self
, evt
):
1231 exec raw_input('C:\> ')
1236 (etype
, value
, tb
) =sys
.exc_info()
1237 tblist
=traceback
.extract_tb(tb
)[1:]
1238 msg
=string
.join(traceback
.format_exception_only(etype
, value
)
1239 +traceback
.format_list(tblist
))
1242 def OnCreate(self
, evt
):
1243 selected
= tree
.GetSelection()
1244 appendChild
= not tree
.NeedInsert(selected
)
1245 xxx
= tree
.GetPyData(selected
)
1247 # If has next item, insert, else append to parent
1248 nextItem
= tree
.GetNextSibling(selected
)
1250 # Insert before nextItem
1251 parentLeaf
= tree
.GetItemParent(selected
)
1252 else: # last child: change selected to parent
1254 selected
= tree
.GetItemParent(selected
)
1255 # Expanded container (must have children)
1256 elif tree
.IsExpanded(selected
) and tree
.ItemHasChildren(selected
):
1258 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
1259 parentLeaf
= selected
1260 # Parent should be tree element or None
1262 parent
= tree
.GetPyData(selected
)
1264 parent
= tree
.GetPyData(parentLeaf
)
1265 if parent
and parent
.hasChild
: parent
= parent
.child
1268 className
= self
.createMap
[evt
.GetId()]
1269 xxx
= MakeEmptyXXX(parent
, className
)
1270 # Figure out if we must append a new child or sibling
1273 if parent
: node
= parent
.element
1274 else: node
= tree
.mainNode
1275 # Insert newline for debug purposes
1276 node
.appendChild(tree
.dom
.createTextNode('\n'))
1277 node
.appendChild(elem
)
1278 newItem
= tree
.AppendItem(selected
, xxx
.treeName(), image
=xxx
.treeImage(),
1279 data
=wxTreeItemData(xxx
))
1281 node
= tree
.GetPyData(nextItem
).element
1283 elemParent
= parent
.element
1285 elemParent
= tree
.mainNode
1286 elemParent
.insertBefore(tree
.dom
.createTextNode('\n'), node
)
1287 elemParent
.insertBefore(elem
, node
)
1288 # Inserting before is difficult, se we insert after or first child
1289 newItem
= tree
.InsertItem(parentLeaf
, selected
,
1290 xxx
.treeName(), image
=xxx
.treeImage(),
1291 data
=wxTreeItemData(xxx
))
1292 tree
.EnsureVisible(newItem
)
1293 tree
.SelectItem(newItem
)
1294 if not tree
.IsVisible(newItem
):
1295 tree
.ScrollTo(newItem
)
1298 if testWin
and tree
.GetItemAncestor(newItem
) == testWin
.item
:
1299 if conf
.autoRefresh
:
1300 tree
.needUpdate
= true
1301 tree
.pendingHighLight
= newItem
1303 tree
.pendingHighLight
= None
1305 def OnExpand(self
, evt
):
1306 if tree
.GetSelection().IsOk():
1307 tree
.ExpandAll(tree
.GetSelection())
1309 tree
.ExpandAll(tree
.GetRootItem())
1311 def OnPullDownHighlight(self
, evt
):
1312 menuId
= evt
.GetMenuId()
1314 menu
= evt
.GetEventObject()
1315 help = menu
.GetHelpString(menuId
)
1316 self
.SetStatusText(help)
1318 self
.SetStatusText('')
1320 def OnUpdateUI(self
, evt
):
1321 if evt
.GetId() in [wxID_CUT
, wxID_COPY
, self
.ID_DELETE
]:
1322 enable
= tree
.GetSelection().IsOk() and \
1323 tree
.GetSelection() != tree
.GetRootItem()
1325 elif evt
.GetId() == wxID_PASTE
:
1326 enable
= self
.clipboard
!= None
1329 def OnIdle(self
, evt
):
1331 if conf
.autoRefresh
:
1334 tree
.CreateTestWin(testWin
.item
)
1335 tree
.needUpdate
= false
1336 elif tree
.pendingHighLight
:
1337 tree
.HighLight(tree
.pendingHighLight
)
1340 def OnCloseWindow(self
, evt
):
1341 if not self
.AskSave(): return
1342 if testWin
: testWin
.Destroy()
1343 conf
.width
, conf
.height
= self
.GetSize()
1348 self
.clipboard
= None
1349 self
.modified
= false
1350 panel
.SetModified(false
)
1357 self
.SetTitle(progname
)
1359 def Open(self
, path
):
1360 # Try to read the file
1365 dom
= minidom
.parse(path
)
1367 self
.dataFile
= path
1368 self
.SetTitle(progname
+ ': ' + os
.path
.basename(path
))
1370 wxLogError('Error reading file: ' + path
)
1373 def Save(self
, path
):
1375 self
.OnRefresh(wxCommandEvent())
1376 memFile
= MemoryFile(path
)
1377 tree
.dom
.writexml(memFile
)
1379 self
.modified
= false
1380 panel
.SetModified(false
)
1382 wxLogError('Error writing file: ' + path
)
1386 if not (self
.modified
or panel
.IsModified()): return true
1387 flags
= wxICON_EXCLAMATION | wxYES_NO | wxCANCEL | wxCENTRE
1388 say
= wxMessageDialog( self
, 'File is modified. Save before exit?',
1389 'Save before too late?', flags
).ShowModal()
1391 self
.OnSaveOrSaveAs(wxCommandEvent(wxID_SAVE
))
1392 # If save was successful, modified flag is unset
1393 if not self
.modified
: return true
1394 elif say
== wxID_NO
:
1395 self
.modified
= false
1396 panel
.SetModified(false
)
1400 ################################################################################
1404 self
.SetAppName("xrced")
1407 # !!! wxConfigBase_Get doesn't seem to work
1408 conf
= wxConfig(style
=wxCONFIG_USE_LOCAL_FILE
)
1409 conf
.autoRefresh
= conf
.ReadInt('autorefresh', true
)
1410 size
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600)
1412 wxFileSystem_AddHandler(wxMemoryFSHandler())
1413 wxInitAllImageHandlers()
1416 frame
= self
.frame
= Frame(size
)
1417 self
.frame
.Show(true
)
1418 # Load resources from XRC file (!!! should be transformed to .py later)
1419 sys
.modules
['params'].frame
= frame
1420 frame
.res
= wxXmlResource('')
1421 frame
.res
.Load(os
.path
.join(sys
.path
[0], 'xrced.xrc'))
1426 wc
= wxConfigBase_Get()
1427 wc
.WriteInt('autorefresh', conf
.autoRefresh
)
1428 wc
.WriteInt('width', conf
.width
)
1429 wc
.WriteInt('height', conf
.height
)
1437 if __name__
== '__main__':