2 # Purpose:      XRC editor, main module 
   3 # Author:       Roman Rolinsky <rolinsky@mema.ucl.ac.be> 
   9 xrced -- Simple resource editor for XRC format used by wxWindows/wxPython 
  14     xrced [ -h ] [ -v ] [ XRC-file ] 
  18     -h          output short usage info and exit 
  20     -v          output version info and exit 
  24 import os
, sys
, getopt
, re
, traceback
, tempfile
, shutil
, cPickle
 
  27 from tree 
import *                      # imports xxx which imports params 
  30 # Cleanup recursive import sideeffects, otherwise we can't create undoMan 
  32 undo
.ParamPage 
= ParamPage
 
  33 undoMan 
= g
.undoMan 
= UndoManager() 
  35 # Set application path for loading resources 
  36 if __name__ 
== '__main__': 
  37     basePath 
= os
.path
.dirname(sys
.argv
[0]) 
  39     basePath 
= os
.path
.dirname(__file__
) 
  41 # 1 adds CMD command to Help menu 
  45 <HTML><H2>Welcome to XRC<font color="blue">ed</font></H2><H3><font color="green">DON'T PANIC :)</font></H3> 
  46 Read this note before clicking on anything!<P> 
  47 To start select tree root, then popup menu with your right mouse button, 
  48 select "Append Child", and then any command.<P> 
  49 Or just press one of the buttons on the tools palette.<P> 
  50 Enter XML ID, change properties, create children.<P> 
  51 To test your interface select Test command (View menu).<P> 
  52 Consult README file for the details.</HTML> 
  55 defaultIDs 
= {xxxPanel
:'PANEL', xxxDialog
:'DIALOG', xxxFrame
:'FRAME', 
  56               xxxMenuBar
:'MENUBAR', xxxMenu
:'MENU', xxxToolBar
:'TOOLBAR', 
  57               xxxWizard
:'WIZARD', xxxBitmap
:'BITMAP', xxxIcon
:'ICON'} 
  59 defaultName 
= 'UNTITLED.xrc' 
  61 ################################################################################ 
  63 # ScrolledMessageDialog - modified from wxPython lib to set fixed-width font 
  64 class ScrolledMessageDialog(wxDialog
): 
  65     def __init__(self
, parent
, msg
, caption
, pos 
= wxDefaultPosition
, size 
= (500,300)): 
  66         from wxPython
.lib
.layoutf 
import Layoutf
 
  67         wxDialog
.__init
__(self
, parent
, -1, caption
, pos
, size
) 
  68         text 
= wxTextCtrl(self
, -1, msg
, wxDefaultPosition
, 
  69                              wxDefaultSize
, wxTE_MULTILINE | wxTE_READONLY
) 
  70         text
.SetFont(g
.modernFont()) 
  72         # !!! possible bug - GetTextExtent without font returns sysfont dims 
  73         w
, h 
= dc
.GetFullTextExtent(' ', g
.modernFont())[:2] 
  74         ok 
= wxButton(self
, wxID_OK
, "OK") 
  75         text
.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self
,ok
))) 
  76         text
.SetSize((w 
* 80 + 30, h 
* 40)) 
  78         ok
.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self
,))) 
  79         self
.SetAutoLayout(True) 
  81         self
.CenterOnScreen(wxBOTH
) 
  83 ################################################################################ 
  85 # Event handler for using during location 
  86 class Locator(wxEvtHandler
): 
  87     def ProcessEvent(self
, evt
): 
  91     def __init__(self
, pos
, size
): 
  92         wxFrame
.__init
__(self
, None, -1, '', pos
, size
) 
  94         frame 
= g
.frame 
= self
 
  95         bar 
= self
.CreateStatusBar(2) 
  96         bar
.SetStatusWidths([-1, 40]) 
  97         self
.SetIcon(images
.getIconIcon()) 
 102         # Load our own resources 
 103         self
.res 
= wxXmlResource('') 
 104         # !!! Blocking of assert failure occurring in older unicode builds 
 106             self
.res
.Load(os
.path
.join(basePath
, 'xrced.xrc')) 
 107         except wx
._core
.PyAssertionError
: 
 108             print 'PyAssertionError was ignored' 
 111         menuBar 
= wxMenuBar() 
 114         menu
.Append(wxID_NEW
, '&New\tCtrl-N', 'New file') 
 115         menu
.AppendSeparator() 
 116         menu
.Append(wxID_OPEN
, '&Open...\tCtrl-O', 'Open XRC file') 
 117         self
.recentMenu 
= wxMenu() 
 118         self
.AppendRecent(self
.recentMenu
) 
 119         menu
.AppendMenu(-1, 'Open Recent', self
.recentMenu
, 'Open a recent file') 
 120         menu
.AppendSeparator() 
 121         menu
.Append(wxID_SAVE
, '&Save\tCtrl-S', 'Save XRC file') 
 122         menu
.Append(wxID_SAVEAS
, 'Save &As...', 'Save XRC file under different name') 
 123         menu
.AppendSeparator() 
 124         menu
.Append(wxID_EXIT
, '&Quit\tCtrl-Q', 'Exit application') 
 126         menuBar
.Append(menu
, '&File') 
 129         menu
.Append(wxID_UNDO
, '&Undo\tCtrl-Z', 'Undo') 
 130         menu
.Append(wxID_REDO
, '&Redo\tCtrl-Y', 'Redo') 
 131         menu
.AppendSeparator() 
 132         menu
.Append(wxID_CUT
, 'Cut\tCtrl-X', 'Cut to the clipboard') 
 133         menu
.Append(wxID_COPY
, '&Copy\tCtrl-C', 'Copy to the clipboard') 
 134         menu
.Append(wxID_PASTE
, '&Paste\tCtrl-V', 'Paste from the clipboard') 
 135         self
.ID_DELETE 
= wxNewId() 
 136         menu
.Append(self
.ID_DELETE
, '&Delete\tCtrl-D', 'Delete object') 
 137         menu
.AppendSeparator() 
 138         self
.ID_LOCATE 
= wxNewId() 
 139         self
.ID_TOOL_LOCATE 
= wxNewId() 
 140         self
.ID_TOOL_PASTE 
= wxNewId() 
 141         menu
.Append(self
.ID_LOCATE
, '&Locate\tCtrl-L', 'Locate control in test window and select it') 
 142         menuBar
.Append(menu
, '&Edit') 
 145         self
.ID_EMBED_PANEL 
= wxNewId() 
 146         menu
.Append(self
.ID_EMBED_PANEL
, '&Embed Panel', 
 147                     'Toggle embedding properties panel in the main window', True) 
 148         menu
.Check(self
.ID_EMBED_PANEL
, conf
.embedPanel
) 
 149         self
.ID_SHOW_TOOLS 
= wxNewId() 
 150         menu
.Append(self
.ID_SHOW_TOOLS
, 'Show &Tools', 'Toggle tools', True) 
 151         menu
.Check(self
.ID_SHOW_TOOLS
, conf
.showTools
) 
 152         menu
.AppendSeparator() 
 153         self
.ID_TEST 
= wxNewId() 
 154         menu
.Append(self
.ID_TEST
, '&Test\tF5', 'Show test window') 
 155         self
.ID_REFRESH 
= wxNewId() 
 156         menu
.Append(self
.ID_REFRESH
, '&Refresh\tCtrl-R', 'Refresh test window') 
 157         self
.ID_AUTO_REFRESH 
= wxNewId() 
 158         menu
.Append(self
.ID_AUTO_REFRESH
, '&Auto-refresh\tCtrl-A', 
 159                     'Toggle auto-refresh mode', True) 
 160         menu
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 161         self
.ID_TEST_HIDE 
= wxNewId() 
 162         menu
.Append(self
.ID_TEST_HIDE
, '&Hide\tCtrl-H', 'Close test window') 
 163         menuBar
.Append(menu
, '&View') 
 166         menu
.Append(wxID_ABOUT
, '&About...', 'About XCRed') 
 167         self
.ID_README 
= wxNewId() 
 168         menu
.Append(self
.ID_README
, '&Readme...', 'View the README file') 
 170             self
.ID_DEBUG_CMD 
= wxNewId() 
 171             menu
.Append(self
.ID_DEBUG_CMD
, 'CMD', 'Python command line') 
 172             EVT_MENU(self
, self
.ID_DEBUG_CMD
, self
.OnDebugCMD
) 
 173         menuBar
.Append(menu
, '&Help') 
 175         self
.menuBar 
= menuBar
 
 176         self
.SetMenuBar(menuBar
) 
 179         tb 
= self
.CreateToolBar(wxTB_HORIZONTAL | wxNO_BORDER | wxTB_FLAT
) 
 180         tb
.SetToolBitmapSize((24,24)) 
 181         new_bmp  
= wx
.ArtProvider
.GetBitmap(wx
.ART_NORMAL_FILE
, wx
.ART_TOOLBAR
) 
 182         open_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_FILE_OPEN
, wx
.ART_TOOLBAR
) 
 183         save_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_FILE_SAVE
, wx
.ART_TOOLBAR
) 
 184         undo_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_UNDO
, wx
.ART_TOOLBAR
) 
 185         redo_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_REDO
, wx
.ART_TOOLBAR
) 
 186         cut_bmp  
= wx
.ArtProvider
.GetBitmap(wx
.ART_CUT
, wx
.ART_TOOLBAR
) 
 187         copy_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_COPY
, wx
.ART_TOOLBAR
) 
 188         paste_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_PASTE
, wx
.ART_TOOLBAR
) 
 190         tb
.AddSimpleTool(wxID_NEW
, new_bmp
, 'New', 'New file') 
 191         tb
.AddSimpleTool(wxID_OPEN
, open_bmp
, 'Open', 'Open file') 
 192         tb
.AddSimpleTool(wxID_SAVE
, save_bmp
, 'Save', 'Save file') 
 193         tb
.AddControl(wxStaticLine(tb
, -1, size
=(-1,23), style
=wxLI_VERTICAL
)) 
 194         tb
.AddSimpleTool(wxID_UNDO
, undo_bmp
, 'Undo', 'Undo') 
 195         tb
.AddSimpleTool(wxID_REDO
, redo_bmp
, 'Redo', 'Redo') 
 196         tb
.AddControl(wxStaticLine(tb
, -1, size
=(-1,23), style
=wxLI_VERTICAL
)) 
 197         tb
.AddSimpleTool(wxID_CUT
, cut_bmp
, 'Cut', 'Cut') 
 198         tb
.AddSimpleTool(wxID_COPY
, copy_bmp
, 'Copy', 'Copy') 
 199         tb
.AddSimpleTool(self
.ID_TOOL_PASTE
, paste_bmp
, 'Paste', 'Paste') 
 200         tb
.AddControl(wxStaticLine(tb
, -1, size
=(-1,23), style
=wxLI_VERTICAL
)) 
 201         tb
.AddSimpleTool(self
.ID_TOOL_LOCATE
, 
 202                         images
.getLocateBitmap(), #images.getLocateArmedBitmap(), 
 203                         'Locate', 'Locate control in test window and select it', True) 
 204         tb
.AddControl(wxStaticLine(tb
, -1, size
=(-1,23), style
=wxLI_VERTICAL
)) 
 205         tb
.AddSimpleTool(self
.ID_TEST
, images
.getTestBitmap(), 'Test', 'Test window') 
 206         tb
.AddSimpleTool(self
.ID_REFRESH
, images
.getRefreshBitmap(), 
 207                          'Refresh', 'Refresh view') 
 208         tb
.AddSimpleTool(self
.ID_AUTO_REFRESH
, images
.getAutoRefreshBitmap(), 
 209                          'Auto-refresh', 'Toggle auto-refresh mode', True) 
 210 #        if wxPlatform == '__WXGTK__': 
 211 #            tb.AddSeparator()   # otherwise auto-refresh sticks in status line 
 212         tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 216         self
.minWidth 
= tb
.GetSize()[0] # minimal width is the size of toolbar 
 219         EVT_MENU(self
, wxID_NEW
, self
.OnNew
) 
 220         EVT_MENU(self
, wxID_OPEN
, self
.OnOpen
) 
 221         EVT_MENU(self
, wxID_SAVE
, self
.OnSaveOrSaveAs
) 
 222         EVT_MENU(self
, wxID_SAVEAS
, self
.OnSaveOrSaveAs
) 
 223         EVT_MENU(self
, wxID_EXIT
, self
.OnExit
) 
 225         EVT_MENU(self
, wxID_UNDO
, self
.OnUndo
) 
 226         EVT_MENU(self
, wxID_REDO
, self
.OnRedo
) 
 227         EVT_MENU(self
, wxID_CUT
, self
.OnCutDelete
) 
 228         EVT_MENU(self
, wxID_COPY
, self
.OnCopy
) 
 229         EVT_MENU(self
, wxID_PASTE
, self
.OnPaste
) 
 230         EVT_MENU(self
, self
.ID_TOOL_PASTE
, self
.OnPaste
) 
 231         EVT_MENU(self
, self
.ID_DELETE
, self
.OnCutDelete
) 
 232         EVT_MENU(self
, self
.ID_LOCATE
, self
.OnLocate
) 
 233         EVT_MENU(self
, self
.ID_TOOL_LOCATE
, self
.OnLocate
) 
 235         EVT_MENU(self
, self
.ID_EMBED_PANEL
, self
.OnEmbedPanel
) 
 236         EVT_MENU(self
, self
.ID_SHOW_TOOLS
, self
.OnShowTools
) 
 237         EVT_MENU(self
, self
.ID_TEST
, self
.OnTest
) 
 238         EVT_MENU(self
, self
.ID_REFRESH
, self
.OnRefresh
) 
 239         EVT_MENU(self
, self
.ID_AUTO_REFRESH
, self
.OnAutoRefresh
) 
 240         EVT_MENU(self
, self
.ID_TEST_HIDE
, self
.OnTestHide
) 
 242         EVT_MENU(self
, wxID_ABOUT
, self
.OnAbout
) 
 243         EVT_MENU(self
, self
.ID_README
, self
.OnReadme
) 
 246         EVT_UPDATE_UI(self
, wxID_SAVE
, self
.OnUpdateUI
) 
 247         EVT_UPDATE_UI(self
, wxID_CUT
, self
.OnUpdateUI
) 
 248         EVT_UPDATE_UI(self
, wxID_COPY
, self
.OnUpdateUI
) 
 249         EVT_UPDATE_UI(self
, wxID_PASTE
, self
.OnUpdateUI
) 
 250         EVT_UPDATE_UI(self
, self
.ID_LOCATE
, self
.OnUpdateUI
) 
 251         EVT_UPDATE_UI(self
, self
.ID_TOOL_LOCATE
, self
.OnUpdateUI
) 
 252         EVT_UPDATE_UI(self
, self
.ID_TOOL_PASTE
, self
.OnUpdateUI
) 
 253         EVT_UPDATE_UI(self
, wxID_UNDO
, self
.OnUpdateUI
) 
 254         EVT_UPDATE_UI(self
, wxID_REDO
, self
.OnUpdateUI
) 
 255         EVT_UPDATE_UI(self
, self
.ID_DELETE
, self
.OnUpdateUI
) 
 256         EVT_UPDATE_UI(self
, self
.ID_TEST
, self
.OnUpdateUI
) 
 257         EVT_UPDATE_UI(self
, self
.ID_REFRESH
, self
.OnUpdateUI
) 
 260         sizer 
= wxBoxSizer(wxVERTICAL
) 
 261         sizer
.Add(wxStaticLine(self
, -1), 0, wxEXPAND
) 
 262         # Horizontal sizer for toolbar and splitter 
 263         self
.toolsSizer 
= sizer1 
= wxBoxSizer() 
 264         splitter 
= wxSplitterWindow(self
, -1, style
=wxSP_3DSASH
) 
 265         self
.splitter 
= splitter
 
 266         splitter
.SetMinimumPaneSize(100) 
 269         g
.tree 
= tree 
= XML_Tree(splitter
, -1) 
 271         # Init pull-down menu data 
 273         g
.pullDownMenu 
= pullDownMenu 
= PullDownMenu(self
) 
 275         # Vertical toolbar for GUI buttons 
 276         g
.tools 
= tools 
= Tools(self
) 
 277         tools
.Show(conf
.showTools
) 
 278         if conf
.showTools
: sizer1
.Add(tools
, 0, wxEXPAND
) 
 280         tree
.RegisterKeyEvents() 
 282         # !!! frame styles are broken 
 283         # Miniframe for not embedded mode 
 284         miniFrame 
= wxFrame(self
, -1, 'Properties & Style', 
 285                             (conf
.panelX
, conf
.panelY
), 
 286                             (conf
.panelWidth
, conf
.panelHeight
)) 
 287         self
.miniFrame 
= miniFrame
 
 288         sizer2 
= wxBoxSizer() 
 289         miniFrame
.SetAutoLayout(True) 
 290         miniFrame
.SetSizer(sizer2
) 
 291         EVT_CLOSE(self
.miniFrame
, self
.OnCloseMiniFrame
) 
 292         # Create panel for parameters 
 295             panel 
= Panel(splitter
) 
 296             # Set plitter windows 
 297             splitter
.SplitVertically(tree
, panel
, conf
.sashPos
) 
 299             panel 
= Panel(miniFrame
) 
 300             sizer2
.Add(panel
, 1, wxEXPAND
) 
 302             splitter
.Initialize(tree
) 
 303         sizer1
.Add(splitter
, 1, wxEXPAND
) 
 304         sizer
.Add(sizer1
, 1, wxEXPAND
) 
 305         self
.SetAutoLayout(True) 
 312         EVT_IDLE(self
, self
.OnIdle
) 
 313         EVT_CLOSE(self
, self
.OnCloseWindow
) 
 314         EVT_KEY_DOWN(self
, tools
.OnKeyDown
) 
 315         EVT_KEY_UP(self
, tools
.OnKeyUp
) 
 316         EVT_ICONIZE(self
, self
.OnIconize
) 
 318     def AppendRecent(self
, menu
): 
 319         # add recently used files to the menu 
 320         for id,name 
in conf
.recentfiles
.iteritems(): 
 322             EVT_MENU(self
,id,self
.OnRecentFile
) 
 325     def OnRecentFile(self
,evt
): 
 326         # open recently used file 
 327         if not self
.AskSave(): return 
 330             path
=conf
.recentfiles
[evt
.GetId()] 
 332                 self
.SetStatusText('Data loaded') 
 334                 self
.SetStatusText('Failed') 
 336             self
.SetStatusText('No such file') 
 339     def OnNew(self
, evt
): 
 340         if not self
.AskSave(): return 
 343     def OnOpen(self
, evt
): 
 344         if not self
.AskSave(): return 
 345         dlg 
= wxFileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
), 
 346                            '', '*.xrc', wxOPEN | wxCHANGE_DIR
) 
 347         if dlg
.ShowModal() == wxID_OK
: 
 349             self
.SetStatusText('Loading...') 
 353                     self
.SetStatusText('Data loaded') 
 355                     self
.SetStatusText('Failed') 
 356                 self
.SaveRecent(path
) 
 361     def OnSaveOrSaveAs(self
, evt
): 
 362         if evt
.GetId() == wxID_SAVEAS 
or not self
.dataFile
: 
 363             if self
.dataFile
: name 
= '' 
 364             else: name 
= defaultName
 
 365             dirname 
= os
.path
.abspath(os
.path
.dirname(self
.dataFile
)) 
 366             dlg 
= wxFileDialog(self
, 'Save As', dirname
, name
, '*.xrc', 
 367                                wxSAVE | wxOVERWRITE_PROMPT | wxCHANGE_DIR
) 
 368             if dlg
.ShowModal() == wxID_OK
: 
 376         self
.SetStatusText('Saving...') 
 380                 tmpFile
,tmpName 
= tempfile
.mkstemp(prefix
='xrced-') 
 382                 self
.Save(tmpName
) # save temporary file first 
 383                 shutil
.move(tmpName
, path
) 
 385                 self
.SetStatusText('Data saved') 
 386                 self
.SaveRecent(path
) 
 388                 self
.SetStatusText('Failed') 
 392     def SaveRecent(self
,path
): 
 393         # append to recently used files 
 394         if path 
not in conf
.recentfiles
.values(): 
 396             self
.recentMenu
.Append(newid
, path
) 
 397             EVT_MENU(self
, newid
, self
.OnRecentFile
) 
 398             conf
.recentfiles
[newid
] = path
 
 400     def OnExit(self
, evt
): 
 403     def OnUndo(self
, evt
): 
 404         # Extra check to not mess with idle updating 
 405         if undoMan
.CanUndo(): 
 408     def OnRedo(self
, evt
): 
 409         if undoMan
.CanRedo(): 
 412     def OnCopy(self
, evt
): 
 413         selected 
= tree
.selection
 
 414         if not selected
: return         # key pressed event 
 415         xxx 
= tree
.GetPyData(selected
) 
 416         wx
.TheClipboard
.Open() 
 417         data 
= wx
.CustomDataObject('XRCED') 
 418         data
.SetData(cPickle
.dumps(xxx
.element
)) 
 419         wx
.TheClipboard
.SetData(data
) 
 420         wx
.TheClipboard
.Close() 
 421         self
.SetStatusText('Copied') 
 423     def OnPaste(self
, evt
): 
 424         selected 
= tree
.selection
 
 425         if not selected
: return         # key pressed event 
 426         # For pasting with Ctrl pressed 
 428         if evt
.GetId() == pullDownMenu
.ID_PASTE_SIBLING
: appendChild 
= False 
 429         elif evt
.GetId() == self
.ID_TOOL_PASTE
: 
 430             if g
.tree
.ctrl
: appendChild 
= False 
 431             else: appendChild 
= not tree
.NeedInsert(selected
) 
 432         else: appendChild 
= not tree
.NeedInsert(selected
) 
 433         xxx 
= tree
.GetPyData(selected
) 
 435             # If has next item, insert, else append to parent 
 436             nextItem 
= tree
.GetNextSibling(selected
) 
 437             parentLeaf 
= tree
.GetItemParent(selected
) 
 438         # Expanded container (must have children) 
 439         elif tree
.IsExpanded(selected
) and tree
.GetChildrenCount(selected
, False): 
 440             # Insert as first child 
 441             nextItem 
= tree
.GetFirstChild(selected
)[0] 
 442             parentLeaf 
= selected
 
 444             # No children or unexpanded item - appendChild stays True 
 445             nextItem 
= wxTreeItemId()   # no next item 
 446             parentLeaf 
= selected
 
 447         parent 
= tree
.GetPyData(parentLeaf
).treeObject() 
 449         # Create a copy of clipboard pickled element 
 450         wx
.TheClipboard
.Open() 
 451         data 
= wx
.CustomDataObject('XRCED') 
 452         if not wx
.TheClipboard
.IsSupported(data
.GetFormat()): 
 453             wx
.TheClipboard
.Close() 
 454             wx
.LogError('unsupported clipboard format') 
 456         wx
.TheClipboard
.GetData(data
) 
 457         wx
.TheClipboard
.Close() 
 458         elem 
= cPickle
.loads(data
.GetData()) 
 459         # Tempopary xxx object to test things 
 460         xxx 
= MakeXXXFromDOM(parent
, elem
) 
 462         # Check compatibility 
 466         if x
.__class
__ in [xxxDialog
, xxxFrame
, xxxMenuBar
, xxxWizard
]: 
 468             if parent
.__class
__ != xxxMainNode
: error 
= True 
 469         elif x
.__class
__ == xxxToolBar
: 
 470             # Toolbar can be top-level of child of panel or frame 
 471             if parent
.__class
__ not in [xxxMainNode
, xxxPanel
, xxxFrame
] and \
 
 472                not parent
.isSizer
: error 
= True 
 473         elif x
.__class
__ == xxxPanel 
and parent
.__class
__ == xxxMainNode
: 
 475         elif x
.__class
__ == xxxSpacer
: 
 476             if not parent
.isSizer
: error 
= True 
 477         elif x
.__class
__ == xxxSeparator
: 
 478             if not parent
.__class
__ in [xxxMenu
, xxxToolBar
]: error 
= True 
 479         elif x
.__class
__ == xxxTool
: 
 480             if parent
.__class
__ != xxxToolBar
: error 
= True 
 481         elif x
.__class
__ == xxxMenu
: 
 482             if not parent
.__class
__ in [xxxMainNode
, xxxMenuBar
, xxxMenu
]: error 
= True 
 483         elif x
.__class
__ == xxxMenuItem
: 
 484             if not parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error 
= True 
 485         elif x
.isSizer 
and parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
]: 
 487         else:                           # normal controls can be almost anywhere 
 488             if parent
.__class
__ == xxxMainNode 
or \
 
 489                parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error 
= True 
 491             if parent
.__class
__ == xxxMainNode
: parentClass 
= 'root' 
 492             else: parentClass 
= parent
.className
 
 493             wxLogError('Incompatible parent/child: parent is %s, child is %s!' % 
 494                        (parentClass
, x
.className
)) 
 497         # Check parent and child relationships. 
 498         # If parent is sizer or notebook, child is of wrong class or 
 499         # parent is normal window, child is child container then detach child. 
 500         isChildContainer 
= isinstance(xxx
, xxxChildContainer
) 
 501         parentIsBook 
= parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
] 
 502         if isChildContainer 
and \
 
 503            ((parent
.isSizer 
and not isinstance(xxx
, xxxSizerItem
)) or \
 
 504             (parentIsBook 
and not isinstance(xxx
, xxxPage
)) or \
 
 505            not (parent
.isSizer 
or parentIsBook
)): 
 506             elem
.removeChild(xxx
.child
.element
) # detach child 
 507             elem
.unlink()           # delete child container 
 508             elem 
= xxx
.child
.element 
# replace 
 509             # This may help garbage collection 
 510             xxx
.child
.parent 
= None 
 511             isChildContainer 
= False 
 512         # Parent is sizer or notebook, child is not child container 
 513         if parent
.isSizer 
and not isChildContainer 
and not isinstance(xxx
, xxxSpacer
): 
 514             # Create sizer item element 
 515             sizerItemElem 
= MakeEmptyDOM(parent
.itemTag
) 
 516             sizerItemElem
.appendChild(elem
) 
 518         elif isinstance(parent
, xxxNotebook
) and not isChildContainer
: 
 519             pageElem 
= MakeEmptyDOM('notebookpage') 
 520             pageElem
.appendChild(elem
) 
 522         elif isinstance(parent
, xxxChoicebook
) and not isChildContainer
: 
 523             pageElem 
= MakeEmptyDOM('choicebookpage') 
 524             pageElem
.appendChild(elem
) 
 526         elif isinstance(parent
, xxxListbook
) and not isChildContainer
: 
 527             pageElem 
= MakeEmptyDOM('listbookpage') 
 528             pageElem
.appendChild(elem
) 
 530         # Insert new node, register undo 
 531         newItem 
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
) 
 532         undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
)) 
 533         # Scroll to show new item (!!! redundant?) 
 534         tree
.EnsureVisible(newItem
) 
 535         tree
.SelectItem(newItem
) 
 536         if not tree
.IsVisible(newItem
): 
 537             tree
.ScrollTo(newItem
) 
 540         if g
.testWin 
and tree
.IsHighlatable(newItem
): 
 542                 tree
.needUpdate 
= True 
 543                 tree
.pendingHighLight 
= newItem
 
 545                 tree
.pendingHighLight 
= None 
 547         self
.SetStatusText('Pasted') 
 549     def OnCutDelete(self
, evt
): 
 550         selected 
= tree
.selection
 
 551         if not selected
: return         # key pressed event 
 553         if evt
.GetId() == wxID_CUT
: 
 555             status 
= 'Removed to clipboard' 
 557             self
.lastOp 
= 'DELETE' 
 561             # If deleting top-level item, delete testWin 
 562             if selected 
== g
.testWin
.item
: 
 566                 # Remove highlight, update testWin 
 567                 if g
.testWin
.highLight
: 
 568                     g
.testWin
.highLight
.Remove() 
 569                 tree
.needUpdate 
= True 
 572         index 
= tree
.ItemFullIndex(selected
) 
 573         parent 
= tree
.GetPyData(tree
.GetItemParent(selected
)).treeObject() 
 574         elem 
= tree
.RemoveLeaf(selected
) 
 575         undoMan
.RegisterUndo(UndoCutDelete(index
, parent
, elem
)) 
 576         if evt
.GetId() == wxID_CUT
: 
 577             wx
.TheClipboard
.Open() 
 578             data 
= wx
.CustomDataObject('XRCED') 
 579             data
.SetData(cPickle
.dumps(elem
)) 
 580             wx
.TheClipboard
.SetData(data
) 
 581             wx
.TheClipboard
.Close() 
 582         tree
.pendingHighLight 
= None 
 584         tree
.selection 
= None 
 589         self
.SetStatusText(status
) 
 591     def OnSubclass(self
, evt
): 
 592         selected 
= tree
.selection
 
 593         xxx 
= tree
.GetPyData(selected
).treeObject() 
 595         subclass 
= xxx
.subclass
 
 596         dlg 
= wxTextEntryDialog(self
, 'Subclass:', defaultValue
=subclass
) 
 597         if dlg
.ShowModal() == wxID_OK
: 
 598             subclass 
= dlg
.GetValue() 
 600                 elem
.setAttribute('subclass', subclass
) 
 601             elif elem
.hasAttribute('subclass'): 
 602                 elem
.removeAttribute('subclass') 
 604             xxx
.subclass 
= elem
.getAttribute('subclass') 
 605             tree
.SetItemText(selected
, xxx
.treeName()) 
 606             panel
.pages
[0].box
.SetLabel(xxx
.panelName()) 
 609     def OnEmbedPanel(self
, evt
): 
 610         conf
.embedPanel 
= evt
.IsChecked() 
 612             # Remember last dimentions 
 613             conf
.panelX
, conf
.panelY 
= self
.miniFrame
.GetPosition() 
 614             conf
.panelWidth
, conf
.panelHeight 
= self
.miniFrame
.GetSize() 
 615             size 
= self
.GetSize() 
 616             pos 
= self
.GetPosition() 
 617             sizePanel 
= panel
.GetSize() 
 618             panel
.Reparent(self
.splitter
) 
 619             self
.miniFrame
.GetSizer().Remove(panel
) 
 621             self
.SetDimensions(pos
.x
, pos
.y
, size
.width 
+ sizePanel
.width
, size
.height
) 
 622             self
.splitter
.SplitVertically(tree
, panel
, conf
.sashPos
) 
 623             self
.miniFrame
.Show(False) 
 625             conf
.sashPos 
= self
.splitter
.GetSashPosition() 
 626             pos 
= self
.GetPosition() 
 627             size 
= self
.GetSize() 
 628             sizePanel 
= panel
.GetSize() 
 629             self
.splitter
.Unsplit(panel
) 
 630             sizer 
= self
.miniFrame
.GetSizer() 
 631             panel
.Reparent(self
.miniFrame
) 
 633             sizer
.Add(panel
, 1, wxEXPAND
) 
 634             self
.miniFrame
.Show(True) 
 635             self
.miniFrame
.SetDimensions(conf
.panelX
, conf
.panelY
, 
 636                                          conf
.panelWidth
, conf
.panelHeight
) 
 638             self
.SetDimensions(pos
.x
, pos
.y
, 
 639                                max(size
.width 
- sizePanel
.width
, self
.minWidth
), size
.height
) 
 641     def OnShowTools(self
, evt
): 
 642         conf
.showTools 
= evt
.IsChecked() 
 643         g
.tools
.Show(conf
.showTools
) 
 645             self
.toolsSizer
.Prepend(g
.tools
, 0, wxEXPAND
) 
 647             self
.toolsSizer
.Remove(g
.tools
) 
 648         self
.toolsSizer
.Layout() 
 650     def OnTest(self
, evt
): 
 651         if not tree
.selection
: return   # key pressed event 
 652         tree
.ShowTestWindow(tree
.selection
) 
 654     def OnTestHide(self
, evt
): 
 655         tree
.CloseTestWindow() 
 657     # Find object by relative position 
 658     def FindObject(self
, item
, obj
): 
 659         # We simply perform depth-first traversal, sinse it's too much 
 660         # hassle to deal with all sizer/window combinations 
 661         w 
= tree
.FindNodeObject(item
) 
 664         if tree
.ItemHasChildren(item
): 
 665             child 
= tree
.GetFirstChild(item
)[0] 
 667                 found 
= self
.FindObject(child
, obj
) 
 668                 if found
: return found
 
 669                 child 
= tree
.GetNextSibling(child
) 
 672     def OnTestWinLeftDown(self
, evt
): 
 673         pos 
= evt
.GetPosition() 
 674         self
.SetHandler(g
.testWin
) 
 675         g
.testWin
.Disconnect(wxID_ANY
, wxID_ANY
, wxEVT_LEFT_DOWN
) 
 676         item 
= self
.FindObject(g
.testWin
.item
, evt
.GetEventObject()) 
 678             tree
.SelectItem(item
) 
 679         self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, False) 
 681             self
.SetStatusText('Selected %s' % tree
.GetItemText(item
)) 
 683             self
.SetStatusText('Locate failed!') 
 685     def SetHandler(self
, w
, h
=None): 
 688             w
.SetCursor(wxCROSS_CURSOR
) 
 691             w
.SetCursor(wxNullCursor
) 
 692         for ch 
in w
.GetChildren(): 
 693             self
.SetHandler(ch
, h
) 
 695     def OnLocate(self
, evt
): 
 697             if evt
.GetId() == self
.ID_LOCATE 
or \
 
 698                evt
.GetId() == self
.ID_TOOL_LOCATE 
and evt
.IsChecked(): 
 699                 self
.SetHandler(g
.testWin
, g
.testWin
) 
 700                 g
.testWin
.Connect(wxID_ANY
, wxID_ANY
, wxEVT_LEFT_DOWN
, self
.OnTestWinLeftDown
) 
 701                 if evt
.GetId() == self
.ID_LOCATE
: 
 702                     self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, True) 
 703             elif evt
.GetId() == self
.ID_TOOL_LOCATE 
and not evt
.IsChecked(): 
 704                 self
.SetHandler(g
.testWin
, None) 
 705                 g
.testWin
.Disconnect(wxID_ANY
, wxID_ANY
, wxEVT_LEFT_DOWN
) 
 706             self
.SetStatusText('Click somewhere in your test window now') 
 708     def OnRefresh(self
, evt
): 
 709         # If modified, apply first 
 710         selection 
= tree
.selection
 
 712             xxx 
= tree
.GetPyData(selection
) 
 713             if xxx 
and panel
.IsModified(): 
 714                 tree
.Apply(xxx
, selection
) 
 717             tree
.CreateTestWin(g
.testWin
.item
) 
 718         panel
.modified 
= False 
 719         tree
.needUpdate 
= False 
 721     def OnAutoRefresh(self
, evt
): 
 722         conf
.autoRefresh 
= evt
.IsChecked() 
 723         self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 724         self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 726     def OnAbout(self
, evt
): 
 730 (c) Roman Rolinsky <rollrom@users.sourceforge.net> 
 731 Homepage: http://xrced.sourceforge.net\ 
 733         dlg 
= wxMessageDialog(self
, str, 'About XRCed', wxOK | wxCENTRE
) 
 737     def OnReadme(self
, evt
): 
 738         text 
= open(os
.path
.join(basePath
, 'README.txt'), 'r').read() 
 739         dlg 
= ScrolledMessageDialog(self
, text
, "XRCed README") 
 743     # Simple emulation of python command line 
 744     def OnDebugCMD(self
, evt
): 
 747                 exec raw_input('C:\> ') 
 752                 (etype
, value
, tb
) =sys
.exc_info() 
 753                 tblist 
=traceback
.extract_tb(tb
)[1:] 
 754                 msg 
=' '.join(traceback
.format_exception_only(etype
, value
) 
 755                         +traceback
.format_list(tblist
)) 
 758     def OnCreate(self
, evt
): 
 759         selected 
= tree
.selection
 
 760         if tree
.ctrl
: appendChild 
= False 
 761         else: appendChild 
= not tree
.NeedInsert(selected
) 
 762         xxx 
= tree
.GetPyData(selected
) 
 766                 # If has previous item, insert after it, else append to parent 
 768                 parentLeaf 
= tree
.GetItemParent(selected
) 
 770                 # If has next item, insert, else append to parent 
 771                 nextItem 
= tree
.GetNextSibling(selected
) 
 772                 parentLeaf 
= tree
.GetItemParent(selected
) 
 773         # Expanded container (must have children) 
 774         elif tree
.shift 
and tree
.IsExpanded(selected
) \
 
 775            and tree
.GetChildrenCount(selected
, False): 
 776             nextItem 
= tree
.GetFirstChild(selected
)[0] 
 777             parentLeaf 
= selected
 
 779             nextItem 
= wxTreeItemId() 
 780             parentLeaf 
= selected
 
 781         parent 
= tree
.GetPyData(parentLeaf
) 
 782         if parent
.hasChild
: parent 
= parent
.child
 
 785         if evt
.GetId() == ID_NEW
.REF
: 
 786             ref 
= wxGetTextFromUser('Create reference to:', 'Create reference') 
 788             xxx 
= MakeEmptyRefXXX(parent
, ref
) 
 790             # Create empty element 
 791             className 
= pullDownMenu
.createMap
[evt
.GetId()] 
 792             xxx 
= MakeEmptyXXX(parent
, className
) 
 794         # Set default name for top-level windows 
 795         if parent
.__class
__ == xxxMainNode
: 
 796             cl 
= xxx
.treeObject().__class
__ 
 797             frame
.maxIDs
[cl
] += 1 
 798             xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
])) 
 799         # And for some other standard controls 
 800         elif parent
.__class
__ == xxxStdDialogButtonSizer
: 
 801             xxx
.setTreeName(pullDownMenu
.stdButtonIDs
[evt
.GetId()][0]) 
 802             # We can even set label 
 803             obj 
= xxx
.treeObject() 
 804             elem 
= g
.tree
.dom
.createElement('label') 
 805             elem
.appendChild(g
.tree
.dom
.createTextNode(pullDownMenu
.stdButtonIDs
[evt
.GetId()][1])) 
 806             obj
.params
['label'] = xxxParam(elem
) 
 807             xxx
.treeObject().element
.appendChild(elem
) 
 809         # Insert new node, register undo 
 811         newItem 
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
) 
 812         undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
)) 
 813         tree
.EnsureVisible(newItem
) 
 814         tree
.SelectItem(newItem
) 
 815         if not tree
.IsVisible(newItem
): 
 816             tree
.ScrollTo(newItem
) 
 819         if g
.testWin 
and tree
.IsHighlatable(newItem
): 
 821                 tree
.needUpdate 
= True 
 822                 tree
.pendingHighLight 
= newItem
 
 824                 tree
.pendingHighLight 
= None 
 828     # Replace one object with another 
 829     def OnReplace(self
, evt
): 
 830         selected 
= tree
.selection
 
 831         xxx 
= tree
.GetPyData(selected
).treeObject() 
 833         parent 
= elem
.parentNode
 
 834         undoMan
.RegisterUndo(UndoReplace(selected
)) 
 836         className 
= pullDownMenu
.createMap
[evt
.GetId() - 1000] 
 837         # Create temporary empty node (with default values) 
 838         dummy 
= MakeEmptyDOM(className
) 
 839         if className 
== 'spacer' and xxx
.className 
!= 'spacer': 
 841         elif xxx
.className 
== 'spacer' and className 
!= 'spacer': 
 844             klass 
= xxxDict
[className
] 
 845         # Remove non-compatible children 
 846         if tree
.ItemHasChildren(selected
) and not klass
.hasChildren
: 
 847             tree
.DeleteChildren(selected
) 
 848         nodes 
= elem
.childNodes
[:] 
 851             if node
.nodeType 
!= minidom
.Node
.ELEMENT_NODE
: continue 
 855                 if not klass
.hasChildren
:  remove 
= True 
 856             elif tag 
not in klass
.allParams 
and \
 
 857                      (not klass
.hasStyle 
or tag 
not in klass
.styles
): 
 862                 elem
.removeChild(node
) 
 865         # Remove sizeritem child if spacer 
 866         if className 
== 'spacer' and xxx
.className 
!= 'spacer': 
 867             sizeritem 
= elem
.parentNode
 
 868             assert sizeritem
.getAttribute('class') == 'sizeritem' 
 869             sizeritem
.removeChild(elem
) 
 872             tree
.GetPyData(selected
).hasChild 
= false
 
 873         elif xxx
.className 
== 'spacer' and className 
!= 'spacer': 
 874             # Create sizeritem element 
 875             assert xxx
.parent
.isSizer
 
 876             elem
.setAttribute('class', 'sizeritem') 
 877             node 
= MakeEmptyDOM(className
) 
 878             elem
.appendChild(node
) 
 879             # Replace to point to new object 
 880             xxx 
= xxxSizerItem(xxx
.parent
, elem
) 
 882             tree
.SetPyData(selected
, xxx
) 
 885             # Copy parameters present in dummy but not in elem 
 886             for node 
in dummy
.childNodes
: 
 887                 if node
.tagName 
not in tags
:  elem
.appendChild(node
.cloneNode(True)) 
 891         elem
.setAttribute('class', className
) 
 892         if elem
.hasAttribute('subclass'): 
 893             elem
.removeAttribute('subclass') # clear subclassing 
 894         # Re-create xxx element 
 895         xxx 
= MakeXXXFromDOM(xxx
.parent
, elem
) 
 896         # Update parent in child objects 
 897         if tree
.ItemHasChildren(selected
): 
 898             i
, cookie 
= tree
.GetFirstChild(selected
) 
 900                 x 
= tree
.GetPyData(i
) 
 902                 if x
.hasChild
: x
.child
.parent 
= xxx
 
 903                 i
, cookie 
= tree
.GetNextChild(selected
, cookie
) 
 906         if tree
.GetPyData(selected
).hasChild
: # child container 
 907             container 
= tree
.GetPyData(selected
) 
 908             container
.child 
= xxx
 
 909             container
.hasChildren 
= xxx
.hasChildren
 
 910             container
.isSizer 
= xxx
.isSizer
 
 913             tree
.SetPyData(selected
, xxx
) 
 914         tree
.SetItemText(selected
, xxx
.treeName()) 
 915         tree
.SetItemImage(selected
, xxx
.treeImage()) 
 917         # Set default name for top-level windows 
 918         if parent
.__class
__ == xxxMainNode
: 
 919             cl 
= xxx
.treeObject().__class
__ 
 920             frame
.maxIDs
[cl
] += 1 
 921             xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
])) 
 928         #undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected)) 
 930         if g
.testWin 
and tree
.IsHighlatable(selected
): 
 932                 tree
.needUpdate 
= True 
 933                 tree
.pendingHighLight 
= selected
 
 935                 tree
.pendingHighLight 
= None 
 939     # Expand/collapse subtree 
 940     def OnExpand(self
, evt
): 
 941         if tree
.selection
: tree
.ExpandAll(tree
.selection
) 
 942         else: tree
.ExpandAll(tree
.root
) 
 943     def OnCollapse(self
, evt
): 
 944         if tree
.selection
: tree
.CollapseAll(tree
.selection
) 
 945         else: tree
.CollapseAll(tree
.root
) 
 947     def OnPullDownHighlight(self
, evt
): 
 948         menuId 
= evt
.GetMenuId() 
 950             menu 
= evt
.GetEventObject() 
 951             help = menu
.GetHelpString(menuId
) 
 952             self
.SetStatusText(help) 
 954             self
.SetStatusText('') 
 956     def OnUpdateUI(self
, evt
): 
 957         if evt
.GetId() in [wxID_CUT
, wxID_COPY
, self
.ID_DELETE
]: 
 958             evt
.Enable(tree
.selection 
is not None and tree
.selection 
!= tree
.root
) 
 959         elif evt
.GetId() == wxID_SAVE
: 
 960             evt
.Enable(self
.modified
) 
 961         elif evt
.GetId() in [wxID_PASTE
, self
.ID_TOOL_PASTE
]: 
 962             evt
.Enable(tree
.selection 
is not None) 
 963         elif evt
.GetId() == self
.ID_TEST
: 
 964             evt
.Enable(tree
.selection 
is not None and tree
.selection 
!= tree
.root
) 
 965         elif evt
.GetId() in [self
.ID_LOCATE
, self
.ID_TOOL_LOCATE
]: 
 966             evt
.Enable(g
.testWin 
is not None) 
 967         elif evt
.GetId() == wxID_UNDO
:  evt
.Enable(undoMan
.CanUndo()) 
 968         elif evt
.GetId() == wxID_REDO
:  evt
.Enable(undoMan
.CanRedo()) 
 970     def OnIdle(self
, evt
): 
 971         if self
.inIdle
: return          # Recursive call protection 
 977                         self
.SetStatusText('Refreshing test window...') 
 979                         tree
.CreateTestWin(g
.testWin
.item
) 
 980                         self
.SetStatusText('') 
 981                     tree
.needUpdate 
= False 
 982             elif tree
.pendingHighLight
: 
 984                     tree
.HighLight(tree
.pendingHighLight
) 
 986                     # Remove highlight if any problem 
 987                     if g
.testWin
.highLight
: 
 988                         g
.testWin
.highLight
.Remove() 
 989                     tree
.pendingHighLight 
= None 
 996     # We don't let close panel window 
 997     def OnCloseMiniFrame(self
, evt
): 
1000     def OnIconize(self
, evt
): 
1001         conf
.x
, conf
.y 
= self
.GetPosition() 
1002         conf
.width
, conf
.height 
= self
.GetSize() 
1004             conf
.sashPos 
= self
.splitter
.GetSashPosition() 
1006             conf
.panelX
, conf
.panelY 
= self
.miniFrame
.GetPosition() 
1007             conf
.panelWidth
, conf
.panelHeight 
= self
.miniFrame
.GetSize() 
1008             self
.miniFrame
.Iconize() 
1011     def OnCloseWindow(self
, evt
): 
1012         if not self
.AskSave(): return 
1013         if g
.testWin
: g
.testWin
.Destroy() 
1014         if not panel
.GetPageCount() == 2: 
1015             panel
.page2
.Destroy() 
1017             # If we don't do this, page does not get destroyed (a bug?) 
1019         if not self
.IsIconized(): 
1020             conf
.x
, conf
.y 
= self
.GetPosition() 
1021             conf
.width
, conf
.height 
= self
.GetSize() 
1023                 conf
.sashPos 
= self
.splitter
.GetSashPosition() 
1025                 conf
.panelX
, conf
.panelY 
= self
.miniFrame
.GetPosition() 
1026                 conf
.panelWidth
, conf
.panelHeight 
= self
.miniFrame
.GetSize() 
1032         self
.SetModified(False) 
1038         # Numbers for new controls 
1040         for cl 
in [xxxPanel
, xxxDialog
, xxxFrame
, 
1041                    xxxMenuBar
, xxxMenu
, xxxToolBar
, 
1042                    xxxWizard
, xxxBitmap
, xxxIcon
]: 
1045     def SetModified(self
, state
=True): 
1046         self
.modified 
= state
 
1047         name 
= os
.path
.basename(self
.dataFile
) 
1048         if not name
: name 
= defaultName
 
1050             self
.SetTitle(progname 
+ ': ' + name 
+ ' *') 
1052             self
.SetTitle(progname 
+ ': ' + name
) 
1054     def Open(self
, path
): 
1055         if not os
.path
.exists(path
): 
1056             wxLogError('File does not exists: %s' % path
) 
1058         # Try to read the file 
1062             dom 
= minidom
.parse(f
) 
1064             # Set encoding global variable and default encoding 
1066                 g
.currentEncoding 
= dom
.encoding
 
1067                 wx
.SetDefaultPyEncoding(g
.currentEncoding
.encode()) 
1069                 g
.currentEncoding 
= '' 
1071             self
.dataFile 
= path 
= os
.path
.abspath(path
) 
1072             dir = os
.path
.dirname(path
) 
1073             if dir: os
.chdir(dir) 
1075             self
.SetTitle(progname 
+ ': ' + os
.path
.basename(path
)) 
1077             # Nice exception printing 
1078             inf 
= sys
.exc_info() 
1079             wxLogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1]) 
1080             wxLogError('Error reading file: %s' % path
) 
1085     def Indent(self
, node
, indent 
= 0): 
1086         # Copy child list because it will change soon 
1087         children 
= node
.childNodes
[:] 
1088         # Main node doesn't need to be indented 
1090             text 
= self
.domCopy
.createTextNode('\n' + ' ' * indent
) 
1091             node
.parentNode
.insertBefore(text
, node
) 
1093             # Append newline after last child, except for text nodes 
1094             if children
[-1].nodeType 
== minidom
.Node
.ELEMENT_NODE
: 
1095                 text 
= self
.domCopy
.createTextNode('\n' + ' ' * indent
) 
1096                 node
.appendChild(text
) 
1097             # Indent children which are elements 
1099                 if n
.nodeType 
== minidom
.Node
.ELEMENT_NODE
: 
1100                     self
.Indent(n
, indent 
+ 2) 
1102     def Save(self
, path
): 
1106             if tree
.selection 
and panel
.IsModified(): 
1107                 self
.OnRefresh(wxCommandEvent()) 
1108             if g
.currentEncoding
: 
1109                 f 
= codecs
.open(path
, 'wt', g
.currentEncoding
) 
1111                 f 
= codecs
.open(path
, 'wt') 
1112             # Make temporary copy for formatting it 
1113             # !!! We can't clone dom node, it works only once 
1114             #self.domCopy = tree.dom.cloneNode(True) 
1115             self
.domCopy 
= MyDocument() 
1116             mainNode 
= self
.domCopy
.appendChild(tree
.mainNode
.cloneNode(True)) 
1117             # Remove first child (test element) 
1118             testElem 
= mainNode
.firstChild
 
1119             mainNode
.removeChild(testElem
) 
1121             self
.Indent(mainNode
) 
1122             self
.domCopy
.writexml(f
, encoding 
= g
.currentEncoding
) 
1124             self
.domCopy
.unlink() 
1126             self
.SetModified(False) 
1127             panel
.SetModified(False) 
1129             inf 
= sys
.exc_info() 
1130             wxLogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1]) 
1131             wxLogError('Error writing file: %s' % path
) 
1135         if not (self
.modified 
or panel
.IsModified()): return True 
1136         flags 
= wxICON_EXCLAMATION | wxYES_NO | wxCANCEL | wxCENTRE
 
1137         dlg 
= wxMessageDialog( self
, 'File is modified. Save before exit?', 
1138                                'Save before too late?', flags 
) 
1139         say 
= dlg
.ShowModal() 
1142             self
.OnSaveOrSaveAs(wxCommandEvent(wxID_SAVE
)) 
1143             # If save was successful, modified flag is unset 
1144             if not self
.modified
: return True 
1145         elif say 
== wxID_NO
: 
1146             self
.SetModified(False) 
1147             panel
.SetModified(False) 
1154 ################################################################################ 
1157     print >> sys
.stderr
, 'usage: xrced [-dhiv] [file]' 
1162         if wxVERSION
[:3] < MinWxVersion
: 
1164 This version of XRCed may not work correctly on your version of wxWindows. \ 
1165 Please upgrade wxWindows to %d.%d.%d or higher.''' % MinWxVersion
) 
1167         # Process comand-line 
1170             opts
, args 
= getopt
.getopt(sys
.argv
[1:], 'dhiv') 
1178                     print 'XRCed version', version
 
1181         except getopt
.GetoptError
: 
1182             if wxPlatform 
!= '__WXMAC__': # macs have some extra parameters 
1183                 print >> sys
.stderr
, 'Unknown option' 
1187         self
.SetAppName('xrced') 
1190         conf 
= g
.conf 
= wxConfig(style 
= wxCONFIG_USE_LOCAL_FILE
) 
1191         conf
.autoRefresh 
= conf
.ReadInt('autorefresh', True) 
1192         pos 
= conf
.ReadInt('x', -1), conf
.ReadInt('y', -1) 
1193         size 
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600) 
1194         conf
.embedPanel 
= conf
.ReadInt('embedPanel', True) 
1195         conf
.showTools 
= conf
.ReadInt('showTools', True) 
1196         conf
.sashPos 
= conf
.ReadInt('sashPos', 200) 
1197         # read recently used files 
1198         recentfiles
=conf
.Read('recentFiles','') 
1201             for fil 
in recentfiles
.split('|'): 
1202                 conf
.recentfiles
[wxNewId()]=fil
 
1203         if not conf
.embedPanel
: 
1204             conf
.panelX 
= conf
.ReadInt('panelX', -1) 
1205             conf
.panelY 
= conf
.ReadInt('panelY', -1) 
1207             conf
.panelX 
= conf
.panelY 
= -1 
1208         conf
.panelWidth 
= conf
.ReadInt('panelWidth', 200) 
1209         conf
.panelHeight 
= conf
.ReadInt('panelHeight', 200) 
1210         conf
.panic 
= not conf
.HasEntry('nopanic') 
1212         wxFileSystem_AddHandler(wxMemoryFSHandler()) 
1213         wxInitAllImageHandlers() 
1215         frame 
= Frame(pos
, size
) 
1218         # Load file after showing 
1221             frame
.open = frame
.Open(args
[0]) 
1228         wc 
= wxConfigBase_Get() 
1229         wc
.WriteInt('autorefresh', conf
.autoRefresh
) 
1230         wc
.WriteInt('x', conf
.x
) 
1231         wc
.WriteInt('y', conf
.y
) 
1232         wc
.WriteInt('width', conf
.width
) 
1233         wc
.WriteInt('height', conf
.height
) 
1234         wc
.WriteInt('embedPanel', conf
.embedPanel
) 
1235         wc
.WriteInt('showTools', conf
.showTools
) 
1236         if not conf
.embedPanel
: 
1237             wc
.WriteInt('panelX', conf
.panelX
) 
1238             wc
.WriteInt('panelY', conf
.panelY
) 
1239         wc
.WriteInt('sashPos', conf
.sashPos
) 
1240         wc
.WriteInt('panelWidth', conf
.panelWidth
) 
1241         wc
.WriteInt('panelHeight', conf
.panelHeight
) 
1242         wc
.WriteInt('nopanic', True) 
1243         wc
.Write('recentFiles', '|'.join(conf
.recentfiles
.values()[-5:])) 
1247     app 
= App(0, useBestVisual
=False) 
1248     #app.SetAssertMode(wxPYAPP_ASSERT_LOG) 
1254 if __name__ 
== '__main__':