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 self
.SetIcon(wxIconFromXPMData(images
.getIconData()))
841 menuBar
= wxMenuBar()
844 menu
.Append(wxID_NEW
, '&New\tCtrl-N', 'New file')
845 menu
.Append(wxID_OPEN
, '&Open...\tCtrl-O', 'Open XRC file')
846 menu
.Append(wxID_SAVE
, '&Save\tCtrl-S', 'Save XRC file')
847 menu
.Append(wxID_SAVEAS
, 'Save &As...', 'Save XRC file under different name')
848 menu
.AppendSeparator()
849 menu
.Append(wxID_EXIT
, '&Quit\tCtrl-Q', 'Exit application')
850 menuBar
.Append(menu
, '&File')
853 menu
.Append(wxID_UNDO
, '&Undo\tCtrl-Z', 'Undo')
854 menu
.Append(wxID_REDO
, '&Redo\tCtrl-R', 'Redo')
855 menu
.AppendSeparator()
856 menu
.Append(wxID_CUT
, 'Cut\tCtrl-X', 'Cut to the clipboard')
857 menu
.Append(wxID_COPY
, '&Copy\tCtrl-C', 'Copy to the clipboard')
858 menu
.Append(wxID_PASTE
, '&Paste\tCtrl-V', 'Paste from the clipboard')
859 self
.ID_DELETE
= wxNewId()
860 menu
.Append(self
.ID_DELETE
, '&Delete\tCtrl-D', 'Delete object')
861 menuBar
.Append(menu
, '&Edit')
864 self
.ID_REFRESH
= wxNewId()
865 menu
.Append(self
.ID_REFRESH
, '&Refresh\tCtrl-R', 'Refresh view')
866 self
.ID_AUTO_REFRESH
= wxNewId()
867 menu
.Append(self
.ID_AUTO_REFRESH
, '&Auto-refresh\tCtrl-A',
868 'Toggle auto-refresh mode', true
)
869 menu
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
870 menuBar
.Append(menu
, '&View')
873 menu
.Append(wxID_ABOUT
, 'About...', 'About XCRed')
875 self
.ID_DEBUG_CMD
= wxNewId()
876 menu
.Append(self
.ID_DEBUG_CMD
, 'CMD', 'Python command line')
877 EVT_MENU(self
, self
.ID_DEBUG_CMD
, self
.OnDebugCMD
)
878 menuBar
.Append(menu
, '&Help')
880 self
.menuBar
= menuBar
881 self
.SetMenuBar(menuBar
)
884 tb
= self
.CreateToolBar(wxTB_HORIZONTAL | wxNO_BORDER | wxTB_FLAT
)
885 tb
.SetToolBitmapSize((24, 23))
886 tb
.AddSimpleTool(wxID_NEW
, images
.getNewBitmap(), 'New', 'New file')
887 tb
.AddSimpleTool(wxID_OPEN
, images
.getOpenBitmap(), 'Open', 'Open file')
888 tb
.AddSimpleTool(wxID_SAVE
, images
.getSaveBitmap(), 'Save', 'Save file')
890 tb
.AddSimpleTool(wxID_CUT
, images
.getCutBitmap(), 'Cut', 'Cut')
891 tb
.AddSimpleTool(wxID_COPY
, images
.getCopyBitmap(), 'Copy', 'Copy')
892 tb
.AddSimpleTool(wxID_PASTE
, images
.getPasteBitmap(), 'Paste', 'Paste')
894 tb
.AddSimpleTool(self
.ID_REFRESH
, images
.getRefreshBitmap(),
895 'Refresh', 'Refresh view')
896 tb
.AddSimpleTool(self
.ID_AUTO_REFRESH
, images
.getAutoRefreshBitmap(),
897 'Auto-refresh', 'Toggle auto-refresh mode', true
)
898 tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
903 EVT_MENU(self
, wxID_NEW
, self
.OnNew
)
904 EVT_MENU(self
, wxID_OPEN
, self
.OnOpen
)
905 EVT_MENU(self
, wxID_SAVE
, self
.OnSaveOrSaveAs
)
906 EVT_MENU(self
, wxID_SAVEAS
, self
.OnSaveOrSaveAs
)
907 EVT_MENU(self
, wxID_EXIT
, self
.OnExit
)
909 EVT_MENU(self
, wxID_UNDO
, self
.OnUndo
)
910 EVT_MENU(self
, wxID_REDO
, self
.OnRedo
)
911 EVT_MENU(self
, wxID_CUT
, self
.OnCut
)
912 EVT_MENU(self
, wxID_COPY
, self
.OnCopy
)
913 EVT_MENU(self
, wxID_PASTE
, self
.OnPaste
)
914 EVT_MENU(self
, self
.ID_DELETE
, self
.OnDelete
)
916 EVT_MENU(self
, self
.ID_REFRESH
, self
.OnRefresh
)
917 EVT_MENU(self
, self
.ID_AUTO_REFRESH
, self
.OnAutoRefresh
)
919 EVT_MENU(self
, wxID_ABOUT
, self
.OnAbout
)
922 EVT_UPDATE_UI(self
, wxID_CUT
, self
.OnUpdateUI
)
923 EVT_UPDATE_UI(self
, wxID_COPY
, self
.OnUpdateUI
)
924 EVT_UPDATE_UI(self
, wxID_PASTE
, self
.OnUpdateUI
)
925 EVT_UPDATE_UI(self
, self
.ID_DELETE
, self
.OnUpdateUI
)
928 sizer
= wxBoxSizer(wxVERTICAL
)
929 sizer
.Add(wxStaticLine(self
, -1), 0, wxEXPAND
)
930 splitter
= wxSplitterWindow(self
, -1, style
=wxSP_3DSASH
)
931 self
.splitter
= splitter
932 splitter
.SetMinimumPaneSize(100)
935 tree
= XML_Tree(splitter
, -1)
936 sys
.modules
['xxx'].tree
= tree
937 # Create panel for parameters
939 panel
= Panel(splitter
)
940 # Set plitter windows
941 splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
942 sizer
.Add(splitter
, 1, wxEXPAND
)
943 self
.SetAutoLayout(true
)
946 # Init pull-down menu data
948 pullDownMenu
= PullDownMenu(self
)
949 # Mapping from IDs to element names
951 pullDownMenu
.ID_NEW_PANEL
: 'wxPanel',
952 pullDownMenu
.ID_NEW_DIALOG
: 'wxDialog',
953 pullDownMenu
.ID_NEW_FRAME
: 'wxFrame',
954 pullDownMenu
.ID_NEW_TOOL_BAR
: 'wxToolBar',
955 pullDownMenu
.ID_NEW_TOOL
: 'tool',
956 pullDownMenu
.ID_NEW_MENU_BAR
: 'wxMenuBar',
957 pullDownMenu
.ID_NEW_MENU
: 'wxMenu',
958 pullDownMenu
.ID_NEW_MENU_ITEM
: 'wxMenuItem',
959 pullDownMenu
.ID_NEW_SEPARATOR
: 'separator',
961 pullDownMenu
.ID_NEW_STATIC_TEXT
: 'wxStaticText',
962 pullDownMenu
.ID_NEW_TEXT_CTRL
: 'wxTextCtrl',
964 pullDownMenu
.ID_NEW_BUTTON
: 'wxButton',
965 pullDownMenu
.ID_NEW_BITMAP_BUTTON
: 'wxBitmapButton',
966 pullDownMenu
.ID_NEW_RADIO_BUTTON
: 'wxRadioButton',
967 pullDownMenu
.ID_NEW_SPIN_BUTTON
: 'wxSpinButton',
969 pullDownMenu
.ID_NEW_STATIC_BOX
: 'wxStaticBox',
970 pullDownMenu
.ID_NEW_CHECK_BOX
: 'wxCheckBox',
971 pullDownMenu
.ID_NEW_RADIO_BOX
: 'wxRadioBox',
972 pullDownMenu
.ID_NEW_COMBO_BOX
: 'wxComboBox',
973 pullDownMenu
.ID_NEW_LIST_BOX
: 'wxListBox',
975 pullDownMenu
.ID_NEW_STATIC_LINE
: 'wxStaticLine',
976 pullDownMenu
.ID_NEW_STATIC_BITMAP
: 'wxStaticBitmap',
977 pullDownMenu
.ID_NEW_CHOICE
: 'wxChoice',
978 pullDownMenu
.ID_NEW_SLIDER
: 'wxSlider',
979 pullDownMenu
.ID_NEW_GAUGE
: 'wxGauge',
980 pullDownMenu
.ID_NEW_SCROLL_BAR
: 'wxScrollBar',
981 pullDownMenu
.ID_NEW_TREE_CTRL
: 'wxTreeCtrl',
982 pullDownMenu
.ID_NEW_LIST_CTRL
: 'wxListCtrl',
983 pullDownMenu
.ID_NEW_CHECK_LIST
: 'wxCheckList',
984 pullDownMenu
.ID_NEW_NOTEBOOK
: 'wxNotebook',
985 pullDownMenu
.ID_NEW_HTML_WINDOW
: 'wxHtmlWindow',
986 pullDownMenu
.ID_NEW_CALENDAR
: 'wxCalendar',
988 pullDownMenu
.ID_NEW_BOX_SIZER
: 'wxBoxSizer',
989 pullDownMenu
.ID_NEW_STATIC_BOX_SIZER
: 'wxStaticBoxSizer',
990 pullDownMenu
.ID_NEW_GRID_SIZER
: 'wxGridSizer',
991 pullDownMenu
.ID_NEW_FLEX_GRID_SIZER
: 'wxFlexGridSizer',
992 pullDownMenu
.ID_NEW_SPACER
: 'spacer',
994 pullDownMenu
.controls
= [
995 ['control', 'Various controls',
996 (pullDownMenu
.ID_NEW_STATIC_TEXT
, 'Label', 'Create static label'),
997 (pullDownMenu
.ID_NEW_STATIC_LINE
, 'Line', 'Create static line'),
998 (pullDownMenu
.ID_NEW_TEXT_CTRL
, 'TextBox', 'Create text box control'),
999 (pullDownMenu
.ID_NEW_CHOICE
, 'Choice', 'Create choice control'),
1000 (pullDownMenu
.ID_NEW_SLIDER
, 'Slider', 'Create slider control'),
1001 (pullDownMenu
.ID_NEW_GAUGE
, 'Gauge', 'Create gauge control'),
1002 (pullDownMenu
.ID_NEW_SCROLL_BAR
, 'ScrollBar', 'Create scroll bar'),
1003 (pullDownMenu
.ID_NEW_TREE_CTRL
, 'TreeCtrl', 'Create tree control'),
1004 (pullDownMenu
.ID_NEW_LIST_CTRL
, 'ListCtrl', 'Create list control'),
1005 (pullDownMenu
.ID_NEW_CHECK_LIST
, 'CheckList', 'Create check list control'),
1006 (pullDownMenu
.ID_NEW_HTML_WINDOW
, 'HtmlWindow', 'Create HTML window'),
1007 (pullDownMenu
.ID_NEW_CALENDAR
, 'Calendar', 'Create calendar control'),
1008 (pullDownMenu
.ID_NEW_PANEL
, 'Panel', 'Create panel'),
1009 (pullDownMenu
.ID_NEW_NOTEBOOK
, 'Notebook', 'Create notebook control'),
1011 ['button', 'Buttons',
1012 (pullDownMenu
.ID_NEW_BUTTON
, 'Button', 'Create button'),
1013 (pullDownMenu
.ID_NEW_BITMAP_BUTTON
, 'BitmapButton', 'Create bitmap button'),
1014 (pullDownMenu
.ID_NEW_RADIO_BUTTON
, 'RadioButton', 'Create radio button'),
1015 (pullDownMenu
.ID_NEW_SPIN_BUTTON
, 'SpinButton', 'Create spin button'),
1018 (pullDownMenu
.ID_NEW_STATIC_BOX
, 'StaticBox', 'Create static box'),
1019 (pullDownMenu
.ID_NEW_CHECK_BOX
, 'CheckBox', 'Create check box'),
1020 (pullDownMenu
.ID_NEW_RADIO_BOX
, 'RadioBox', 'Create radio box'),
1021 (pullDownMenu
.ID_NEW_COMBO_BOX
, 'ComboBox', 'Create combo box'),
1022 (pullDownMenu
.ID_NEW_LIST_BOX
, 'ListBox', 'Create list box'),
1025 (pullDownMenu
.ID_NEW_BOX_SIZER
, 'BoxSizer', 'Create box sizer'),
1026 (pullDownMenu
.ID_NEW_STATIC_BOX_SIZER
, 'StaticBoxSizer',
1027 'Create static box sizer'),
1028 (pullDownMenu
.ID_NEW_GRID_SIZER
, 'GridSizer', 'Create grid sizer'),
1029 (pullDownMenu
.ID_NEW_FLEX_GRID_SIZER
, 'FlexGridSizer',
1030 'Create flexgrid sizer'),
1031 (pullDownMenu
.ID_NEW_SPACER
, 'Spacer', 'Create spacer'),
1034 pullDownMenu
.menuControls
= [
1035 (pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu'),
1036 (pullDownMenu
.ID_NEW_MENU_ITEM
, 'MenuItem', 'Create menu item'),
1037 (pullDownMenu
.ID_NEW_SEPARATOR
, 'Separator', 'Create separator'),
1039 pullDownMenu
.toolBarControls
= [
1040 (pullDownMenu
.ID_NEW_TOOL
, 'Tool', 'Create tool'),
1041 (pullDownMenu
.ID_NEW_SEPARATOR
, 'Separator', 'Create separator'),
1048 EVT_IDLE(self
, self
.OnIdle
)
1049 EVT_CLOSE(self
, self
.OnCloseWindow
)
1051 def OnNew(self
, evt
):
1054 def OnOpen(self
, evt
):
1055 if not self
.AskSave(): return
1056 dlg
= wxFileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
),
1057 '', '*.xrc', wxOPEN | wxCHANGE_DIR
)
1058 if dlg
.ShowModal() == wxID_OK
:
1059 path
= dlg
.GetPath()
1060 self
.SetStatusText('Loading...')
1065 self
.SetStatusText('Ready')
1068 def OnSaveOrSaveAs(self
, evt
):
1069 if evt
.GetId() == wxID_SAVEAS
or not self
.dataFile
:
1070 if self
.dataFile
: defaultName
= ''
1071 else: defaultName
= 'UNTITLED.xrc'
1072 dlg
= wxFileDialog(self
, 'Save As', os
.path
.dirname(self
.dataFile
),
1073 defaultName
, '*.xrc',
1074 wxSAVE | wxOVERWRITE_PROMPT | wxCHANGE_DIR
)
1075 if dlg
.ShowModal() == wxID_OK
:
1076 path
= dlg
.GetPath()
1082 path
= self
.dataFile
1083 self
.SetStatusText('Saving...')
1087 self
.dataFile
= path
1089 self
.SetStatusText('Ready')
1091 def OnExit(self
, evt
):
1094 def OnUndo(self
, evt
):
1095 print '*** being implemented'
1096 print self
.lastOp
, self
.undo
1097 if self
.lastOp
== 'DELETE':
1098 parent
, prev
, elem
= self
.undo
1100 xxx
= MakeXXXFromDOM(tree
.GetPyData(parent
).treeObject(), elem
)
1101 item
= tree
.InsertItem( parent
, prev
, xxx
.treeObject().className
,
1102 data
=wxTreeItemData(xxx
) )
1104 def OnRedo(self
, evt
):
1105 print '*** being implemented'
1107 def OnCut(self
, evt
):
1108 selected
= tree
.GetSelection()
1111 self
.undo
= [tree
.GetItemParent(selected
), tree
.GetPrevSibling(selected
)]
1115 # If deleting top-level item, delete testWin
1116 if selected
== testWin
.item
:
1120 # Remove highlight, update testWin
1121 if tree
.GetItemAncestor(selected
) == testWin
.item
:
1122 if testWin
.highLight
: testWin
.highLight
.Remove()
1123 tree
.needUpdate
= true
1124 self
.clipboard
= tree
.RemoveLeaf(selected
)
1125 tree
.pendingHighLight
= None
1128 self
.modified
= true
1130 def OnCopy(self
, evt
):
1131 selected
= tree
.GetSelection()
1132 xxx
= tree
.GetPyData(selected
)
1133 self
.clipboard
= xxx
.element
.cloneNode(true
)
1135 def OnPaste(self
, evt
):
1136 selected
= tree
.GetSelection()
1137 appendChild
= not tree
.NeedInsert(selected
)
1138 xxx
= tree
.GetPyData(selected
)
1140 # If has next item, insert, else append to parent
1141 nextItem
= tree
.GetNextSibling(selected
)
1143 # Insert before nextItem
1144 parentLeaf
= tree
.GetItemParent(selected
)
1145 else: # last child: change selected to parent
1147 selected
= tree
.GetItemParent(selected
)
1148 # Expanded container (must have children)
1149 elif tree
.IsExpanded(selected
) and tree
.ItemHasChildren(selected
):
1151 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
1152 parentLeaf
= selected
1153 # Parent should be tree element or None
1155 parent
= tree
.GetPyData(selected
)
1157 parent
= tree
.GetPyData(parentLeaf
)
1158 if parent
and parent
.hasChild
: parent
= parent
.child
1160 # Create a copy of clipboard element
1161 elem
= self
.clipboard
.cloneNode(true
)
1162 # Tempopary xxx object to test things
1163 xxx
= MakeXXXFromDOM(parent
, elem
)
1164 className
= xxx
.treeObject().className
1165 # Check parent and child relationships
1166 # Parent is sizer or notebook, child is of wrong class or
1167 # parent is normal window, child is child container: detach child
1168 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
1169 if not parent
and isChildContainer
or \
1170 (parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
1171 (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
1172 (not parent
.isSizer
and not isinstance(parent
, xxxNotebook
) and \
1174 if isChildContainer
:
1175 elem
.removeChild(xxx
.child
.element
) # detach child
1176 elem
.unlink() # delete child container
1177 elem
= xxx
.child
.element
# replace
1178 # This should help garbage collection (!!! maybe not needed?)
1179 xxx
.child
.parent
= None
1182 # Parent is sizer or notebook, child is not child container
1183 if parent
.isSizer
and not isChildContainer
and \
1184 not isinstance(xxx
, xxxSpacer
):
1185 # Create sizer item element
1186 sizerItemElem
= MakeEmptyDOM('sizeritem')
1187 sizerItemElem
.appendChild(elem
)
1188 elem
= sizerItemElem
1189 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
1190 pageElem
= MakeEmptyDOM('notebookpage')
1191 pageElem
.appendChild(elem
)
1193 xxx
= MakeXXXFromDOM(parent
, elem
)
1194 # Figure out if we must append a new child or sibling
1196 if parent
: node
= parent
.element
1197 else: node
= tree
.mainNode
1198 node
.appendChild(elem
)
1199 newItem
= tree
.AppendItem(selected
, xxx
.treeName(), image
=xxx
.treeImage(),
1200 data
=wxTreeItemData(xxx
))
1202 node
= tree
.GetPyData(nextItem
).element
1204 elemParent
= parent
.element
1206 elemParent
= tree
.mainNode
1207 elemParent
.insertBefore(elem
, node
)
1208 # Inserting before is difficult, se we insert after or first child
1209 newItem
= tree
.InsertItem(parentLeaf
, selected
, xxx
.treeName(),
1210 image
=xxx
.treeImage(), data
=wxTreeItemData(xxx
))
1211 # Add children items
1213 treeObj
= xxx
.treeObject()
1214 for n
in treeObj
.element
.childNodes
:
1216 tree
.AddNode(newItem
, treeObj
, n
)
1217 # Scroll to show new item
1218 tree
.EnsureVisible(newItem
)
1219 tree
.SelectItem(newItem
)
1220 if not tree
.IsVisible(newItem
):
1221 tree
.ScrollTo(newItem
)
1224 if testWin
and tree
.GetItemAncestor(newItem
) == testWin
.item
:
1225 if conf
.autoRefresh
:
1226 tree
.needUpdate
= true
1227 tree
.pendingHighLight
= newItem
1229 tree
.pendingHighLight
= None
1230 self
.modified
= true
1232 def OnDelete(self
, evt
):
1233 selected
= tree
.GetSelection()
1235 self
.lastOp
= 'DELETE'
1236 self
.undo
= [tree
.GetItemParent(selected
), tree
.GetPrevSibling(selected
)]
1240 # If deleting top-level item, delete testWin
1241 if selected
== testWin
.item
:
1245 # Remove highlight, update testWin
1246 if tree
.GetItemAncestor(selected
) == testWin
.item
:
1247 if testWin
.highLight
: testWin
.highLight
.Remove()
1248 tree
.needUpdate
= true
1249 xnode
= tree
.RemoveLeaf(selected
)
1250 self
.undo
.append(xnode
.cloneNode(true
))
1252 tree
.pendingHighLight
= None
1255 self
.modified
= true
1257 def OnRefresh(self
, evt
):
1258 # If modified, apply first
1259 selection
= tree
.GetSelection()
1260 if selection
.IsOk():
1261 xxx
= tree
.GetPyData(selection
)
1262 if xxx
and panel
.IsModified():
1263 tree
.Apply(xxx
, selection
)
1266 tree
.CreateTestWin(testWin
.item
)
1267 tree
.needUpdate
= false
1269 def OnAutoRefresh(self
, evt
):
1270 conf
.autoRefresh
= evt
.IsChecked()
1271 self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1272 self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1274 def OnAbout(self
, evt
):
1275 str = '%s %s\n\nRoman Rolinsky <rolinsky@mema.ucl.ac.be>' % \
1277 dlg
= wxMessageDialog(self
, str, 'About ' + progname
, wxOK | wxCENTRE
)
1281 # Simple emulation of python command line
1282 def OnDebugCMD(self
, evt
):
1285 exec raw_input('C:\> ')
1290 (etype
, value
, tb
) =sys
.exc_info()
1291 tblist
=traceback
.extract_tb(tb
)[1:]
1292 msg
=string
.join(traceback
.format_exception_only(etype
, value
)
1293 +traceback
.format_list(tblist
))
1296 def OnCreate(self
, evt
):
1297 selected
= tree
.GetSelection()
1298 appendChild
= not tree
.NeedInsert(selected
)
1299 xxx
= tree
.GetPyData(selected
)
1301 # If has next item, insert, else append to parent
1302 nextItem
= tree
.GetNextSibling(selected
)
1304 # Insert before nextItem
1305 parentLeaf
= tree
.GetItemParent(selected
)
1306 else: # last child: change selected to parent
1308 selected
= tree
.GetItemParent(selected
)
1309 # Expanded container (must have children)
1310 elif tree
.IsExpanded(selected
) and tree
.ItemHasChildren(selected
):
1312 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
1313 parentLeaf
= selected
1314 # Parent should be tree element or None
1316 parent
= tree
.GetPyData(selected
)
1318 parent
= tree
.GetPyData(parentLeaf
)
1319 if parent
and parent
.hasChild
: parent
= parent
.child
1322 className
= self
.createMap
[evt
.GetId()]
1323 xxx
= MakeEmptyXXX(parent
, className
)
1324 # Figure out if we must append a new child or sibling
1327 if parent
: node
= parent
.element
1328 else: node
= tree
.mainNode
1329 # Insert newline for debug purposes
1330 node
.appendChild(tree
.dom
.createTextNode('\n'))
1331 node
.appendChild(elem
)
1332 newItem
= tree
.AppendItem(selected
, xxx
.treeName(), image
=xxx
.treeImage(),
1333 data
=wxTreeItemData(xxx
))
1335 node
= tree
.GetPyData(nextItem
).element
1337 elemParent
= parent
.element
1339 elemParent
= tree
.mainNode
1340 elemParent
.insertBefore(tree
.dom
.createTextNode('\n'), node
)
1341 elemParent
.insertBefore(elem
, node
)
1342 # Inserting before is difficult, se we insert after or first child
1343 newItem
= tree
.InsertItem(parentLeaf
, selected
,
1344 xxx
.treeName(), image
=xxx
.treeImage(),
1345 data
=wxTreeItemData(xxx
))
1346 tree
.EnsureVisible(newItem
)
1347 tree
.SelectItem(newItem
)
1348 if not tree
.IsVisible(newItem
):
1349 tree
.ScrollTo(newItem
)
1352 if testWin
and tree
.GetItemAncestor(newItem
) == testWin
.item
:
1353 if conf
.autoRefresh
:
1354 tree
.needUpdate
= true
1355 tree
.pendingHighLight
= newItem
1357 tree
.pendingHighLight
= None
1359 def OnExpand(self
, evt
):
1360 if tree
.GetSelection().IsOk():
1361 tree
.ExpandAll(tree
.GetSelection())
1363 tree
.ExpandAll(tree
.GetRootItem())
1365 def OnPullDownHighlight(self
, evt
):
1366 menuId
= evt
.GetMenuId()
1368 menu
= evt
.GetEventObject()
1369 help = menu
.GetHelpString(menuId
)
1370 self
.SetStatusText(help)
1372 self
.SetStatusText('')
1374 def OnUpdateUI(self
, evt
):
1375 if evt
.GetId() in [wxID_CUT
, wxID_COPY
, self
.ID_DELETE
]:
1376 enable
= tree
.GetSelection().IsOk() and \
1377 tree
.GetSelection() != tree
.GetRootItem()
1379 elif evt
.GetId() == wxID_PASTE
:
1380 enable
= tree
.GetSelection().IsOk() and \
1381 tree
.GetSelection() != tree
.GetRootItem() and \
1382 self
.clipboard
!= None
1385 def OnIdle(self
, evt
):
1387 if conf
.autoRefresh
:
1390 tree
.CreateTestWin(testWin
.item
)
1391 tree
.needUpdate
= false
1392 elif tree
.pendingHighLight
:
1393 tree
.HighLight(tree
.pendingHighLight
)
1397 def OnCloseWindow(self
, evt
):
1398 if not self
.AskSave(): return
1399 if testWin
: testWin
.Destroy()
1400 # Destroy cached windows
1401 for w
in panel
.styleCache
.values(): w
.Destroy()
1402 conf
.width
, conf
.height
= self
.GetSize()
1403 conf
.sashPos
= self
.splitter
.GetSashPosition()
1408 self
.clipboard
= None
1409 self
.modified
= false
1410 panel
.SetModified(false
)
1417 self
.SetTitle(progname
)
1419 def Open(self
, path
):
1420 # Try to read the file
1425 dom
= minidom
.parse(path
)
1427 self
.dataFile
= path
1428 self
.SetTitle(progname
+ ': ' + os
.path
.basename(path
))
1430 wxLogError('Error reading file: ' + path
)
1433 def Save(self
, path
):
1435 self
.OnRefresh(wxCommandEvent())
1436 memFile
= MemoryFile(path
)
1437 tree
.dom
.writexml(memFile
)
1439 self
.modified
= false
1440 panel
.SetModified(false
)
1442 wxLogError('Error writing file: ' + path
)
1446 if not (self
.modified
or panel
.IsModified()): return true
1447 flags
= wxICON_EXCLAMATION | wxYES_NO | wxCANCEL | wxCENTRE
1448 dlg
= wxMessageDialog( self
, 'File is modified. Save before exit?',
1449 'Save before too late?', flags
)
1450 say
= dlg
.ShowModal()
1453 self
.OnSaveOrSaveAs(wxCommandEvent(wxID_SAVE
))
1454 # If save was successful, modified flag is unset
1455 if not self
.modified
: return true
1456 elif say
== wxID_NO
:
1457 self
.modified
= false
1458 panel
.SetModified(false
)
1462 ################################################################################
1466 self
.SetAppName("xrced")
1469 # !!! wxConfigBase_Get doesn't seem to work
1470 conf
= wxConfig(style
=wxCONFIG_USE_LOCAL_FILE
)
1471 conf
.autoRefresh
= conf
.ReadInt('autorefresh', true
)
1472 size
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600)
1473 conf
.sashPos
= conf
.ReadInt('sashPos', 200)
1475 wxFileSystem_AddHandler(wxMemoryFSHandler())
1476 wxInitAllImageHandlers()
1479 frame
= self
.frame
= Frame(size
)
1480 self
.frame
.Show(true
)
1481 # Load resources from XRC file (!!! should be transformed to .py later?)
1482 sys
.modules
['params'].frame
= frame
1483 frame
.res
= wxXmlResource('')
1484 frame
.res
.Load(os
.path
.join(sys
.path
[0], 'xrced.xrc'))
1489 wc
= wxConfigBase_Get()
1490 wc
.WriteInt('autorefresh', conf
.autoRefresh
)
1491 wc
.WriteInt('width', conf
.width
)
1492 wc
.WriteInt('height', conf
.height
)
1493 wc
.WriteInt('sashPos', conf
.sashPos
)
1501 if __name__
== '__main__':