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 # Background colour problem on wxGTK
21 if wxGetOsVersion()[1] == 1:
22 bgcolor
= (faceColour
.Red()-1, faceColour
.Green()-1, faceColour
.Blue()-1)
24 bgcolor
= (faceColour
.Red(), faceColour
.Green(), faceColour
.Blue())
25 htmlHeader
= '<html><body bgcolor="#%02x%02x%02x">\n' % bgcolor
26 htmlFooter
= '</body></html>\n'
35 testWinPos
= wxDefaultPosition
37 # 1 adds CMD command to Help menu
44 # Set menu to list items.
45 # Each menu command is a tuple (id, label, help)
46 # submenus are lists [id, label, help, submenu]
47 # and separators are any other type
50 if type(l
) == types
.TupleType
:
52 elif type(l
) == types
.ListType
:
54 SetMenu(subMenu
, l
[2:])
55 m
.AppendMenu(wxNewId(), l
[0], subMenu
, l
[1])
59 ################################################################################
61 # Properties panel containing notebook
62 class Panel(wxNotebook
):
63 def __init__(self
, parent
, id = -1):
64 wxNotebook
.__init
__(self
, parent
, id, style
=wxNB_BOTTOM
)
65 sys
.modules
['params'].panel
= self
66 self
.page1
= HtmlPage(self
)
67 self
.AddPage(self
.page1
, 'Properties')
69 # Cache for already used panels
71 def SetData(self
, xxx
):
73 self
.page1
.SetPageData(xxx
)
74 # Replace/remove style page
75 curPage
= self
.GetSelection()
77 # If style page for a same class, don't need to recreate
78 if xxx
and self
.page2
.cacheId
== xxx
.treeObject().__class
__:
79 self
.page2
.SetData(xxx
.treeObject())
81 # Else remove and then add if needed
83 if not self
.styleCache
.has_key(self
.page2
.cacheId
):
84 self
.styleCache
[self
.page2
.cacheId
] = self
.page2
86 if xxx
and xxx
.treeObject().hasStyle
:
87 cacheId
= xxx
.treeObject().__class
__
88 if self
.styleCache
.has_key(cacheId
):
89 self
.page2
= self
.styleCache
[cacheId
]
90 self
.page2
.SetData(xxx
.treeObject())
92 self
.page2
= StylePage(self
, xxx
.treeObject())
93 self
.AddPage(self
.page2
, 'Style')
97 if self
.page2
and curPage
== 1:
98 self
.SetSelection(curPage
)
106 # If some parameter on some page has changed
107 def IsModified(self
):
108 return self
.page1
.IsModified() or self
.page2
and self
.page2
.IsModified()
109 def SetModified(self
, value
):
110 self
.page1
.SetModified(value
)
112 self
.page2
.SetModified(value
)
114 ################################################################################
116 # General class for notebook pages
119 # Register event handlers
120 for id in paramIDs
.values():
121 EVT_CHECKBOX(self
, id, self
.OnCheckParams
)
122 def OnCheckParams(self
, evt
):
123 selected
= tree
.GetSelection()
124 xxx
= tree
.GetPyData(selected
)
125 winName
= evt
.GetEventObject().GetName()
127 if winName
[0] == '_':
131 if xxx
.hasChild
: xxx
= xxx
.child
135 w
= self
.FindWindowByName('_data_' + param
)
137 w
= self
.FindWindowByName('data_' + param
)
138 objElem
= xxx
.element
140 # Ad new text node in order of allParams
141 w
.SetValue('') # set empty (default) value
142 w
.SetModified() # mark as changed
143 elem
= tree
.dom
.createElement(param
)
144 xxx
.params
[param
] = xxxParam(elem
)
145 # Find place to put new element: first present element after param
147 paramStyles
= xxx
.allParams
+ xxx
.styles
148 for p
in paramStyles
[paramStyles
.index(param
) + 1:]:
149 # Content params don't have same type
150 if xxx
.params
.has_key(p
) and p
!= 'content':
154 nextTextElem
= xxx
.params
[p
].node
155 objElem
.insertBefore(elem
, nextTextElem
)
157 objElem
.appendChild(elem
)
160 xxx
.params
[param
].remove()
161 del xxx
.params
[param
]
164 self
.SetModified(true
)
165 w
.Enable(evt
.IsChecked())
168 ################################################################################
170 # Properties panel notebook page
171 class HtmlPage(wxHtmlWindow
, ParamPage
):
172 def __init__(self
, parent
, id = -1):
173 wxHtmlWindow
.__init
__(self
, parent
, id)
174 ParamPage
.__init
__(self
)
176 if wxGetOsVersion()[1] == 1:
177 self
.SetFonts('', '', [8, 10, 12, 14, 16, 19, 24])
179 self
.SetFonts("", "", [7, 8, 10, 12, 16, 22, 30])
180 self
.modified
= false
182 self
.xxxClass
= self
.xxxChildClass
= None
184 self
.SetPage(htmlHeader
+ 'select a tree item on the left' + htmlFooter
)
185 def SetPageData(self
, xxx
):
187 self
.SetPage(htmlHeader
+ 'this item has no properties' + htmlFooter
)
189 self
.Freeze() # doesn't seem to help
190 # Don't change interface if same class
192 if self
.xxxClass
and self
.xxxClass
== xxx
.__class
__:
193 compare
= true
# a little weird code
195 if self
.xxxChildClass
!= xxx
.child
.__class
__:
197 if not compare
: # not same
198 self
.SetPage(htmlHeader
+ xxx
.generateHtml() + htmlFooter
)
199 self
.xxxClass
= xxx
.__class
__
200 if xxx
.hasChild
: self
.xxxChildClass
= xxx
.child
.__class
__
203 self
.SetValues(xxx
.child
)
205 def SetValues(self
, xxx
):
206 # Set values, checkboxes to false, disable defaults
207 if xxx
.hasChild
: prefix
= '_'
210 self
.FindWindowByName('data_name').SetValue(xxx
.name
)
211 for param
in xxx
.allParams
:
213 value
= xxx
.params
[param
].value()
214 self
.FindWindowByName(prefix
+ 'data_' + param
).SetValue(value
)
215 if not param
in xxx
.required
:
216 self
.FindWindowByName(prefix
+ 'check_' + param
).SetValue(true
)
218 self
.FindWindowByName(prefix
+ 'data_' + param
).Enable(false
)
219 # If some parameter has changed
220 def IsModified(self
):
222 def SetModified(self
, value
):
223 self
.modified
= value
225 ################################################################################
227 # Style notebook page
228 class StylePage(wxPanel
, ParamPage
):
229 def __init__(self
, parent
, xxx
):
230 wxPanel
.__init
__(self
, parent
, -1)
231 ParamPage
.__init
__(self
)
232 self
.cacheId
= xxx
.__class
__
233 if wxGetOsVersion()[1] == 1:
234 self
.SetFont(wxFont(12, wxDEFAULT
, wxNORMAL
, wxNORMAL
))
236 self
.SetFont(wxFont(10, wxDEFAULT
, wxNORMAL
, wxNORMAL
))
237 topSizer
= wxBoxSizer(wxVERTICAL
)
238 sizer
= wxFlexGridSizer(len(xxx
.styles
), 2, 1, 1)
239 self
.controls
= {} # save python objects
240 for param
in xxx
.styles
:
241 present
= param
in xxx
.params
.keys()
242 check
= wxCheckBox(self
, paramIDs
[param
],
243 param
+ ':', name
= 'check_' + param
)
244 check
.SetValue(present
)
245 control
= paramDict
[param
](self
, name
= 'data_' + param
)
247 control
.SetValue(xxx
.params
[param
].value())
250 control
.Enable(present
)
251 sizer
.AddMany([ (check
, 0, wxALIGN_CENTER_VERTICAL
),
252 (control
, 0, wxALIGN_CENTER_VERTICAL
) ])
253 self
.controls
[param
] = control
254 topSizer
.Add(sizer
, 1, wxALL
, 5)
255 self
.SetAutoLayout(true
)
256 self
.SetSizer(topSizer
)
258 self
.modified
= false
260 # Set data for a cahced page
261 def SetData(self
, xxx
):
262 for param
in xxx
.styles
:
263 present
= param
in xxx
.params
.keys()
264 check
= self
.FindWindowByName('check_' + param
)
265 check
.SetValue(present
)
266 control
= self
.controls
[param
]
268 control
.SetValue(xxx
.params
[param
].value())
271 control
.Enable(present
)
272 self
.modified
= false
274 # If some parameter has changed
275 def IsModified(self
):
277 def SetModified(self
, value
):
278 self
.modified
= value
280 ################################################################################
283 def __init__(self
, pos
, size
):
285 l1
= wxWindow(w
, -1, pos
, wxSize(size
.x
, 2))
286 l1
.SetBackgroundColour(wxRED
)
287 l2
= wxWindow(w
, -1, pos
, wxSize(2, size
.y
))
288 l2
.SetBackgroundColour(wxRED
)
289 l3
= wxWindow(w
, -1, wxPoint(pos
.x
+ size
.x
- 2, pos
.y
), wxSize(2, size
.y
))
290 l3
.SetBackgroundColour(wxRED
)
291 l4
= wxWindow(w
, -1, wxPoint(pos
.x
, pos
.y
+ size
.y
- 2), wxSize(size
.x
, 2))
292 l4
.SetBackgroundColour(wxRED
)
293 self
.lines
= [l1
, l2
, l3
, l4
]
294 # Move highlight to a new position
295 def Replace(self
, pos
, size
):
296 self
.lines
[0].SetDimensions(pos
.x
, pos
.y
, size
.x
, 2, wxSIZE_ALLOW_MINUS_ONE
)
297 self
.lines
[1].SetDimensions(pos
.x
, pos
.y
, 2, size
.y
, wxSIZE_ALLOW_MINUS_ONE
)
298 self
.lines
[2].SetDimensions(pos
.x
+ size
.x
- 2, pos
.y
, 2, size
.y
,
299 wxSIZE_ALLOW_MINUS_ONE
)
300 self
.lines
[3].SetDimensions(pos
.x
, pos
.y
+ size
.y
- 2, size
.x
, 2,
301 wxSIZE_ALLOW_MINUS_ONE
)
304 map(wxWindow
.Destroy
, self
.lines
)
305 testWin
.highLight
= None
307 ################################################################################
310 def __init__(self
, name
):
313 def write(self
, data
):
314 self
.buffer = self
.buffer + data
.encode()
316 f
= open(self
.name
, 'w')
319 # !!! memory FS will work someday
320 #self.file = wxMemoryFSHandler_AddFile(self.name, self.buffer)
322 class XML_Tree(wxTreeCtrl
):
323 def __init__(self
, parent
, id):
324 wxTreeCtrl
.__init
__(self
, parent
, id,
325 style
=wxTR_HAS_BUTTONS | wxTR_LINES_AT_ROOT
)
326 self
.SetBackgroundColour(wxColour(224, 248, 224))
327 EVT_TREE_SEL_CHANGED(self
, self
.GetId(), self
.OnSelChanged
)
328 # One works on Linux, another on Windows
329 EVT_TREE_ITEM_ACTIVATED(self
, self
.GetId(), self
.OnItemActivated
)
330 EVT_LEFT_DCLICK(self
, self
.OnDClick
)
331 EVT_RIGHT_DOWN(self
, self
.OnRightDown
)
332 self
.needUpdate
= false
333 self
.pendingHighLight
= None
337 il
= wxImageList(16, 16, true
)
338 self
.rootImage
= il
.AddIcon(wxIconFromXPMData(images
.getTreeRootData()))
339 xxxObject
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeDefaultData()))
340 xxxPanel
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreePanelData()))
341 xxxDialog
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeDialogData()))
342 xxxFrame
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeFrameData()))
343 xxxMenuBar
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeMenuBarData()))
344 xxxToolBar
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeToolBarData()))
345 xxxMenu
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeMenuData()))
346 xxxSizer
.imageH
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerHData()))
347 xxxSizer
.imageV
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerVData()))
348 xxxStaticBoxSizer
.imageH
= il
.AddIcon(wxIconFromXPMData(images
.getTreeStaticBoxSizerHData()))
349 xxxStaticBoxSizer
.imageV
= il
.AddIcon(wxIconFromXPMData(images
.getTreeStaticBoxSizerVData()))
350 xxxGridSizer
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerGridData()))
351 xxxFlexGridSizer
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerFlexGridData()))
353 self
.SetImageList(il
)
355 # !!! temporary solution for GetOldItem problem
357 self
.selection
= wxTreeItemId()
358 wxTreeCtrl
.Unselect(self
)
359 def GetSelection(self
):
360 return self
.selection
362 def ExpandAll(self
, item
):
363 if self
.ItemHasChildren(item
):
365 i
, cookie
= self
.GetFirstChild(item
, 0)
369 i
, cookie
= self
.GetNextChild(item
, cookie
)
373 def SetData(self
, dom
):
375 # Find 'resource' child, add it's children
376 self
.mainNode
= dom
.getElementsByTagName('resource')[0]
377 nodes
= self
.mainNode
.childNodes
[:]
380 self
.AddNode(self
.GetRootItem(), None, node
)
382 self
.mainNode
.removeChild(node
)
386 # Add tree item for given parent item if node is DOM element node with
387 # 'object' tag. xxxParent is parent xxx object
388 def AddNode(self
, itemParent
, xxxParent
, node
):
389 # Set item data to current node
391 xxx
= MakeXXXFromDOM(xxxParent
, node
)
394 treeObj
= xxx
.treeObject()
396 item
= self
.AppendItem(itemParent
, treeObj
.treeName(),
397 image
=treeObj
.treeImage(),
398 data
=wxTreeItemData(xxx
))
399 # Try to find children objects
400 if treeObj
.hasChildren
:
401 nodes
= treeObj
.element
.childNodes
[:]
404 self
.AddNode(item
, treeObj
, n
)
405 elif n
.nodeType
!= minidom
.Node
.ELEMENT_NODE
:
406 treeObj
.element
.removeChild(n
)
410 # Remove leaf of tree, return it's data object
411 def RemoveLeaf(self
, leaf
):
412 xxx
= self
.GetPyData(leaf
)
414 parent
= node
.parentNode
415 parent
.removeChild(node
)
418 #if testWin and self.GetItemAncestor(leaf) == testWin.item:
419 # if testWin.highLight:
420 # testWin.highLight.Remove()
421 # self.needUpdate = true
424 # Find position relative to the top-level window
425 def FindNodePos(self
, item
):
426 itemParent
= self
.GetItemParent(item
)
427 if itemParent
== self
.GetRootItem(): return wxPoint(0, 0)
428 obj
= self
.FindNodeObject(item
)
429 # Find first ancestor which is a wxWindow (not a sizer)
430 winParent
= itemParent
431 while self
.GetPyData(winParent
).isSizer
:
432 winParent
= self
.GetItemParent(winParent
)
433 parentPos
= self
.FindNodePos(winParent
)
434 return parentPos
+ obj
.GetPosition()
436 # Find window (or sizer) corresponding to a tree item.
437 def FindNodeObject(self
, item
):
438 itemParent
= self
.GetItemParent(item
)
439 # If top-level, return testWin (or panel if wxFrame)
440 if itemParent
== self
.GetRootItem(): return testWin
.panel
441 xxx
= self
.GetPyData(item
).treeObject()
442 parentWin
= self
.FindNodeObject(itemParent
)
443 # Top-level sizer? return window's sizer
444 if xxx
.isSizer
and isinstance(parentWin
, wxWindowPtr
):
445 return parentWin
.GetSizer()
446 # Otherwise get parent's object and it's child
447 n
= 0 # index of sibling
448 prev
= self
.GetPrevSibling(item
)
450 prev
= self
.GetPrevSibling(prev
)
452 child
= parentWin
.GetChildren()[n
]
453 # Return window or sizer for sizer items
454 if child
.GetClassName() == 'wxSizerItem':
455 if child
.IsWindow(): child
= child
.GetWindow()
456 elif child
.IsSizer():
457 child
= child
.GetSizer()
458 # Test for notebook sizers
459 if isinstance(child
, wxNotebookSizerPtr
):
460 child
= child
.GetNotebook()
463 def OnSelChanged(self
, evt
):
465 # !!! problem with wxGTK
466 #oldItem = evt.GetOldItem()
467 oldItem
= self
.selection
469 xxx
= self
.GetPyData(oldItem
)
470 # If some data was modified, apply changes
472 if panel
.IsModified():
473 self
.Apply(xxx
, oldItem
)
474 #if conf.autoRefresh:
475 if testWin
and testWin
.highLight
:
476 testWin
.highLight
.Remove()
477 self
.needUpdate
= true
480 self
.selection
= item
# !!! fix
481 xxx
= self
.GetPyData(item
)
485 if not xxx
and testWin
and testWin
.highLight
:
486 testWin
.highLight
.Remove()
489 panel
.SetModified(false
)
490 # Hightlighting is done in OnIdle
491 tree
.pendingHighLight
= item
493 # Find top-level parent
494 def GetItemAncestor(self
, item
):
495 while self
.GetItemParent(item
) != self
.GetRootItem():
496 item
= self
.GetItemParent(item
)
499 # Highlight selected item
500 def HighLight(self
, item
):
501 self
.pendingHighLight
= None
502 if not testWin
or self
.GetPyData(testWin
.item
).className \
503 not in ['wxDialog', 'wxPanel', 'wxFrame']:
505 # Top-level does not have highlight
506 if item
== testWin
.item
or item
== tree
.GetRootItem():
507 if testWin
.highLight
: testWin
.highLight
.Remove()
509 # If a control from another window is selected, remove highlight
510 if self
.GetItemAncestor(item
) != testWin
.item
and testWin
.highLight
:
511 testWin
.highLight
.Remove()
513 # Get window/sizer object
514 obj
, pos
= self
.FindNodeObject(item
), self
.FindNodePos(item
)
516 # For notebook, select item's page.
517 # For children of page, nothing happens (too much work)
518 if isinstance(self
.GetPyData(item
).parent
, xxxNotebook
):
519 notebook
= self
.FindNodeObject(self
.GetItemParent(item
))
522 prev
= self
.GetPrevSibling(item
)
525 prev
= self
.GetPrevSibling(prev
)
526 notebook
.SetSelection(n
)
528 try: # finally I use exceptions
529 testWin
.highLight
.Replace(pos
, size
)
530 except AttributeError:
531 testWin
.highLight
= HightLightBox(pos
, size
)
532 testWin
.highLight
.item
= item
534 # Double-click on Linux
535 def OnItemActivated(self
, evt
):
537 xxx
= self
.GetPyData(item
)
538 if not xxx
: return # if root selected, do nothing
539 if panel
.IsModified():
540 self
.Apply(xxx
, item
) # apply changes
541 self
.CreateTestWin(item
)
543 # Double-click on Windows
544 def OnDClick(self
, evt
):
545 id, flags
= self
.HitTest(evt
.GetPosition())
546 if flags
in [wxTREE_HITTEST_ONITEMBUTTON
, wxTREE_HITTEST_ONITEMLABEL
]:
547 # !!! can't create a wxTreeItemId from int
548 item
= self
.selection
# assume item already selected
549 xxx
= self
.GetPyData(item
)
550 if not xxx
: return # if root selected, do nothing
551 if panel
.IsModified():
552 self
.Apply(xxx
, item
) # apply changes
553 self
.CreateTestWin(item
)
557 # (re)create test window
558 def CreateTestWin(self
, node
):
560 # Create a window with this resource
561 xxx
= self
.GetPyData(node
).treeObject()
562 if not xxx
: return # if root selected, do nothing
563 # If noname element, display error
564 if not xxx
.hasName
or not xxx
.name
:
565 wxLogError("Can't display a noname element")
567 # Close old window, remember where it was
570 pos
= testWin
.GetPosition()
571 if node
== testWin
.item
:
572 # Remember highlight if same top-level window
573 if testWin
.highLight
:
574 highLight
= testWin
.highLight
.item
575 # !!! if 0 is removed, refresh is broken (notebook not deleted?)
576 if 0 and xxx
.className
== 'wxPanel':
577 if testWin
.highLight
:
578 testWin
.pendingHighLight
= highLight
579 testWin
.highLight
.Remove()
580 testWin
.panel
.Destroy()
590 # Save in temporary file before activating
591 memFile
= MemoryFile(tempfile
.mktemp('xrc'))
592 #memFile = MemoryFile('core.xrc') # to write debug file
593 # Create partial XML file - faster for big files
595 dom
= minidom
.Document()
596 mainNode
= dom
.createElement('resource')
597 dom
.appendChild(mainNode
)
599 # Remove temporarily from old parent
601 parent
= elem
.parentNode
602 next
= elem
.nextSibling
603 parent
.replaceChild(self
.dummyNode
, elem
)
604 # Append to new DOM, write it
605 mainNode
.appendChild(elem
)
606 dom
.writexml(memFile
)
608 mainNode
.removeChild(elem
)
610 parent
.replaceChild(elem
, self
.dummyNode
)
612 memFile
.close() # write to wxMemoryFS
613 res
= wxXmlResource('')
614 res
.Load(memFile
.name
)
615 if xxx
.className
== 'wxFrame':
617 testWin
= wxPreFrame()
618 res
.LoadFrame(testWin
, frame
, xxx
.name
)
619 testWin
.panel
= testWin
620 testWin
.SetPosition(pos
)
622 elif xxx
.className
== 'wxPanel':
625 testWin
= wxFrame(frame
, -1, 'Panel: ' + xxx
.name
, pos
=pos
)
626 testWin
.panel
= res
.LoadPanel(testWin
, xxx
.name
)
627 testWin
.SetSize(testWin
.panel
.GetSize())
629 elif xxx
.className
== 'wxDialog':
631 testWin
= res
.LoadDialog(None, xxx
.name
)
632 testWin
.panel
= testWin
633 testWin
.SetPosition(pos
)
635 elif xxx
.className
== 'wxMenuBar':
636 testWin
= wxFrame(frame
, -1, 'MenuBar: ' + xxx
.name
, pos
=pos
)
637 # Set status bar to display help
638 testWin
.CreateStatusBar()
639 testWin
.menuBar
= res
.LoadMenuBar(xxx
.name
)
640 testWin
.SetMenuBar(testWin
.menuBar
)
643 wxLogMessage('No view for this element yet')
645 os
.unlink(memFile
.name
) # remove tmp file
647 testWin
.Connect(testWin
.GetId(), -1, wxEVT_CLOSE_WINDOW
, self
.OnCloseTestWin
)
648 testWin
.highLight
= None
649 if highLight
and not tree
.pendingHighLight
:
650 self
.HighLight(highLight
)
652 def OnCloseTestWin(self
, evt
):
653 global testWin
, testWinPos
654 testWinPos
= testWin
.GetPosition()
659 # True if next item should be inserted after current (vs. appended to it)
660 def NeedInsert(self
, item
):
661 xxx
= self
.GetPyData(item
)
662 if not xxx
: return false
# root item
663 if self
.ctrl
: return true
# if Ctrl pressed, always insert
664 if xxx
.hasChildren
and not self
.ItemHasChildren(item
):
666 return not (self
.IsExpanded(item
) and self
.ItemHasChildren(item
))
669 def OnRightDown(self
, evt
):
673 item
= self
.GetSelection()
675 menu
.Append(pullDownMenu
.ID_EXPAND
, 'Expand', 'Expand tree')
677 self
.ctrl
= evt
.ControlDown() # save Ctrl state
678 self
.shift
= evt
.ShiftDown() # and Shift too
679 m
= wxMenu() # create menu
681 if item
!= self
.GetRootItem(): needInsert
= self
.NeedInsert(item
)
682 if item
== self
.GetRootItem() or \
683 self
.GetItemParent(item
) == self
.GetRootItem() and needInsert
:
684 m
.Append(pullDownMenu
.ID_NEW_PANEL
, 'Panel', 'Create panel')
685 m
.Append(pullDownMenu
.ID_NEW_DIALOG
, 'Dialog', 'Create dialog')
686 m
.Append(pullDownMenu
.ID_NEW_FRAME
, 'Frame', 'Create frame')
688 m
.Append(pullDownMenu
.ID_NEW_TOOL_BAR
, 'ToolBar', 'Create toolbar')
689 m
.Append(pullDownMenu
.ID_NEW_MENU_BAR
, 'MenuBar', 'Create menubar')
690 m
.Append(pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu')
692 xxx
= self
.GetPyData(item
)
693 if xxx
.__class
__ == xxxMenuBar
:
694 m
.Append(pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu')
695 elif xxx
.__class
__ in [xxxToolBar
, xxxTool
]:
696 SetMenu(m
, pullDownMenu
.toolBarControls
)
697 elif xxx
.__class
__ in [xxxMenu
, xxxMenuItem
]:
698 SetMenu(m
, pullDownMenu
.menuControls
)
700 SetMenu(m
, pullDownMenu
.controls
)
701 if not (xxx
.isSizer
or \
702 xxx
.parent
and xxx
.parent
.isSizer
):
703 m
.Enable(pullDownMenu
.ID_NEW_SPACER
, false
)
704 # Select correct label for create menu
707 menu
.AppendMenu(wxNewId(), 'Insert Child', m
,
708 'Create child object as the first child')
710 menu
.AppendMenu(wxNewId(), 'Append Child', m
,
711 'Create child object as the last child')
714 menu
.AppendMenu(wxNewId(), 'Create Sibling', m
,
715 'Create sibling before selected object')
717 menu
.AppendMenu(wxNewId(), 'Create Sibling', m
,
718 'Create sibling after selected object')
719 menu
.AppendSeparator()
720 menu
.Append(wxID_CUT
, 'Cut', 'Cut to the clipboard')
721 menu
.Append(wxID_COPY
, 'Copy', 'Copy to the clipboard')
722 menu
.Append(wxID_PASTE
, 'Paste', 'Paste from the clipboard')
723 menu
.Append(pullDownMenu
.ID_DELETE
,
724 'Delete', 'Delete object')
725 if item
.IsOk() and self
.ItemHasChildren(item
):
726 menu
.AppendSeparator()
727 menu
.Append(pullDownMenu
.ID_EXPAND
, 'Expand', 'Expand subtree')
728 self
.PopupMenu(menu
, evt
.GetPosition())
733 self
.DeleteAllItems()
734 # Add minimal structure
735 root
= self
.AddRoot('XML tree', self
.rootImage
)
737 if self
.dom
: self
.dom
.unlink()
738 self
.dom
= minidom
.Document()
739 self
.dummyNode
= self
.dom
.createComment('dummy node')
741 self
.mainNode
= self
.dom
.createElement('resource')
742 self
.dom
.appendChild(self
.mainNode
)
745 def Apply(self
, xxx
, item
):
748 if xxx
.undo
: xxx
.undo
.unlink()
749 xxx
.undo
= xxx
.element
.cloneNode(false
)
751 name
= panel
.page1
.FindWindowByName('data_name').GetValue()
754 xxx
.element
.setAttribute('name', name
)
755 self
.SetItemText(item
, xxx
.treeName())
756 if xxx
.hasChild
: prefix
= '_'
758 for param
, paramObj
in xxx
.params
.items():
759 paramWin
= panel
.FindWindowByName(prefix
+ 'data_' + param
)
760 if not paramWin
.modified
: continue
761 value
= paramWin
.GetValue()
762 if param
in xxx
.specials
:
763 xxx
.setSpecial(param
, value
)
765 paramObj
.update(value
)
767 self
.Apply(xxx
.child
, item
)
769 # Change tree icon for sizers
770 if isinstance(xxx
, xxxBoxSizer
):
771 self
.SetItemImage(item
, xxx
.treeImage())
772 # Set global modified state
773 frame
.modified
= true
776 ID_NEW_PANEL
= wxNewId()
777 ID_NEW_DIALOG
= wxNewId()
778 ID_NEW_FRAME
= wxNewId()
779 ID_NEW_TOOL_BAR
= wxNewId()
780 ID_NEW_TOOL
= wxNewId()
781 ID_NEW_MENU_BAR
= wxNewId()
782 ID_NEW_MENU
= wxNewId()
784 ID_NEW_STATIC_TEXT
= wxNewId()
785 ID_NEW_TEXT_CTRL
= wxNewId()
787 ID_NEW_BUTTON
= wxNewId()
788 ID_NEW_BITMAP_BUTTON
= wxNewId()
789 ID_NEW_RADIO_BUTTON
= wxNewId()
790 ID_NEW_SPIN_BUTTON
= wxNewId()
792 ID_NEW_STATIC_BOX
= wxNewId()
793 ID_NEW_CHECK_BOX
= wxNewId()
794 ID_NEW_RADIO_BOX
= wxNewId()
795 ID_NEW_COMBO_BOX
= wxNewId()
796 ID_NEW_LIST_BOX
= wxNewId()
798 ID_NEW_STATIC_LINE
= wxNewId()
799 ID_NEW_STATIC_BITMAP
= wxNewId()
800 ID_NEW_CHOICE
= wxNewId()
801 ID_NEW_SLIDER
= wxNewId()
802 ID_NEW_GAUGE
= wxNewId()
803 ID_NEW_SCROLL_BAR
= wxNewId()
804 ID_NEW_TREE_CTRL
= wxNewId()
805 ID_NEW_LIST_CTRL
= wxNewId()
806 ID_NEW_CHECK_LIST
= wxNewId()
807 ID_NEW_NOTEBOOK
= wxNewId()
808 ID_NEW_HTML_WINDOW
= wxNewId()
809 ID_NEW_CALENDAR
= wxNewId()
811 ID_NEW_BOX_SIZER
= wxNewId()
812 ID_NEW_STATIC_BOX_SIZER
= wxNewId()
813 ID_NEW_GRID_SIZER
= wxNewId()
814 ID_NEW_FLEX_GRID_SIZER
= wxNewId()
815 ID_NEW_SPACER
= wxNewId()
816 ID_NEW_TOOL_BAR
= wxNewId()
817 ID_NEW_TOOL
= wxNewId()
818 ID_NEW_MENU
= wxNewId()
819 ID_NEW_MENU_ITEM
= wxNewId()
820 ID_NEW_SEPARATOR
= wxNewId()
821 ID_NEW_LAST
= wxNewId()
822 ID_EXPAND
= wxNewId()
824 def __init__(self
, parent
):
825 self
.ID_DELETE
= parent
.ID_DELETE
826 EVT_MENU_RANGE(parent
, self
.ID_NEW_PANEL
,
827 self
.ID_NEW_LAST
, parent
.OnCreate
)
828 EVT_MENU(parent
, self
.ID_EXPAND
, parent
.OnExpand
)
829 # We connect to tree, but process in frame
830 EVT_MENU_HIGHLIGHT_ALL(tree
, parent
.OnPullDownHighlight
)
832 ################################################################################
834 class Frame(wxFrame
):
835 def __init__(self
, size
):
836 wxFrame
.__init
__(self
, None, -1, '', size
=size
)
837 self
.CreateStatusBar()
838 #icon = wxIconFromXPMData(images.getIconData())
839 icon
= wxIcon(os
.path
.join(sys
.path
[0], "xrced.ico"), wxBITMAP_TYPE_ICO
)
843 menuBar
= wxMenuBar()
846 menu
.Append(wxID_NEW
, '&New\tCtrl-N', 'New file')
847 menu
.Append(wxID_OPEN
, '&Open...\tCtrl-O', 'Open XRC file')
848 menu
.Append(wxID_SAVE
, '&Save\tCtrl-S', 'Save XRC file')
849 menu
.Append(wxID_SAVEAS
, 'Save &As...', 'Save XRC file under different name')
850 menu
.AppendSeparator()
851 menu
.Append(wxID_EXIT
, '&Quit\tCtrl-Q', 'Exit application')
852 menuBar
.Append(menu
, '&File')
855 menu
.Append(wxID_UNDO
, '&Undo\tCtrl-Z', 'Undo')
856 menu
.Append(wxID_REDO
, '&Redo\tCtrl-R', 'Redo')
857 menu
.AppendSeparator()
858 menu
.Append(wxID_CUT
, 'Cut\tCtrl-X', 'Cut to the clipboard')
859 menu
.Append(wxID_COPY
, '&Copy\tCtrl-C', 'Copy to the clipboard')
860 menu
.Append(wxID_PASTE
, '&Paste\tCtrl-V', 'Paste from the clipboard')
861 self
.ID_DELETE
= wxNewId()
862 menu
.Append(self
.ID_DELETE
, '&Delete\tCtrl-D', 'Delete object')
863 menuBar
.Append(menu
, '&Edit')
866 self
.ID_REFRESH
= wxNewId()
867 menu
.Append(self
.ID_REFRESH
, '&Refresh\tCtrl-R', 'Refresh view')
868 self
.ID_AUTO_REFRESH
= wxNewId()
869 menu
.Append(self
.ID_AUTO_REFRESH
, '&Auto-refresh\tCtrl-A',
870 'Toggle auto-refresh mode', true
)
871 menu
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
872 menuBar
.Append(menu
, '&View')
875 menu
.Append(wxID_ABOUT
, 'About...', 'About XCRed')
877 self
.ID_DEBUG_CMD
= wxNewId()
878 menu
.Append(self
.ID_DEBUG_CMD
, 'CMD', 'Python command line')
879 EVT_MENU(self
, self
.ID_DEBUG_CMD
, self
.OnDebugCMD
)
880 menuBar
.Append(menu
, '&Help')
882 self
.menuBar
= menuBar
883 self
.SetMenuBar(menuBar
)
886 tb
= self
.CreateToolBar(wxTB_HORIZONTAL | wxNO_BORDER | wxTB_FLAT
)
887 tb
.SetToolBitmapSize((24, 23))
888 tb
.AddSimpleTool(wxID_NEW
, images
.getNewBitmap(), 'New', 'New file')
889 tb
.AddSimpleTool(wxID_OPEN
, images
.getOpenBitmap(), 'Open', 'Open file')
890 tb
.AddSimpleTool(wxID_SAVE
, images
.getSaveBitmap(), 'Save', 'Save file')
892 tb
.AddSimpleTool(wxID_CUT
, images
.getCutBitmap(), 'Cut', 'Cut')
893 tb
.AddSimpleTool(wxID_COPY
, images
.getCopyBitmap(), 'Copy', 'Copy')
894 tb
.AddSimpleTool(wxID_PASTE
, images
.getPasteBitmap(), 'Paste', 'Paste')
896 tb
.AddSimpleTool(self
.ID_REFRESH
, images
.getRefreshBitmap(),
897 'Refresh', 'Refresh view')
898 tb
.AddSimpleTool(self
.ID_AUTO_REFRESH
, images
.getAutoRefreshBitmap(),
899 'Auto-refresh', 'Toggle auto-refresh mode', true
)
900 tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
905 EVT_MENU(self
, wxID_NEW
, self
.OnNew
)
906 EVT_MENU(self
, wxID_OPEN
, self
.OnOpen
)
907 EVT_MENU(self
, wxID_SAVE
, self
.OnSaveOrSaveAs
)
908 EVT_MENU(self
, wxID_SAVEAS
, self
.OnSaveOrSaveAs
)
909 EVT_MENU(self
, wxID_EXIT
, self
.OnExit
)
911 EVT_MENU(self
, wxID_UNDO
, self
.OnUndo
)
912 EVT_MENU(self
, wxID_REDO
, self
.OnRedo
)
913 EVT_MENU(self
, wxID_CUT
, self
.OnCut
)
914 EVT_MENU(self
, wxID_COPY
, self
.OnCopy
)
915 EVT_MENU(self
, wxID_PASTE
, self
.OnPaste
)
916 EVT_MENU(self
, self
.ID_DELETE
, self
.OnDelete
)
918 EVT_MENU(self
, self
.ID_REFRESH
, self
.OnRefresh
)
919 EVT_MENU(self
, self
.ID_AUTO_REFRESH
, self
.OnAutoRefresh
)
921 EVT_MENU(self
, wxID_ABOUT
, self
.OnAbout
)
924 EVT_UPDATE_UI(self
, wxID_CUT
, self
.OnUpdateUI
)
925 EVT_UPDATE_UI(self
, wxID_COPY
, self
.OnUpdateUI
)
926 EVT_UPDATE_UI(self
, wxID_PASTE
, self
.OnUpdateUI
)
927 EVT_UPDATE_UI(self
, self
.ID_DELETE
, self
.OnUpdateUI
)
930 sizer
= wxBoxSizer(wxVERTICAL
)
931 sizer
.Add(wxStaticLine(self
, -1), 0, wxEXPAND
)
932 splitter
= wxSplitterWindow(self
, -1, style
=wxSP_3DSASH
)
933 self
.splitter
= splitter
934 splitter
.SetMinimumPaneSize(100)
937 tree
= XML_Tree(splitter
, -1)
938 sys
.modules
['xxx'].tree
= tree
939 # Create panel for parameters
941 panel
= Panel(splitter
)
942 # Set plitter windows
943 splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
944 sizer
.Add(splitter
, 1, wxEXPAND
)
945 self
.SetAutoLayout(true
)
948 # Init pull-down menu data
950 pullDownMenu
= PullDownMenu(self
)
951 # Mapping from IDs to element names
953 pullDownMenu
.ID_NEW_PANEL
: 'wxPanel',
954 pullDownMenu
.ID_NEW_DIALOG
: 'wxDialog',
955 pullDownMenu
.ID_NEW_FRAME
: 'wxFrame',
956 pullDownMenu
.ID_NEW_TOOL_BAR
: 'wxToolBar',
957 pullDownMenu
.ID_NEW_TOOL
: 'tool',
958 pullDownMenu
.ID_NEW_MENU_BAR
: 'wxMenuBar',
959 pullDownMenu
.ID_NEW_MENU
: 'wxMenu',
960 pullDownMenu
.ID_NEW_MENU_ITEM
: 'wxMenuItem',
961 pullDownMenu
.ID_NEW_SEPARATOR
: 'separator',
963 pullDownMenu
.ID_NEW_STATIC_TEXT
: 'wxStaticText',
964 pullDownMenu
.ID_NEW_TEXT_CTRL
: 'wxTextCtrl',
966 pullDownMenu
.ID_NEW_BUTTON
: 'wxButton',
967 pullDownMenu
.ID_NEW_BITMAP_BUTTON
: 'wxBitmapButton',
968 pullDownMenu
.ID_NEW_RADIO_BUTTON
: 'wxRadioButton',
969 pullDownMenu
.ID_NEW_SPIN_BUTTON
: 'wxSpinButton',
971 pullDownMenu
.ID_NEW_STATIC_BOX
: 'wxStaticBox',
972 pullDownMenu
.ID_NEW_CHECK_BOX
: 'wxCheckBox',
973 pullDownMenu
.ID_NEW_RADIO_BOX
: 'wxRadioBox',
974 pullDownMenu
.ID_NEW_COMBO_BOX
: 'wxComboBox',
975 pullDownMenu
.ID_NEW_LIST_BOX
: 'wxListBox',
977 pullDownMenu
.ID_NEW_STATIC_LINE
: 'wxStaticLine',
978 pullDownMenu
.ID_NEW_STATIC_BITMAP
: 'wxStaticBitmap',
979 pullDownMenu
.ID_NEW_CHOICE
: 'wxChoice',
980 pullDownMenu
.ID_NEW_SLIDER
: 'wxSlider',
981 pullDownMenu
.ID_NEW_GAUGE
: 'wxGauge',
982 pullDownMenu
.ID_NEW_SCROLL_BAR
: 'wxScrollBar',
983 pullDownMenu
.ID_NEW_TREE_CTRL
: 'wxTreeCtrl',
984 pullDownMenu
.ID_NEW_LIST_CTRL
: 'wxListCtrl',
985 pullDownMenu
.ID_NEW_CHECK_LIST
: 'wxCheckList',
986 pullDownMenu
.ID_NEW_NOTEBOOK
: 'wxNotebook',
987 pullDownMenu
.ID_NEW_HTML_WINDOW
: 'wxHtmlWindow',
988 pullDownMenu
.ID_NEW_CALENDAR
: 'wxCalendar',
990 pullDownMenu
.ID_NEW_BOX_SIZER
: 'wxBoxSizer',
991 pullDownMenu
.ID_NEW_STATIC_BOX_SIZER
: 'wxStaticBoxSizer',
992 pullDownMenu
.ID_NEW_GRID_SIZER
: 'wxGridSizer',
993 pullDownMenu
.ID_NEW_FLEX_GRID_SIZER
: 'wxFlexGridSizer',
994 pullDownMenu
.ID_NEW_SPACER
: 'spacer',
996 pullDownMenu
.controls
= [
997 ['control', 'Various controls',
998 (pullDownMenu
.ID_NEW_STATIC_TEXT
, 'Label', 'Create static label'),
999 (pullDownMenu
.ID_NEW_STATIC_LINE
, 'Line', 'Create static line'),
1000 (pullDownMenu
.ID_NEW_TEXT_CTRL
, 'TextBox', 'Create text box control'),
1001 (pullDownMenu
.ID_NEW_CHOICE
, 'Choice', 'Create choice control'),
1002 (pullDownMenu
.ID_NEW_SLIDER
, 'Slider', 'Create slider control'),
1003 (pullDownMenu
.ID_NEW_GAUGE
, 'Gauge', 'Create gauge control'),
1004 (pullDownMenu
.ID_NEW_SCROLL_BAR
, 'ScrollBar', 'Create scroll bar'),
1005 (pullDownMenu
.ID_NEW_TREE_CTRL
, 'TreeCtrl', 'Create tree control'),
1006 (pullDownMenu
.ID_NEW_LIST_CTRL
, 'ListCtrl', 'Create list control'),
1007 (pullDownMenu
.ID_NEW_CHECK_LIST
, 'CheckList', 'Create check list control'),
1008 (pullDownMenu
.ID_NEW_HTML_WINDOW
, 'HtmlWindow', 'Create HTML window'),
1009 (pullDownMenu
.ID_NEW_CALENDAR
, 'Calendar', 'Create calendar control'),
1010 (pullDownMenu
.ID_NEW_PANEL
, 'Panel', 'Create panel'),
1011 (pullDownMenu
.ID_NEW_NOTEBOOK
, 'Notebook', 'Create notebook control'),
1013 ['button', 'Buttons',
1014 (pullDownMenu
.ID_NEW_BUTTON
, 'Button', 'Create button'),
1015 (pullDownMenu
.ID_NEW_BITMAP_BUTTON
, 'BitmapButton', 'Create bitmap button'),
1016 (pullDownMenu
.ID_NEW_RADIO_BUTTON
, 'RadioButton', 'Create radio button'),
1017 (pullDownMenu
.ID_NEW_SPIN_BUTTON
, 'SpinButton', 'Create spin button'),
1020 (pullDownMenu
.ID_NEW_STATIC_BOX
, 'StaticBox', 'Create static box'),
1021 (pullDownMenu
.ID_NEW_CHECK_BOX
, 'CheckBox', 'Create check box'),
1022 (pullDownMenu
.ID_NEW_RADIO_BOX
, 'RadioBox', 'Create radio box'),
1023 (pullDownMenu
.ID_NEW_COMBO_BOX
, 'ComboBox', 'Create combo box'),
1024 (pullDownMenu
.ID_NEW_LIST_BOX
, 'ListBox', 'Create list box'),
1027 (pullDownMenu
.ID_NEW_BOX_SIZER
, 'BoxSizer', 'Create box sizer'),
1028 (pullDownMenu
.ID_NEW_STATIC_BOX_SIZER
, 'StaticBoxSizer',
1029 'Create static box sizer'),
1030 (pullDownMenu
.ID_NEW_GRID_SIZER
, 'GridSizer', 'Create grid sizer'),
1031 (pullDownMenu
.ID_NEW_FLEX_GRID_SIZER
, 'FlexGridSizer',
1032 'Create flexgrid sizer'),
1033 (pullDownMenu
.ID_NEW_SPACER
, 'Spacer', 'Create spacer'),
1036 pullDownMenu
.menuControls
= [
1037 (pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu'),
1038 (pullDownMenu
.ID_NEW_MENU_ITEM
, 'MenuItem', 'Create menu item'),
1039 (pullDownMenu
.ID_NEW_SEPARATOR
, 'Separator', 'Create separator'),
1041 pullDownMenu
.toolBarControls
= [
1042 (pullDownMenu
.ID_NEW_TOOL
, 'Tool', 'Create tool'),
1043 (pullDownMenu
.ID_NEW_SEPARATOR
, 'Separator', 'Create separator'),
1050 EVT_IDLE(self
, self
.OnIdle
)
1051 EVT_CLOSE(self
, self
.OnCloseWindow
)
1053 def OnNew(self
, evt
):
1056 def OnOpen(self
, evt
):
1057 if not self
.AskSave(): return
1058 dlg
= wxFileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
),
1059 '', '*.xrc', wxOPEN | wxCHANGE_DIR
)
1060 if dlg
.ShowModal() == wxID_OK
:
1061 path
= dlg
.GetPath()
1062 self
.SetStatusText('Loading...')
1067 self
.SetStatusText('Ready')
1070 def OnSaveOrSaveAs(self
, evt
):
1071 if evt
.GetId() == wxID_SAVEAS
or not self
.dataFile
:
1072 if self
.dataFile
: defaultName
= ''
1073 else: defaultName
= 'UNTITLED.xrc'
1074 dlg
= wxFileDialog(self
, 'Save As', os
.path
.dirname(self
.dataFile
),
1075 defaultName
, '*.xrc',
1076 wxSAVE | wxOVERWRITE_PROMPT | wxCHANGE_DIR
)
1077 if dlg
.ShowModal() == wxID_OK
:
1078 path
= dlg
.GetPath()
1084 path
= self
.dataFile
1085 self
.SetStatusText('Saving...')
1089 self
.dataFile
= path
1091 self
.SetStatusText('Ready')
1093 def OnExit(self
, evt
):
1096 def OnUndo(self
, evt
):
1097 print '*** being implemented'
1098 print self
.lastOp
, self
.undo
1099 if self
.lastOp
== 'DELETE':
1100 parent
, prev
, elem
= self
.undo
1102 xxx
= MakeXXXFromDOM(tree
.GetPyData(parent
).treeObject(), elem
)
1103 item
= tree
.InsertItem( parent
, prev
, xxx
.treeObject().className
,
1104 data
=wxTreeItemData(xxx
) )
1106 def OnRedo(self
, evt
):
1107 print '*** being implemented'
1109 def OnCut(self
, evt
):
1110 selected
= tree
.GetSelection()
1113 self
.undo
= [tree
.GetItemParent(selected
), tree
.GetPrevSibling(selected
)]
1117 # If deleting top-level item, delete testWin
1118 if selected
== testWin
.item
:
1122 # Remove highlight, update testWin
1123 if tree
.GetItemAncestor(selected
) == testWin
.item
:
1124 if testWin
.highLight
: testWin
.highLight
.Remove()
1125 tree
.needUpdate
= true
1126 self
.clipboard
= tree
.RemoveLeaf(selected
)
1127 tree
.pendingHighLight
= None
1130 self
.modified
= true
1132 def OnCopy(self
, evt
):
1133 selected
= tree
.GetSelection()
1134 xxx
= tree
.GetPyData(selected
)
1135 self
.clipboard
= xxx
.element
.cloneNode(true
)
1137 def OnPaste(self
, evt
):
1138 selected
= tree
.GetSelection()
1139 appendChild
= not tree
.NeedInsert(selected
)
1140 xxx
= tree
.GetPyData(selected
)
1142 # If has next item, insert, else append to parent
1143 nextItem
= tree
.GetNextSibling(selected
)
1145 # Insert before nextItem
1146 parentLeaf
= tree
.GetItemParent(selected
)
1147 else: # last child: change selected to parent
1149 selected
= tree
.GetItemParent(selected
)
1150 # Expanded container (must have children)
1151 elif tree
.IsExpanded(selected
) and tree
.ItemHasChildren(selected
):
1153 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
1154 parentLeaf
= selected
1155 # Parent should be tree element or None
1157 parent
= tree
.GetPyData(selected
)
1159 parent
= tree
.GetPyData(parentLeaf
)
1160 if parent
and parent
.hasChild
: parent
= parent
.child
1162 # Create a copy of clipboard element
1163 elem
= self
.clipboard
.cloneNode(true
)
1164 # Tempopary xxx object to test things
1165 xxx
= MakeXXXFromDOM(parent
, elem
)
1166 className
= xxx
.treeObject().className
1167 # Check parent and child relationships
1168 # Parent is sizer or notebook, child is of wrong class or
1169 # parent is normal window, child is child container: detach child
1170 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
1171 if not parent
and isChildContainer
or \
1172 (parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
1173 (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
1174 (not parent
.isSizer
and not isinstance(parent
, xxxNotebook
) and \
1176 if isChildContainer
:
1177 elem
.removeChild(xxx
.child
.element
) # detach child
1178 elem
.unlink() # delete child container
1179 elem
= xxx
.child
.element
# replace
1180 # This should help garbage collection (!!! maybe not needed?)
1181 xxx
.child
.parent
= None
1184 # Parent is sizer or notebook, child is not child container
1185 if parent
.isSizer
and not isChildContainer
and \
1186 not isinstance(xxx
, xxxSpacer
):
1187 # Create sizer item element
1188 sizerItemElem
= MakeEmptyDOM('sizeritem')
1189 sizerItemElem
.appendChild(elem
)
1190 elem
= sizerItemElem
1191 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
1192 pageElem
= MakeEmptyDOM('notebookpage')
1193 pageElem
.appendChild(elem
)
1195 xxx
= MakeXXXFromDOM(parent
, elem
)
1196 # Figure out if we must append a new child or sibling
1198 if parent
: node
= parent
.element
1199 else: node
= tree
.mainNode
1200 node
.appendChild(elem
)
1201 newItem
= tree
.AppendItem(selected
, xxx
.treeName(), image
=xxx
.treeImage(),
1202 data
=wxTreeItemData(xxx
))
1204 node
= tree
.GetPyData(nextItem
).element
1206 elemParent
= parent
.element
1208 elemParent
= tree
.mainNode
1209 elemParent
.insertBefore(elem
, node
)
1210 # Inserting before is difficult, se we insert after or first child
1211 newItem
= tree
.InsertItem(parentLeaf
, selected
, xxx
.treeName(),
1212 image
=xxx
.treeImage(), data
=wxTreeItemData(xxx
))
1213 # Add children items
1215 treeObj
= xxx
.treeObject()
1216 for n
in treeObj
.element
.childNodes
:
1218 tree
.AddNode(newItem
, treeObj
, n
)
1219 # Scroll to show new item
1220 tree
.EnsureVisible(newItem
)
1221 tree
.SelectItem(newItem
)
1222 if not tree
.IsVisible(newItem
):
1223 tree
.ScrollTo(newItem
)
1226 if testWin
and tree
.GetItemAncestor(newItem
) == testWin
.item
:
1227 if conf
.autoRefresh
:
1228 tree
.needUpdate
= true
1229 tree
.pendingHighLight
= newItem
1231 tree
.pendingHighLight
= None
1232 self
.modified
= true
1234 def OnDelete(self
, evt
):
1235 selected
= tree
.GetSelection()
1237 self
.lastOp
= 'DELETE'
1238 self
.undo
= [tree
.GetItemParent(selected
), tree
.GetPrevSibling(selected
)]
1242 # If deleting top-level item, delete testWin
1243 if selected
== testWin
.item
:
1247 # Remove highlight, update testWin
1248 if tree
.GetItemAncestor(selected
) == testWin
.item
:
1249 if testWin
.highLight
: testWin
.highLight
.Remove()
1250 tree
.needUpdate
= true
1251 xnode
= tree
.RemoveLeaf(selected
)
1252 self
.undo
.append(xnode
.cloneNode(true
))
1254 tree
.pendingHighLight
= None
1257 self
.modified
= true
1259 def OnRefresh(self
, evt
):
1260 # If modified, apply first
1261 selection
= tree
.GetSelection()
1262 if selection
.IsOk():
1263 xxx
= tree
.GetPyData(selection
)
1264 if xxx
and panel
.IsModified():
1265 tree
.Apply(xxx
, selection
)
1268 tree
.CreateTestWin(testWin
.item
)
1269 tree
.needUpdate
= false
1271 def OnAutoRefresh(self
, evt
):
1272 conf
.autoRefresh
= evt
.IsChecked()
1273 self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1274 self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1276 def OnAbout(self
, evt
):
1277 str = '%s %s\n\nRoman Rolinsky <rolinsky@mema.ucl.ac.be>' % \
1279 dlg
= wxMessageDialog(self
, str, 'About ' + progname
, wxOK | wxCENTRE
)
1283 # Simple emulation of python command line
1284 def OnDebugCMD(self
, evt
):
1287 exec raw_input('C:\> ')
1292 (etype
, value
, tb
) =sys
.exc_info()
1293 tblist
=traceback
.extract_tb(tb
)[1:]
1294 msg
=string
.join(traceback
.format_exception_only(etype
, value
)
1295 +traceback
.format_list(tblist
))
1298 def OnCreate(self
, evt
):
1299 selected
= tree
.GetSelection()
1300 appendChild
= not tree
.NeedInsert(selected
)
1301 xxx
= tree
.GetPyData(selected
)
1303 # If has next item, insert, else append to parent
1304 nextItem
= tree
.GetNextSibling(selected
)
1306 # Insert before nextItem
1307 parentLeaf
= tree
.GetItemParent(selected
)
1308 else: # last child: change selected to parent
1310 selected
= tree
.GetItemParent(selected
)
1311 # Expanded container (must have children)
1312 elif tree
.IsExpanded(selected
) and tree
.ItemHasChildren(selected
):
1314 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
1315 parentLeaf
= selected
1316 # Parent should be tree element or None
1318 parent
= tree
.GetPyData(selected
)
1320 parent
= tree
.GetPyData(parentLeaf
)
1321 if parent
and parent
.hasChild
: parent
= parent
.child
1324 className
= self
.createMap
[evt
.GetId()]
1325 xxx
= MakeEmptyXXX(parent
, className
)
1326 # Figure out if we must append a new child or sibling
1329 if parent
: node
= parent
.element
1330 else: node
= tree
.mainNode
1331 # Insert newline for debug purposes
1332 node
.appendChild(tree
.dom
.createTextNode('\n'))
1333 node
.appendChild(elem
)
1334 newItem
= tree
.AppendItem(selected
, xxx
.treeName(), image
=xxx
.treeImage(),
1335 data
=wxTreeItemData(xxx
))
1337 node
= tree
.GetPyData(nextItem
).element
1339 elemParent
= parent
.element
1341 elemParent
= tree
.mainNode
1342 elemParent
.insertBefore(tree
.dom
.createTextNode('\n'), node
)
1343 elemParent
.insertBefore(elem
, node
)
1344 # Inserting before is difficult, se we insert after or first child
1345 newItem
= tree
.InsertItem(parentLeaf
, selected
,
1346 xxx
.treeName(), image
=xxx
.treeImage(),
1347 data
=wxTreeItemData(xxx
))
1348 tree
.EnsureVisible(newItem
)
1349 tree
.SelectItem(newItem
)
1350 if not tree
.IsVisible(newItem
):
1351 tree
.ScrollTo(newItem
)
1354 if testWin
and tree
.GetItemAncestor(newItem
) == testWin
.item
:
1355 if conf
.autoRefresh
:
1356 tree
.needUpdate
= true
1357 tree
.pendingHighLight
= newItem
1359 tree
.pendingHighLight
= None
1361 def OnExpand(self
, evt
):
1362 if tree
.GetSelection().IsOk():
1363 tree
.ExpandAll(tree
.GetSelection())
1365 tree
.ExpandAll(tree
.GetRootItem())
1367 def OnPullDownHighlight(self
, evt
):
1368 menuId
= evt
.GetMenuId()
1370 menu
= evt
.GetEventObject()
1371 help = menu
.GetHelpString(menuId
)
1372 self
.SetStatusText(help)
1374 self
.SetStatusText('')
1376 def OnUpdateUI(self
, evt
):
1377 if evt
.GetId() in [wxID_CUT
, wxID_COPY
, self
.ID_DELETE
]:
1378 enable
= tree
.GetSelection().IsOk() and \
1379 tree
.GetSelection() != tree
.GetRootItem()
1381 elif evt
.GetId() == wxID_PASTE
:
1382 enable
= tree
.GetSelection().IsOk() and \
1383 tree
.GetSelection() != tree
.GetRootItem() and \
1384 self
.clipboard
!= None
1387 def OnIdle(self
, evt
):
1389 if conf
.autoRefresh
:
1392 tree
.CreateTestWin(testWin
.item
)
1393 tree
.needUpdate
= false
1394 elif tree
.pendingHighLight
:
1395 tree
.HighLight(tree
.pendingHighLight
)
1399 def OnCloseWindow(self
, evt
):
1400 if not self
.AskSave(): return
1401 if testWin
: testWin
.Destroy()
1402 # Destroy cached windows
1403 for w
in panel
.styleCache
.values(): w
.Destroy()
1404 conf
.width
, conf
.height
= self
.GetSize()
1405 conf
.sashPos
= self
.splitter
.GetSashPosition()
1410 self
.clipboard
= None
1411 self
.modified
= false
1412 panel
.SetModified(false
)
1419 self
.SetTitle(progname
)
1421 def Open(self
, path
):
1422 # Try to read the file
1427 dom
= minidom
.parse(path
)
1429 self
.dataFile
= path
1430 self
.SetTitle(progname
+ ': ' + os
.path
.basename(path
))
1432 wxLogError('Error reading file: ' + path
)
1435 def Save(self
, path
):
1437 self
.OnRefresh(wxCommandEvent())
1438 memFile
= MemoryFile(path
)
1439 tree
.dom
.writexml(memFile
)
1441 self
.modified
= false
1442 panel
.SetModified(false
)
1444 wxLogError('Error writing file: ' + path
)
1448 if not (self
.modified
or panel
.IsModified()): return true
1449 flags
= wxICON_EXCLAMATION | wxYES_NO | wxCANCEL | wxCENTRE
1450 dlg
= wxMessageDialog( self
, 'File is modified. Save before exit?',
1451 'Save before too late?', flags
)
1452 say
= dlg
.ShowModal()
1455 self
.OnSaveOrSaveAs(wxCommandEvent(wxID_SAVE
))
1456 # If save was successful, modified flag is unset
1457 if not self
.modified
: return true
1458 elif say
== wxID_NO
:
1459 self
.modified
= false
1460 panel
.SetModified(false
)
1464 ################################################################################
1468 self
.SetAppName("xrced")
1471 # !!! wxConfigBase_Get doesn't seem to work
1472 conf
= wxConfig(style
=wxCONFIG_USE_LOCAL_FILE
)
1473 conf
.autoRefresh
= conf
.ReadInt('autorefresh', true
)
1474 size
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600)
1475 conf
.sashPos
= conf
.ReadInt('sashPos', 200)
1477 wxFileSystem_AddHandler(wxMemoryFSHandler())
1478 wxInitAllImageHandlers()
1481 frame
= self
.frame
= Frame(size
)
1482 self
.frame
.Show(true
)
1483 # Load resources from XRC file (!!! should be transformed to .py later?)
1484 sys
.modules
['params'].frame
= frame
1485 frame
.res
= wxXmlResource('')
1486 frame
.res
.Load(os
.path
.join(sys
.path
[0], 'xrced.xrc'))
1491 wc
= wxConfigBase_Get()
1492 wc
.WriteInt('autorefresh', conf
.autoRefresh
)
1493 wc
.WriteInt('width', conf
.width
)
1494 wc
.WriteInt('height', conf
.height
)
1495 wc
.WriteInt('sashPos', conf
.sashPos
)
1503 if __name__
== '__main__':