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__':