]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/tools/XRCed/xrced.py
   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 wxWidgets/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
 
  25 from xml
.parsers 
import expat
 
  28 from tree 
import *                      # imports xxx which imports params 
  31 # Cleanup recursive import sideeffects, otherwise we can't create undoMan 
  33 undo
.ParamPage 
= ParamPage
 
  34 undoMan 
= g
.undoMan 
= UndoManager() 
  36 # Set application path for loading resources 
  37 if __name__ 
== '__main__': 
  38     basePath 
= os
.path
.dirname(sys
.argv
[0]) 
  40     basePath 
= os
.path
.dirname(__file__
) 
  42 # 1 adds CMD command to Help menu 
  46 <HTML><H2>Welcome to XRC<font color="blue">ed</font></H2><H3><font color="green">DON'T PANIC :)</font></H3> 
  47 Read this note before clicking on anything!<P> 
  48 To start select tree root, then popup menu with your right mouse button, 
  49 select "Append Child", and then any command.<P> 
  50 Or just press one of the buttons on the tools palette.<P> 
  51 Enter XML ID, change properties, create children.<P> 
  52 To test your interface select Test command (View menu).<P> 
  53 Consult README file for the details.</HTML> 
  56 defaultIDs 
= {xxxPanel
:'PANEL', xxxDialog
:'DIALOG', xxxFrame
:'FRAME', 
  57               xxxMenuBar
:'MENUBAR', xxxMenu
:'MENU', xxxToolBar
:'TOOLBAR', 
  58               xxxWizard
:'WIZARD', xxxBitmap
:'BITMAP', xxxIcon
:'ICON'} 
  60 defaultName 
= 'UNTITLED.xrc' 
  62 ################################################################################ 
  64 # ScrolledMessageDialog - modified from wxPython lib to set fixed-width font 
  65 class ScrolledMessageDialog(wx
.Dialog
): 
  66     def __init__(self
, parent
, msg
, caption
, pos 
= wx
.DefaultPosition
, size 
= (500,300)): 
  67         from wx
.lib
.layoutf 
import Layoutf
 
  68         wx
.Dialog
.__init
__(self
, parent
, -1, caption
, pos
, size
) 
  69         text 
= wx
.TextCtrl(self
, -1, msg
, wx
.DefaultPosition
, 
  70                              wx
.DefaultSize
, wx
.TE_MULTILINE | wx
.TE_READONLY
) 
  71         text
.SetFont(g
.modernFont()) 
  72         dc 
= wx
.WindowDC(text
) 
  73         # !!! possible bug - GetTextExtent without font returns sysfont dims 
  74         w
, h 
= dc
.GetFullTextExtent(' ', g
.modernFont())[:2] 
  75         ok 
= wx
.Button(self
, wx
.ID_OK
, "OK") 
  76         text
.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self
,ok
))) 
  77         text
.SetSize((w 
* 80 + 30, h 
* 40)) 
  79         ok
.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self
,))) 
  80         self
.SetAutoLayout(True) 
  82         self
.CenterOnScreen(wx
.BOTH
) 
  84 ################################################################################ 
  86 # Event handler for using during location 
  87 class Locator(wx
.EvtHandler
): 
  88     def ProcessEvent(self
, evt
): 
  91 class Frame(wx
.Frame
): 
  92     def __init__(self
, pos
, size
): 
  93         wx
.Frame
.__init
__(self
, None, -1, '', pos
, size
) 
  95         frame 
= g
.frame 
= self
 
  96         bar 
= self
.CreateStatusBar(2) 
  97         bar
.SetStatusWidths([-1, 40]) 
  98         self
.SetIcon(images
.getIconIcon()) 
 103         # Load our own resources 
 104         self
.res 
= xrc
.XmlResource('') 
 105         # !!! Blocking of assert failure occurring in older unicode builds 
 107             quietlog 
= wx
.LogNull() 
 108             self
.res
.Load(os
.path
.join(basePath
, 'xrced.xrc')) 
 109         except wx
._core
.PyAssertionError
: 
 110             print 'PyAssertionError was ignored' 
 113         menuBar 
= wx
.MenuBar() 
 116         menu
.Append(wx
.ID_NEW
, '&New\tCtrl-N', 'New file') 
 117         menu
.AppendSeparator() 
 118         menu
.Append(wx
.ID_OPEN
, '&Open...\tCtrl-O', 'Open XRC file') 
 119         self
.recentMenu 
= wx
.Menu() 
 120         self
.AppendRecent(self
.recentMenu
) 
 121         menu
.AppendMenu(-1, 'Open Recent', self
.recentMenu
, 'Open a recent file') 
 122         menu
.AppendSeparator() 
 123         menu
.Append(wx
.ID_SAVE
, '&Save\tCtrl-S', 'Save XRC file') 
 124         menu
.Append(wx
.ID_SAVEAS
, 'Save &As...', 'Save XRC file under different name') 
 125         self
.ID_GENERATE_PYTHON 
= wx
.NewId() 
 126         menu
.Append(self
.ID_GENERATE_PYTHON
, '&Generate Python...',  
 127                     'Generate a Python module that uses this XRC') 
 128         menu
.AppendSeparator() 
 129         menu
.Append(wx
.ID_EXIT
, '&Quit\tCtrl-Q', 'Exit application') 
 131         menuBar
.Append(menu
, '&File') 
 134         menu
.Append(wx
.ID_UNDO
, '&Undo\tCtrl-Z', 'Undo') 
 135         menu
.Append(wx
.ID_REDO
, '&Redo\tCtrl-Y', 'Redo') 
 136         menu
.AppendSeparator() 
 137         menu
.Append(wx
.ID_CUT
, 'Cut\tCtrl-X', 'Cut to the clipboard') 
 138         menu
.Append(wx
.ID_COPY
, '&Copy\tCtrl-C', 'Copy to the clipboard') 
 139         menu
.Append(wx
.ID_PASTE
, '&Paste\tCtrl-V', 'Paste from the clipboard') 
 140         self
.ID_DELETE 
= wx
.NewId() 
 141         menu
.Append(self
.ID_DELETE
, '&Delete\tCtrl-D', 'Delete object') 
 142         menu
.AppendSeparator() 
 143         self
.ID_LOCATE 
= wx
.NewId() 
 144         self
.ID_TOOL_LOCATE 
= wx
.NewId() 
 145         self
.ID_TOOL_PASTE 
= wx
.NewId() 
 146         menu
.Append(self
.ID_LOCATE
, '&Locate\tCtrl-L', 'Locate control in test window and select it') 
 147         menuBar
.Append(menu
, '&Edit') 
 150         self
.ID_EMBED_PANEL 
= wx
.NewId() 
 151         menu
.Append(self
.ID_EMBED_PANEL
, '&Embed Panel', 
 152                     'Toggle embedding properties panel in the main window', True) 
 153         menu
.Check(self
.ID_EMBED_PANEL
, conf
.embedPanel
) 
 154         self
.ID_SHOW_TOOLS 
= wx
.NewId() 
 155         menu
.Append(self
.ID_SHOW_TOOLS
, 'Show &Tools', 'Toggle tools', True) 
 156         menu
.Check(self
.ID_SHOW_TOOLS
, conf
.showTools
) 
 157         menu
.AppendSeparator() 
 158         self
.ID_TEST 
= wx
.NewId() 
 159         menu
.Append(self
.ID_TEST
, '&Test\tF5', 'Show test window') 
 160         self
.ID_REFRESH 
= wx
.NewId() 
 161         menu
.Append(self
.ID_REFRESH
, '&Refresh\tCtrl-R', 'Refresh test window') 
 162         self
.ID_AUTO_REFRESH 
= wx
.NewId() 
 163         menu
.Append(self
.ID_AUTO_REFRESH
, '&Auto-refresh\tCtrl-A', 
 164                     'Toggle auto-refresh mode', True) 
 165         menu
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 166         self
.ID_TEST_HIDE 
= wx
.NewId() 
 167         menu
.Append(self
.ID_TEST_HIDE
, '&Hide\tCtrl-H', 'Close test window') 
 168         menuBar
.Append(menu
, '&View') 
 171         menu
.Append(wx
.ID_ABOUT
, '&About...', 'About XCRed') 
 172         self
.ID_README 
= wx
.NewId() 
 173         menu
.Append(self
.ID_README
, '&Readme...', 'View the README file') 
 175             self
.ID_DEBUG_CMD 
= wx
.NewId() 
 176             menu
.Append(self
.ID_DEBUG_CMD
, 'CMD', 'Python command line') 
 177             wx
.EVT_MENU(self
, self
.ID_DEBUG_CMD
, self
.OnDebugCMD
) 
 178         menuBar
.Append(menu
, '&Help') 
 180         self
.menuBar 
= menuBar
 
 181         self
.SetMenuBar(menuBar
) 
 184         tb 
= self
.CreateToolBar(wx
.TB_HORIZONTAL | wx
.NO_BORDER | wx
.TB_FLAT
) 
 185         tb
.SetToolBitmapSize((24,24)) 
 186         new_bmp  
= wx
.ArtProvider
.GetBitmap(wx
.ART_NORMAL_FILE
, wx
.ART_TOOLBAR
) 
 187         open_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_FILE_OPEN
, wx
.ART_TOOLBAR
) 
 188         save_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_FILE_SAVE
, wx
.ART_TOOLBAR
) 
 189         undo_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_UNDO
, wx
.ART_TOOLBAR
) 
 190         redo_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_REDO
, wx
.ART_TOOLBAR
) 
 191         cut_bmp  
= wx
.ArtProvider
.GetBitmap(wx
.ART_CUT
, wx
.ART_TOOLBAR
) 
 192         copy_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_COPY
, wx
.ART_TOOLBAR
) 
 193         paste_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_PASTE
, wx
.ART_TOOLBAR
) 
 195         tb
.AddSimpleTool(wx
.ID_NEW
, new_bmp
, 'New', 'New file') 
 196         tb
.AddSimpleTool(wx
.ID_OPEN
, open_bmp
, 'Open', 'Open file') 
 197         tb
.AddSimpleTool(wx
.ID_SAVE
, save_bmp
, 'Save', 'Save file') 
 198         tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23), style
=wx
.LI_VERTICAL
)) 
 199         tb
.AddSimpleTool(wx
.ID_UNDO
, undo_bmp
, 'Undo', 'Undo') 
 200         tb
.AddSimpleTool(wx
.ID_REDO
, redo_bmp
, 'Redo', 'Redo') 
 201         tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23), style
=wx
.LI_VERTICAL
)) 
 202         tb
.AddSimpleTool(wx
.ID_CUT
, cut_bmp
, 'Cut', 'Cut') 
 203         tb
.AddSimpleTool(wx
.ID_COPY
, copy_bmp
, 'Copy', 'Copy') 
 204         tb
.AddSimpleTool(self
.ID_TOOL_PASTE
, paste_bmp
, 'Paste', 'Paste') 
 205         tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23), style
=wx
.LI_VERTICAL
)) 
 206         tb
.AddSimpleTool(self
.ID_TOOL_LOCATE
, 
 207                         images
.getLocateBitmap(), #images.getLocateArmedBitmap(), 
 208                         'Locate', 'Locate control in test window and select it', True) 
 209         tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23), style
=wx
.LI_VERTICAL
)) 
 210         tb
.AddSimpleTool(self
.ID_TEST
, images
.getTestBitmap(), 'Test', 'Test window') 
 211         tb
.AddSimpleTool(self
.ID_REFRESH
, images
.getRefreshBitmap(), 
 212                          'Refresh', 'Refresh view') 
 213         tb
.AddSimpleTool(self
.ID_AUTO_REFRESH
, images
.getAutoRefreshBitmap(), 
 214                          'Auto-refresh', 'Toggle auto-refresh mode', True) 
 215 #        if wx.Platform == '__WXGTK__': 
 216 #            tb.AddSeparator()   # otherwise auto-refresh sticks in status line 
 217         tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 221         self
.minWidth 
= tb
.GetSize()[0] # minimal width is the size of toolbar 
 224         wx
.EVT_MENU(self
, wx
.ID_NEW
, self
.OnNew
) 
 225         wx
.EVT_MENU(self
, wx
.ID_OPEN
, self
.OnOpen
) 
 226         wx
.EVT_MENU(self
, wx
.ID_SAVE
, self
.OnSaveOrSaveAs
) 
 227         wx
.EVT_MENU(self
, wx
.ID_SAVEAS
, self
.OnSaveOrSaveAs
) 
 228         wx
.EVT_MENU(self
, self
.ID_GENERATE_PYTHON
, self
.OnGeneratePython
) 
 229         wx
.EVT_MENU(self
, wx
.ID_EXIT
, self
.OnExit
) 
 231         wx
.EVT_MENU(self
, wx
.ID_UNDO
, self
.OnUndo
) 
 232         wx
.EVT_MENU(self
, wx
.ID_REDO
, self
.OnRedo
) 
 233         wx
.EVT_MENU(self
, wx
.ID_CUT
, self
.OnCutDelete
) 
 234         wx
.EVT_MENU(self
, wx
.ID_COPY
, self
.OnCopy
) 
 235         wx
.EVT_MENU(self
, wx
.ID_PASTE
, self
.OnPaste
) 
 236         wx
.EVT_MENU(self
, self
.ID_TOOL_PASTE
, self
.OnPaste
) 
 237         wx
.EVT_MENU(self
, self
.ID_DELETE
, self
.OnCutDelete
) 
 238         wx
.EVT_MENU(self
, self
.ID_LOCATE
, self
.OnLocate
) 
 239         wx
.EVT_MENU(self
, self
.ID_TOOL_LOCATE
, self
.OnLocate
) 
 241         wx
.EVT_MENU(self
, self
.ID_EMBED_PANEL
, self
.OnEmbedPanel
) 
 242         wx
.EVT_MENU(self
, self
.ID_SHOW_TOOLS
, self
.OnShowTools
) 
 243         wx
.EVT_MENU(self
, self
.ID_TEST
, self
.OnTest
) 
 244         wx
.EVT_MENU(self
, self
.ID_REFRESH
, self
.OnRefresh
) 
 245         wx
.EVT_MENU(self
, self
.ID_AUTO_REFRESH
, self
.OnAutoRefresh
) 
 246         wx
.EVT_MENU(self
, self
.ID_TEST_HIDE
, self
.OnTestHide
) 
 248         wx
.EVT_MENU(self
, wx
.ID_ABOUT
, self
.OnAbout
) 
 249         wx
.EVT_MENU(self
, self
.ID_README
, self
.OnReadme
) 
 252         wx
.EVT_UPDATE_UI(self
, wx
.ID_SAVE
, self
.OnUpdateUI
) 
 253         wx
.EVT_UPDATE_UI(self
, wx
.ID_CUT
, self
.OnUpdateUI
) 
 254         wx
.EVT_UPDATE_UI(self
, wx
.ID_COPY
, self
.OnUpdateUI
) 
 255         wx
.EVT_UPDATE_UI(self
, wx
.ID_PASTE
, self
.OnUpdateUI
) 
 256         wx
.EVT_UPDATE_UI(self
, self
.ID_LOCATE
, self
.OnUpdateUI
) 
 257         wx
.EVT_UPDATE_UI(self
, self
.ID_TOOL_LOCATE
, self
.OnUpdateUI
) 
 258         wx
.EVT_UPDATE_UI(self
, self
.ID_TOOL_PASTE
, self
.OnUpdateUI
) 
 259         wx
.EVT_UPDATE_UI(self
, wx
.ID_UNDO
, self
.OnUpdateUI
) 
 260         wx
.EVT_UPDATE_UI(self
, wx
.ID_REDO
, self
.OnUpdateUI
) 
 261         wx
.EVT_UPDATE_UI(self
, self
.ID_DELETE
, self
.OnUpdateUI
) 
 262         wx
.EVT_UPDATE_UI(self
, self
.ID_TEST
, self
.OnUpdateUI
) 
 263         wx
.EVT_UPDATE_UI(self
, self
.ID_REFRESH
, self
.OnUpdateUI
) 
 266         sizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 267         sizer
.Add(wx
.StaticLine(self
, -1), 0, wx
.EXPAND
) 
 268         # Horizontal sizer for toolbar and splitter 
 269         self
.toolsSizer 
= sizer1 
= wx
.BoxSizer() 
 270         splitter 
= wx
.SplitterWindow(self
, -1, style
=wx
.SP_3DSASH
) 
 271         self
.splitter 
= splitter
 
 272         splitter
.SetMinimumPaneSize(100) 
 275         g
.tree 
= tree 
= XML_Tree(splitter
, -1) 
 277         # Init pull-down menu data 
 279         g
.pullDownMenu 
= pullDownMenu 
= PullDownMenu(self
) 
 281         # Vertical toolbar for GUI buttons 
 282         g
.tools 
= tools 
= Tools(self
) 
 283         tools
.Show(conf
.showTools
) 
 284         if conf
.showTools
: sizer1
.Add(tools
, 0, wx
.EXPAND
) 
 286         tree
.RegisterKeyEvents() 
 288         # !!! frame styles are broken 
 289         # Miniframe for not embedded mode 
 290         miniFrame 
= wx
.Frame(self
, -1, 'Properties & Style', 
 291                             (conf
.panelX
, conf
.panelY
), 
 292                             (conf
.panelWidth
, conf
.panelHeight
)) 
 293         self
.miniFrame 
= miniFrame
 
 294         sizer2 
= wx
.BoxSizer() 
 295         miniFrame
.SetAutoLayout(True) 
 296         miniFrame
.SetSizer(sizer2
) 
 297         wx
.EVT_CLOSE(self
.miniFrame
, self
.OnCloseMiniFrame
) 
 298         # Create panel for parameters 
 301             panel 
= Panel(splitter
) 
 302             # Set plitter windows 
 303             splitter
.SplitVertically(tree
, panel
, conf
.sashPos
) 
 305             panel 
= Panel(miniFrame
) 
 306             sizer2
.Add(panel
, 1, wx
.EXPAND
) 
 308             splitter
.Initialize(tree
) 
 309         sizer1
.Add(splitter
, 1, wx
.EXPAND
) 
 310         sizer
.Add(sizer1
, 1, wx
.EXPAND
) 
 311         self
.SetAutoLayout(True) 
 318         wx
.EVT_IDLE(self
, self
.OnIdle
) 
 319         wx
.EVT_CLOSE(self
, self
.OnCloseWindow
) 
 320         wx
.EVT_KEY_DOWN(self
, tools
.OnKeyDown
) 
 321         wx
.EVT_KEY_UP(self
, tools
.OnKeyUp
) 
 322         wx
.EVT_ICONIZE(self
, self
.OnIconize
) 
 324     def AppendRecent(self
, menu
): 
 325         # add recently used files to the menu 
 326         for id,name 
in conf
.recentfiles
.iteritems(): 
 328             wx
.EVT_MENU(self
,id,self
.OnRecentFile
) 
 331     def OnRecentFile(self
,evt
): 
 332         # open recently used file 
 333         if not self
.AskSave(): return 
 336             path
=conf
.recentfiles
[evt
.GetId()] 
 338                 self
.SetStatusText('Data loaded') 
 340                 self
.SetStatusText('Failed') 
 342             self
.SetStatusText('No such file') 
 345     def OnNew(self
, evt
): 
 346         if not self
.AskSave(): return 
 349     def OnOpen(self
, evt
): 
 350         if not self
.AskSave(): return 
 351         dlg 
= wx
.FileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
), 
 352                            '', '*.xrc', wx
.OPEN | wx
.CHANGE_DIR
) 
 353         if dlg
.ShowModal() == wx
.ID_OK
: 
 355             self
.SetStatusText('Loading...') 
 359                     self
.SetStatusText('Data loaded') 
 361                     self
.SetStatusText('Failed') 
 362                 self
.SaveRecent(path
) 
 367     def OnSaveOrSaveAs(self
, evt
): 
 368         if evt
.GetId() == wx
.ID_SAVEAS 
or not self
.dataFile
: 
 369             if self
.dataFile
: name 
= '' 
 370             else: name 
= defaultName
 
 371             dirname 
= os
.path
.abspath(os
.path
.dirname(self
.dataFile
)) 
 372             dlg 
= wx
.FileDialog(self
, 'Save As', dirname
, name
, '*.xrc', 
 373                                wx
.SAVE | wx
.OVERWRITE_PROMPT | wx
.CHANGE_DIR
) 
 374             if dlg
.ShowModal() == wx
.ID_OK
: 
 376                 if isinstance(path
, unicode): 
 377                     path 
= path
.encode(sys
.getfilesystemencoding()) 
 384                 # if we already have a localconf then it needs to be 
 385                 # copied to a new config with the new name 
 387                 nc 
= self
.CreateLocalConf(path
) 
 388                 flag
, key
, idx 
= lc
.GetFirstEntry() 
 390                     nc
.Write(key
, lc
.Read(key
)) 
 391                     flag
, key
, idx 
= lc
.GetNextEntry(idx
) 
 394                 # otherwise create a new one 
 395                 conf
.localconf 
= self
.CreateLocalConf(path
) 
 398         self
.SetStatusText('Saving...') 
 402                 tmpFile
,tmpName 
= tempfile
.mkstemp(prefix
='xrced-') 
 404                 self
.Save(tmpName
) # save temporary file first 
 405                 shutil
.move(tmpName
, path
) 
 407                 if conf
.localconf
.ReadBool("autogenerate", False): 
 408                     pypath 
= conf
.localconf
.Read("filename") 
 409                     embed 
= conf
.localconf
.ReadBool("embedResource", False) 
 410                     genGettext 
= conf
.localconf
.ReadBool("genGettext", False) 
 411                     self
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
) 
 413                 self
.SetStatusText('Data saved') 
 414                 self
.SaveRecent(path
) 
 416                 self
.SetStatusText('Failed') 
 420     def SaveRecent(self
,path
): 
 421         # append to recently used files 
 422         if path 
not in conf
.recentfiles
.values(): 
 424             self
.recentMenu
.Append(newid
, path
) 
 425             wx
.EVT_MENU(self
, newid
, self
.OnRecentFile
) 
 426             conf
.recentfiles
[newid
] = path
 
 428     def GeneratePython(self
, dataFile
, pypath
, embed
, genGettext
): 
 430             import wx
.tools
.pywxrc
 
 431             rescomp 
= wx
.tools
.pywxrc
.XmlResourceCompiler() 
 432             rescomp
.MakePythonModule([dataFile
], pypath
, embed
, genGettext
) 
 435             wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1]) 
 436             wx
.LogError('Error generating python code : %s' % pypath
) 
 440     def OnGeneratePython(self
, evt
): 
 441         if self
.modified 
or not conf
.localconf
: 
 442             wx
.MessageBox("Save the XRC file first!", "Error") 
 445         dlg 
= PythonOptions(self
, conf
.localconf
, self
.dataFile
) 
 450     def OnExit(self
, evt
): 
 453     def OnUndo(self
, evt
): 
 454         # Extra check to not mess with idle updating 
 455         if undoMan
.CanUndo(): 
 458     def OnRedo(self
, evt
): 
 459         if undoMan
.CanRedo(): 
 462     def OnCopy(self
, evt
): 
 463         selected 
= tree
.selection
 
 464         if not selected
: return         # key pressed event 
 465         xxx 
= tree
.GetPyData(selected
) 
 466         if wx
.TheClipboard
.Open(): 
 467             data 
= wx
.CustomDataObject('XRCED') 
 468             # Set encoding in header 
 470             s 
= xxx
.element
.toxml(encoding
=expat
.native_encoding
) 
 471             data
.SetData(cPickle
.dumps(s
)) 
 472             wx
.TheClipboard
.SetData(data
) 
 473             wx
.TheClipboard
.Close() 
 474             self
.SetStatusText('Copied') 
 476             wx
.MessageBox("Unable to open the clipboard", "Error") 
 478     def OnPaste(self
, evt
): 
 479         selected 
= tree
.selection
 
 480         if not selected
: return         # key pressed event 
 481         # For pasting with Ctrl pressed 
 483         if evt
.GetId() == pullDownMenu
.ID_PASTE_SIBLING
: appendChild 
= False 
 484         elif evt
.GetId() == self
.ID_TOOL_PASTE
: 
 485             if g
.tree
.ctrl
: appendChild 
= False 
 486             else: appendChild 
= not tree
.NeedInsert(selected
) 
 487         else: appendChild 
= not tree
.NeedInsert(selected
) 
 488         xxx 
= tree
.GetPyData(selected
) 
 490             # If has next item, insert, else append to parent 
 491             nextItem 
= tree
.GetNextSibling(selected
) 
 492             parentLeaf 
= tree
.GetItemParent(selected
) 
 493         # Expanded container (must have children) 
 494         elif tree
.IsExpanded(selected
) and tree
.GetChildrenCount(selected
, False): 
 495             # Insert as first child 
 496             nextItem 
= tree
.GetFirstChild(selected
)[0] 
 497             parentLeaf 
= selected
 
 499             # No children or unexpanded item - appendChild stays True 
 500             nextItem 
= wx
.TreeItemId()   # no next item 
 501             parentLeaf 
= selected
 
 502         parent 
= tree
.GetPyData(parentLeaf
).treeObject() 
 504         # Create a copy of clipboard pickled element 
 506         if wx
.TheClipboard
.Open(): 
 507             data 
= wx
.CustomDataObject('XRCED') 
 508             if wx
.TheClipboard
.IsSupported(data
.GetFormat()): 
 509                 success 
= wx
.TheClipboard
.GetData(data
) 
 510             wx
.TheClipboard
.Close() 
 514                 "There is no data in the clipboard in the required format", 
 518         xml 
= cPickle
.loads(data
.GetData()) # xml representation of element 
 519         elem 
= minidom
.parseString(xml
).childNodes
[0] 
 520         # Tempopary xxx object to test things 
 521         xxx 
= MakeXXXFromDOM(parent
, elem
) 
 522         # Check compatibility 
 526         if x
.__class
__ in [xxxDialog
, xxxFrame
, xxxWizard
]: 
 528             if parent
.__class
__ != xxxMainNode
: error 
= True 
 529         elif x
.__class
__ == xxxMenuBar
: 
 530             # Menubar can be put in frame or dialog 
 531             if parent
.__class
__ not in [xxxMainNode
, xxxFrame
, xxxDialog
]: error 
= True 
 532         elif x
.__class
__ == xxxToolBar
: 
 533             # Toolbar can be top-level of child of panel or frame 
 534             if parent
.__class
__ not in [xxxMainNode
, xxxPanel
, xxxFrame
] and \
 
 535                not parent
.isSizer
: error 
= True 
 536         elif x
.__class
__ == xxxPanel 
and parent
.__class
__ == xxxMainNode
: 
 538         elif x
.__class
__ == xxxSpacer
: 
 539             if not parent
.isSizer
: error 
= True 
 540         elif x
.__class
__ == xxxSeparator
: 
 541             if not parent
.__class
__ in [xxxMenu
, xxxToolBar
]: error 
= True 
 542         elif x
.__class
__ == xxxTool
: 
 543             if parent
.__class
__ != xxxToolBar
: error 
= True 
 544         elif x
.__class
__ == xxxMenu
: 
 545             if not parent
.__class
__ in [xxxMainNode
, xxxMenuBar
, xxxMenu
]: error 
= True 
 546         elif x
.__class
__ == xxxMenuItem
: 
 547             if not parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error 
= True 
 548         elif x
.isSizer 
and parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
]: 
 550         else:                           # normal controls can be almost anywhere 
 551             if parent
.__class
__ == xxxMainNode 
or \
 
 552                parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error 
= True 
 554             if parent
.__class
__ == xxxMainNode
: parentClass 
= 'root' 
 555             else: parentClass 
= parent
.className
 
 556             wx
.LogError('Incompatible parent/child: parent is %s, child is %s!' % 
 557                        (parentClass
, x
.className
)) 
 560         # Check parent and child relationships. 
 561         # If parent is sizer or notebook, child is of wrong class or 
 562         # parent is normal window, child is child container then detach child. 
 563         isChildContainer 
= isinstance(xxx
, xxxChildContainer
) 
 564         parentIsBook 
= parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
] 
 565         if isChildContainer 
and \
 
 566            ((parent
.isSizer 
and not isinstance(xxx
, xxxSizerItem
)) or \
 
 567             (parentIsBook 
and not isinstance(xxx
, xxxPage
)) or \
 
 568            not (parent
.isSizer 
or parentIsBook
)): 
 569             elem
.removeChild(xxx
.child
.element
) # detach child 
 570             elem
.unlink()           # delete child container 
 571             elem 
= xxx
.child
.element 
# replace 
 572             # This may help garbage collection 
 573             xxx
.child
.parent 
= None 
 574             isChildContainer 
= False 
 575         # Parent is sizer or notebook, child is not child container 
 576         if parent
.isSizer 
and not isChildContainer 
and not isinstance(xxx
, xxxSpacer
): 
 577             # Create sizer item element 
 578             sizerItemElem 
= MakeEmptyDOM(parent
.itemTag
) 
 579             sizerItemElem
.appendChild(elem
) 
 581         elif isinstance(parent
, xxxNotebook
) and not isChildContainer
: 
 582             pageElem 
= MakeEmptyDOM('notebookpage') 
 583             pageElem
.appendChild(elem
) 
 585         elif isinstance(parent
, xxxChoicebook
) and not isChildContainer
: 
 586             pageElem 
= MakeEmptyDOM('choicebookpage') 
 587             pageElem
.appendChild(elem
) 
 589         elif isinstance(parent
, xxxListbook
) and not isChildContainer
: 
 590             pageElem 
= MakeEmptyDOM('listbookpage') 
 591             pageElem
.appendChild(elem
) 
 593         # Insert new node, register undo 
 594         newItem 
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
) 
 595         undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
)) 
 596         # Scroll to show new item (!!! redundant?) 
 597         tree
.EnsureVisible(newItem
) 
 598         tree
.SelectItem(newItem
) 
 599         if not tree
.IsVisible(newItem
): 
 600             tree
.ScrollTo(newItem
) 
 603         if g
.testWin 
and tree
.IsHighlatable(newItem
): 
 605                 tree
.needUpdate 
= True 
 606                 tree
.pendingHighLight 
= newItem
 
 608                 tree
.pendingHighLight 
= None 
 610         self
.SetStatusText('Pasted') 
 613     def OnCutDelete(self
, evt
): 
 614         selected 
= tree
.selection
 
 615         if not selected
: return         # key pressed event 
 617         if evt
.GetId() == wx
.ID_CUT
: 
 619             status 
= 'Removed to clipboard' 
 621             self
.lastOp 
= 'DELETE' 
 625             # If deleting top-level item, delete testWin 
 626             if selected 
== g
.testWin
.item
: 
 630                 # Remove highlight, update testWin 
 631                 if g
.testWin
.highLight
: 
 632                     g
.testWin
.highLight
.Remove() 
 633                 tree
.needUpdate 
= True 
 636         index 
= tree
.ItemFullIndex(selected
) 
 637         parent 
= tree
.GetPyData(tree
.GetItemParent(selected
)).treeObject() 
 638         elem 
= tree
.RemoveLeaf(selected
) 
 639         undoMan
.RegisterUndo(UndoCutDelete(index
, parent
, elem
)) 
 640         if evt
.GetId() == wx
.ID_CUT
: 
 641             if wx
.TheClipboard
.Open(): 
 642                 data 
= wx
.CustomDataObject('XRCED') 
 644                 s 
= elem
.toxml(encoding
=expat
.native_encoding
) 
 645                 data
.SetData(cPickle
.dumps(s
)) 
 646                 wx
.TheClipboard
.SetData(data
) 
 647                 wx
.TheClipboard
.Close() 
 649                 wx
.MessageBox("Unable to open the clipboard", "Error") 
 650         tree
.pendingHighLight 
= None 
 652         tree
.selection 
= None 
 657         self
.SetStatusText(status
) 
 659     def OnSubclass(self
, evt
): 
 660         selected 
= tree
.selection
 
 661         xxx 
= tree
.GetPyData(selected
).treeObject() 
 663         subclass 
= xxx
.subclass
 
 664         dlg 
= wx
.TextEntryDialog(self
, 'Subclass:', defaultValue
=subclass
) 
 665         if dlg
.ShowModal() == wx
.ID_OK
: 
 666             subclass 
= dlg
.GetValue() 
 668                 elem
.setAttribute('subclass', subclass
) 
 669             elif elem
.hasAttribute('subclass'): 
 670                 elem
.removeAttribute('subclass') 
 672             xxx
.subclass 
= elem
.getAttribute('subclass') 
 673             tree
.SetItemText(selected
, xxx
.treeName()) 
 674             panel
.pages
[0].box
.SetLabel(xxx
.panelName()) 
 677     def OnEmbedPanel(self
, evt
): 
 678         conf
.embedPanel 
= evt
.IsChecked() 
 680             # Remember last dimentions 
 681             conf
.panelX
, conf
.panelY 
= self
.miniFrame
.GetPosition() 
 682             conf
.panelWidth
, conf
.panelHeight 
= self
.miniFrame
.GetSize() 
 683             size 
= self
.GetSize() 
 684             pos 
= self
.GetPosition() 
 685             sizePanel 
= panel
.GetSize() 
 686             panel
.Reparent(self
.splitter
) 
 687             self
.miniFrame
.GetSizer().Remove(panel
) 
 689             self
.SetDimensions(pos
.x
, pos
.y
, size
.width 
+ sizePanel
.width
, size
.height
) 
 690             self
.splitter
.SplitVertically(tree
, panel
, conf
.sashPos
) 
 691             self
.miniFrame
.Show(False) 
 693             conf
.sashPos 
= self
.splitter
.GetSashPosition() 
 694             pos 
= self
.GetPosition() 
 695             size 
= self
.GetSize() 
 696             sizePanel 
= panel
.GetSize() 
 697             self
.splitter
.Unsplit(panel
) 
 698             sizer 
= self
.miniFrame
.GetSizer() 
 699             panel
.Reparent(self
.miniFrame
) 
 701             sizer
.Add(panel
, 1, wx
.EXPAND
) 
 702             self
.miniFrame
.Show(True) 
 703             self
.miniFrame
.SetDimensions(conf
.panelX
, conf
.panelY
, 
 704                                          conf
.panelWidth
, conf
.panelHeight
) 
 706             self
.SetDimensions(pos
.x
, pos
.y
, 
 707                                max(size
.width 
- sizePanel
.width
, self
.minWidth
), size
.height
) 
 709     def OnShowTools(self
, evt
): 
 710         conf
.showTools 
= evt
.IsChecked() 
 711         g
.tools
.Show(conf
.showTools
) 
 713             self
.toolsSizer
.Prepend(g
.tools
, 0, wx
.EXPAND
) 
 715             self
.toolsSizer
.Remove(g
.tools
) 
 716         self
.toolsSizer
.Layout() 
 718     def OnTest(self
, evt
): 
 719         if not tree
.selection
: return   # key pressed event 
 720         tree
.ShowTestWindow(tree
.selection
) 
 722     def OnTestHide(self
, evt
): 
 723         tree
.CloseTestWindow() 
 725     # Find object by relative position 
 726     def FindObject(self
, item
, obj
): 
 727         # We simply perform depth-first traversal, sinse it's too much 
 728         # hassle to deal with all sizer/window combinations 
 729         w 
= tree
.FindNodeObject(item
) 
 730         if w 
== obj 
or isinstance(w
, wx
.GBSizerItem
) and w
.GetWindow() == obj
: 
 732         if tree
.ItemHasChildren(item
): 
 733             child 
= tree
.GetFirstChild(item
)[0] 
 735                 found 
= self
.FindObject(child
, obj
) 
 736                 if found
: return found
 
 737                 child 
= tree
.GetNextSibling(child
) 
 740     def OnTestWinLeftDown(self
, evt
): 
 741         pos 
= evt
.GetPosition() 
 742         self
.SetHandler(g
.testWin
) 
 743         g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
) 
 744         item 
= self
.FindObject(g
.testWin
.item
, evt
.GetEventObject()) 
 746             tree
.EnsureVisible(item
) 
 747             tree
.SelectItem(item
) 
 748         self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, False) 
 750             self
.SetStatusText('Selected %s' % tree
.GetItemText(item
)) 
 752             self
.SetStatusText('Locate failed!') 
 754     def SetHandler(self
, w
, h
=None): 
 757             w
.SetCursor(wx
.CROSS_CURSOR
) 
 760             w
.SetCursor(wx
.NullCursor
) 
 761         for ch 
in w
.GetChildren(): 
 762             self
.SetHandler(ch
, h
) 
 764     def OnLocate(self
, evt
): 
 766             if evt
.GetId() == self
.ID_LOCATE 
or \
 
 767                evt
.GetId() == self
.ID_TOOL_LOCATE 
and evt
.IsChecked(): 
 768                 self
.SetHandler(g
.testWin
, g
.testWin
) 
 769                 g
.testWin
.Connect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
, self
.OnTestWinLeftDown
) 
 770                 if evt
.GetId() == self
.ID_LOCATE
: 
 771                     self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, True) 
 772             elif evt
.GetId() == self
.ID_TOOL_LOCATE 
and not evt
.IsChecked(): 
 773                 self
.SetHandler(g
.testWin
, None) 
 774                 g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
) 
 775             self
.SetStatusText('Click somewhere in your test window now') 
 777     def OnRefresh(self
, evt
): 
 778         # If modified, apply first 
 779         selection 
= tree
.selection
 
 781             xxx 
= tree
.GetPyData(selection
) 
 782             if xxx 
and panel
.IsModified(): 
 783                 tree
.Apply(xxx
, selection
) 
 786             tree
.CreateTestWin(g
.testWin
.item
) 
 787         panel
.modified 
= False 
 788         tree
.needUpdate 
= False 
 790     def OnAutoRefresh(self
, evt
): 
 791         conf
.autoRefresh 
= evt
.IsChecked() 
 792         self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 793         self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 795     def OnAbout(self
, evt
): 
 799 (c) Roman Rolinsky <rollrom@users.sourceforge.net> 
 800 Homepage: http://xrced.sourceforge.net\ 
 802         dlg 
= wx
.MessageDialog(self
, str, 'About XRCed', wx
.OK | wx
.CENTRE
) 
 806     def OnReadme(self
, evt
): 
 807         text 
= open(os
.path
.join(basePath
, 'README.txt'), 'r').read() 
 808         dlg 
= ScrolledMessageDialog(self
, text
, "XRCed README") 
 812     # Simple emulation of python command line 
 813     def OnDebugCMD(self
, evt
): 
 816                 exec raw_input('C:\> ') 
 821                 (etype
, value
, tb
) =sys
.exc_info() 
 822                 tblist 
=traceback
.extract_tb(tb
)[1:] 
 823                 msg 
=' '.join(traceback
.format_exception_only(etype
, value
) 
 824                         +traceback
.format_list(tblist
)) 
 827     def OnCreate(self
, evt
): 
 828         selected 
= tree
.selection
 
 829         if tree
.ctrl
: appendChild 
= False 
 830         else: appendChild 
= not tree
.NeedInsert(selected
) 
 831         xxx 
= tree
.GetPyData(selected
) 
 835                 # If has previous item, insert after it, else append to parent 
 837                 parentLeaf 
= tree
.GetItemParent(selected
) 
 839                 # If has next item, insert, else append to parent 
 840                 nextItem 
= tree
.GetNextSibling(selected
) 
 841                 parentLeaf 
= tree
.GetItemParent(selected
) 
 842         # Expanded container (must have children) 
 843         elif tree
.shift 
and tree
.IsExpanded(selected
) \
 
 844            and tree
.GetChildrenCount(selected
, False): 
 845             nextItem 
= tree
.GetFirstChild(selected
)[0] 
 846             parentLeaf 
= selected
 
 848             nextItem 
= wx
.TreeItemId() 
 849             parentLeaf 
= selected
 
 850         parent 
= tree
.GetPyData(parentLeaf
) 
 851         if parent
.hasChild
: parent 
= parent
.child
 
 854         if evt
.GetId() == ID_NEW
.REF
: 
 855             ref 
= wx
.GetTextFromUser('Create reference to:', 'Create reference') 
 857             xxx 
= MakeEmptyRefXXX(parent
, ref
) 
 859             # Create empty element 
 860             className 
= pullDownMenu
.createMap
[evt
.GetId()] 
 861             xxx 
= MakeEmptyXXX(parent
, className
) 
 863         # Set default name for top-level windows 
 864         if parent
.__class
__ == xxxMainNode
: 
 865             cl 
= xxx
.treeObject().__class
__ 
 866             frame
.maxIDs
[cl
] += 1 
 867             xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
])) 
 868         # And for some other standard controls 
 869         elif parent
.__class
__ == xxxStdDialogButtonSizer
: 
 870             xxx
.setTreeName(pullDownMenu
.stdButtonIDs
[evt
.GetId()][0]) 
 871             # We can even set label 
 872             obj 
= xxx
.treeObject() 
 873             elem 
= g
.tree
.dom
.createElement('label') 
 874             elem
.appendChild(g
.tree
.dom
.createTextNode(pullDownMenu
.stdButtonIDs
[evt
.GetId()][1])) 
 875             obj
.params
['label'] = xxxParam(elem
) 
 876             xxx
.treeObject().element
.appendChild(elem
) 
 878         # Insert new node, register undo 
 880         newItem 
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
) 
 881         undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
)) 
 882         tree
.EnsureVisible(newItem
) 
 883         tree
.SelectItem(newItem
) 
 884         if not tree
.IsVisible(newItem
): 
 885             tree
.ScrollTo(newItem
) 
 888         if g
.testWin 
and tree
.IsHighlatable(newItem
): 
 890                 tree
.needUpdate 
= True 
 891                 tree
.pendingHighLight 
= newItem
 
 893                 tree
.pendingHighLight 
= None 
 897     # Replace one object with another 
 898     def OnReplace(self
, evt
): 
 899         selected 
= tree
.selection
 
 900         xxx 
= tree
.GetPyData(selected
).treeObject() 
 902         parent 
= elem
.parentNode
 
 903         undoMan
.RegisterUndo(UndoReplace(selected
)) 
 905         className 
= pullDownMenu
.createMap
[evt
.GetId() - 1000] 
 906         # Create temporary empty node (with default values) 
 907         dummy 
= MakeEmptyDOM(className
) 
 908         if className 
== 'spacer' and xxx
.className 
!= 'spacer': 
 910         elif xxx
.className 
== 'spacer' and className 
!= 'spacer': 
 913             klass 
= xxxDict
[className
] 
 914         # Remove non-compatible children 
 915         if tree
.ItemHasChildren(selected
) and not klass
.hasChildren
: 
 916             tree
.DeleteChildren(selected
) 
 917         nodes 
= elem
.childNodes
[:] 
 920             if node
.nodeType 
!= minidom
.Node
.ELEMENT_NODE
: continue 
 924                 if not klass
.hasChildren
:  remove 
= True 
 925             elif tag 
not in klass
.allParams 
and \
 
 926                      (not klass
.hasStyle 
or tag 
not in klass
.styles
): 
 931                 elem
.removeChild(node
) 
 934         # Remove sizeritem child if spacer 
 935         if className 
== 'spacer' and xxx
.className 
!= 'spacer': 
 936             sizeritem 
= elem
.parentNode
 
 937             assert sizeritem
.getAttribute('class') == 'sizeritem' 
 938             sizeritem
.removeChild(elem
) 
 941             tree
.GetPyData(selected
).hasChild 
= false
 
 942         elif xxx
.className 
== 'spacer' and className 
!= 'spacer': 
 943             # Create sizeritem element 
 944             assert xxx
.parent
.isSizer
 
 945             elem
.setAttribute('class', 'sizeritem') 
 946             node 
= MakeEmptyDOM(className
) 
 947             elem
.appendChild(node
) 
 948             # Replace to point to new object 
 949             xxx 
= xxxSizerItem(xxx
.parent
, elem
) 
 951             tree
.SetPyData(selected
, xxx
) 
 954             # Copy parameters present in dummy but not in elem 
 955             for node 
in dummy
.childNodes
: 
 956                 if node
.tagName 
not in tags
:  elem
.appendChild(node
.cloneNode(True)) 
 960         elem
.setAttribute('class', className
) 
 961         if elem
.hasAttribute('subclass'): 
 962             elem
.removeAttribute('subclass') # clear subclassing 
 963         # Re-create xxx element 
 964         xxx 
= MakeXXXFromDOM(xxx
.parent
, elem
) 
 965         # Update parent in child objects 
 966         if tree
.ItemHasChildren(selected
): 
 967             i
, cookie 
= tree
.GetFirstChild(selected
) 
 969                 x 
= tree
.GetPyData(i
) 
 971                 if x
.hasChild
: x
.child
.parent 
= xxx
 
 972                 i
, cookie 
= tree
.GetNextChild(selected
, cookie
) 
 975         if tree
.GetPyData(selected
).hasChild
: # child container 
 976             container 
= tree
.GetPyData(selected
) 
 977             container
.child 
= xxx
 
 978             container
.hasChildren 
= xxx
.hasChildren
 
 979             container
.isSizer 
= xxx
.isSizer
 
 982             tree
.SetPyData(selected
, xxx
) 
 983         tree
.SetItemText(selected
, xxx
.treeName()) 
 984         tree
.SetItemImage(selected
, xxx
.treeImage()) 
 986         # Set default name for top-level windows 
 987         if parent
.__class
__ == xxxMainNode
: 
 988             cl 
= xxx
.treeObject().__class
__ 
 989             frame
.maxIDs
[cl
] += 1 
 990             xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
])) 
 997         #undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected)) 
 999         if g
.testWin 
and tree
.IsHighlatable(selected
): 
1000             if conf
.autoRefresh
: 
1001                 tree
.needUpdate 
= True 
1002                 tree
.pendingHighLight 
= selected
 
1004                 tree
.pendingHighLight 
= None 
1008     # Expand/collapse subtree 
1009     def OnExpand(self
, evt
): 
1010         if tree
.selection
: tree
.ExpandAll(tree
.selection
) 
1011         else: tree
.ExpandAll(tree
.root
) 
1012     def OnCollapse(self
, evt
): 
1013         if tree
.selection
: tree
.CollapseAll(tree
.selection
) 
1014         else: tree
.CollapseAll(tree
.root
) 
1016     def OnPullDownHighlight(self
, evt
): 
1017         menuId 
= evt
.GetMenuId() 
1019             menu 
= evt
.GetEventObject() 
1020             help = menu
.GetHelpString(menuId
) 
1021             self
.SetStatusText(help) 
1023             self
.SetStatusText('') 
1025     def OnUpdateUI(self
, evt
): 
1026         if evt
.GetId() in [wx
.ID_CUT
, wx
.ID_COPY
, self
.ID_DELETE
]: 
1027             evt
.Enable(tree
.selection 
is not None and tree
.selection 
!= tree
.root
) 
1028         elif evt
.GetId() == wx
.ID_SAVE
: 
1029             evt
.Enable(self
.modified
) 
1030         elif evt
.GetId() in [wx
.ID_PASTE
, self
.ID_TOOL_PASTE
]: 
1031             evt
.Enable(tree
.selection 
is not None) 
1032         elif evt
.GetId() == self
.ID_TEST
: 
1033             evt
.Enable(tree
.selection 
is not None and tree
.selection 
!= tree
.root
) 
1034         elif evt
.GetId() in [self
.ID_LOCATE
, self
.ID_TOOL_LOCATE
]: 
1035             evt
.Enable(g
.testWin 
is not None) 
1036         elif evt
.GetId() == wx
.ID_UNDO
:  evt
.Enable(undoMan
.CanUndo()) 
1037         elif evt
.GetId() == wx
.ID_REDO
:  evt
.Enable(undoMan
.CanRedo()) 
1039     def OnIdle(self
, evt
): 
1040         if self
.inIdle
: return          # Recursive call protection 
1044                 if conf
.autoRefresh
: 
1046                         self
.SetStatusText('Refreshing test window...') 
1048                         tree
.CreateTestWin(g
.testWin
.item
) 
1049                         self
.SetStatusText('') 
1050                     tree
.needUpdate 
= False 
1051             elif tree
.pendingHighLight
: 
1053                     tree
.HighLight(tree
.pendingHighLight
) 
1055                     # Remove highlight if any problem 
1056                     if g
.testWin
.highLight
: 
1057                         g
.testWin
.highLight
.Remove() 
1058                     tree
.pendingHighLight 
= None 
1065     # We don't let close panel window 
1066     def OnCloseMiniFrame(self
, evt
): 
1069     def OnIconize(self
, evt
): 
1070         conf
.x
, conf
.y 
= self
.GetPosition() 
1071         conf
.width
, conf
.height 
= self
.GetSize() 
1073             conf
.sashPos 
= self
.splitter
.GetSashPosition() 
1075             conf
.panelX
, conf
.panelY 
= self
.miniFrame
.GetPosition() 
1076             conf
.panelWidth
, conf
.panelHeight 
= self
.miniFrame
.GetSize() 
1077             self
.miniFrame
.Iconize() 
1080     def OnCloseWindow(self
, evt
): 
1081         if not self
.AskSave(): return 
1082         if g
.testWin
: g
.testWin
.Destroy() 
1083         if not panel
.GetPageCount() == 2: 
1084             panel
.page2
.Destroy() 
1086             # If we don't do this, page does not get destroyed (a bug?) 
1088         if not self
.IsIconized(): 
1089             conf
.x
, conf
.y 
= self
.GetPosition() 
1090             conf
.width
, conf
.height 
= self
.GetSize() 
1092                 conf
.sashPos 
= self
.splitter
.GetSashPosition() 
1094                 conf
.panelX
, conf
.panelY 
= self
.miniFrame
.GetPosition() 
1095                 conf
.panelWidth
, conf
.panelHeight 
= self
.miniFrame
.GetSize() 
1099     def CreateLocalConf(self
, path
): 
1100         name 
= os
.path
.splitext(path
)[0] 
1102         return wx
.FileConfig(localFilename
=name
) 
1107         conf
.localconf 
= None 
1109         self
.SetModified(False) 
1115         # Numbers for new controls 
1117         for cl 
in [xxxPanel
, xxxDialog
, xxxFrame
, 
1118                    xxxMenuBar
, xxxMenu
, xxxToolBar
, 
1119                    xxxWizard
, xxxBitmap
, xxxIcon
]: 
1122     def SetModified(self
, state
=True): 
1123         self
.modified 
= state
 
1124         name 
= os
.path
.basename(self
.dataFile
) 
1125         if not name
: name 
= defaultName
 
1127             self
.SetTitle(progname 
+ ': ' + name 
+ ' *') 
1129             self
.SetTitle(progname 
+ ': ' + name
) 
1131     def Open(self
, path
): 
1132         if not os
.path
.exists(path
): 
1133             wx
.LogError('File does not exists: %s' % path
) 
1135         # Try to read the file 
1139             dom 
= minidom
.parse(f
) 
1141             # Set encoding global variable and default encoding 
1143                 g
.currentEncoding 
= dom
.encoding
 
1144                 wx
.SetDefaultPyEncoding(g
.currentEncoding
.encode()) 
1146                 g
.currentEncoding 
= '' 
1148             self
.dataFile 
= path 
= os
.path
.abspath(path
) 
1149             dir = os
.path
.dirname(path
) 
1150             if dir: os
.chdir(dir) 
1152             self
.SetTitle(progname 
+ ': ' + os
.path
.basename(path
)) 
1153             conf
.localconf 
= self
.CreateLocalConf(self
.dataFile
) 
1155             # Nice exception printing 
1156             inf 
= sys
.exc_info() 
1157             wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1]) 
1158             wx
.LogError('Error reading file: %s' % path
) 
1163     def Indent(self
, node
, indent 
= 0): 
1164         # Copy child list because it will change soon 
1165         children 
= node
.childNodes
[:] 
1166         # Main node doesn't need to be indented 
1168             text 
= self
.domCopy
.createTextNode('\n' + ' ' * indent
) 
1169             node
.parentNode
.insertBefore(text
, node
) 
1171             # Append newline after last child, except for text nodes 
1172             if children
[-1].nodeType 
== minidom
.Node
.ELEMENT_NODE
: 
1173                 text 
= self
.domCopy
.createTextNode('\n' + ' ' * indent
) 
1174                 node
.appendChild(text
) 
1175             # Indent children which are elements 
1177                 if n
.nodeType 
== minidom
.Node
.ELEMENT_NODE
: 
1178                     self
.Indent(n
, indent 
+ 2) 
1180     def Save(self
, path
): 
1184             if tree
.selection 
and panel
.IsModified(): 
1185                 self
.OnRefresh(wx
.CommandEvent()) 
1186             if g
.currentEncoding
: 
1187                 f 
= codecs
.open(path
, 'wt', g
.currentEncoding
) 
1189                 f 
= codecs
.open(path
, 'wt') 
1190             # Make temporary copy for formatting it 
1191             # !!! We can't clone dom node, it works only once 
1192             #self.domCopy = tree.dom.cloneNode(True) 
1193             self
.domCopy 
= MyDocument() 
1194             mainNode 
= self
.domCopy
.appendChild(tree
.mainNode
.cloneNode(True)) 
1195             # Remove first child (test element) 
1196             testElem 
= mainNode
.firstChild
 
1197             mainNode
.removeChild(testElem
) 
1199             self
.Indent(mainNode
) 
1200             self
.domCopy
.writexml(f
, encoding 
= g
.currentEncoding
) 
1202             self
.domCopy
.unlink() 
1204             self
.SetModified(False) 
1205             panel
.SetModified(False) 
1206             conf
.localconf
.Flush() 
1208             inf 
= sys
.exc_info() 
1209             wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1]) 
1210             wx
.LogError('Error writing file: %s' % path
) 
1214         if not (self
.modified 
or panel
.IsModified()): return True 
1215         flags 
= wx
.ICON_EXCLAMATION | wx
.YES_NO | wx
.CANCEL | wx
.CENTRE
 
1216         dlg 
= wx
.MessageDialog( self
, 'File is modified. Save before exit?', 
1217                                'Save before too late?', flags 
) 
1218         say 
= dlg
.ShowModal() 
1221         if say 
== wx
.ID_YES
: 
1222             self
.OnSaveOrSaveAs(wx
.CommandEvent(wx
.ID_SAVE
)) 
1223             # If save was successful, modified flag is unset 
1224             if not self
.modified
: return True 
1225         elif say 
== wx
.ID_NO
: 
1226             self
.SetModified(False) 
1227             panel
.SetModified(False) 
1234 ################################################################################ 
1236 class PythonOptions(wx
.Dialog
): 
1238     def __init__(self
, parent
, cfg
, dataFile
): 
1239         pre 
= wx
.PreDialog() 
1240         g
.frame
.res
.LoadOnDialog(pre
, parent
, "PYTHON_OPTIONS") 
1241         self
.PostCreate(pre
) 
1244         self
.dataFile 
= dataFile
 
1246         self
.AutoGenerateCB 
= xrc
.XRCCTRL(self
, "AutoGenerateCB") 
1247         self
.EmbedCB 
= xrc
.XRCCTRL(self
, "EmbedCB") 
1248         self
.GettextCB 
= xrc
.XRCCTRL(self
, "GettextCB") 
1249         self
.MakeXRSFileCB 
= xrc
.XRCCTRL(self
, "MakeXRSFileCB") 
1250         self
.FileNameTC 
= xrc
.XRCCTRL(self
, "FileNameTC") 
1251         self
.BrowseBtn 
= xrc
.XRCCTRL(self
, "BrowseBtn") 
1252         self
.GenerateBtn 
= xrc
.XRCCTRL(self
, "GenerateBtn") 
1253         self
.SaveOptsBtn 
= xrc
.XRCCTRL(self
, "SaveOptsBtn") 
1255         self
.Bind(wx
.EVT_BUTTON
, self
.OnBrowse
, self
.BrowseBtn
) 
1256         self
.Bind(wx
.EVT_BUTTON
, self
.OnGenerate
, self
.GenerateBtn
) 
1257         self
.Bind(wx
.EVT_BUTTON
, self
.OnSaveOpts
, self
.SaveOptsBtn
) 
1259         if self
.cfg
.Read("filename", "") != "": 
1260             self
.FileNameTC
.SetValue(self
.cfg
.Read("filename")) 
1262             name 
= os
.path
.splitext(os
.path
.split(dataFile
)[1])[0] 
1264             self
.FileNameTC
.SetValue(name
) 
1265         self
.AutoGenerateCB
.SetValue(self
.cfg
.ReadBool("autogenerate", False)) 
1266         self
.EmbedCB
.SetValue(self
.cfg
.ReadBool("embedResource", False)) 
1267         self
.MakeXRSFileCB
.SetValue(self
.cfg
.ReadBool("makeXRS", False)) 
1268         self
.GettextCB
.SetValue(self
.cfg
.ReadBool("genGettext", False)) 
1271     def OnBrowse(self
, evt
): 
1272         path 
= self
.FileNameTC
.GetValue() 
1273         dirname 
= os
.path
.abspath(os
.path
.dirname(path
)) 
1274         name 
= os
.path
.split(path
)[1] 
1275         dlg 
= wx
.FileDialog(self
, 'Save As', dirname
, name
, '*.py', 
1276                                wx
.SAVE | wx
.OVERWRITE_PROMPT
) 
1277         if dlg
.ShowModal() == wx
.ID_OK
: 
1278             path 
= dlg
.GetPath() 
1279             self
.FileNameTC
.SetValue(path
) 
1283     def OnGenerate(self
, evt
): 
1284         pypath 
= self
.FileNameTC
.GetValue() 
1285         embed 
= self
.EmbedCB
.GetValue() 
1286         genGettext 
= self
.GettextCB
.GetValue() 
1287         frame
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
) 
1291     def OnSaveOpts(self
, evt
=None): 
1292         self
.cfg
.Write("filename", self
.FileNameTC
.GetValue()) 
1293         self
.cfg
.WriteBool("autogenerate", self
.AutoGenerateCB
.GetValue()) 
1294         self
.cfg
.WriteBool("embedResource", self
.EmbedCB
.GetValue()) 
1295         self
.cfg
.WriteBool("makeXRS", self
.MakeXRSFileCB
.GetValue()) 
1296         self
.cfg
.WriteBool("genGettext", self
.GettextCB
.GetValue()) 
1298         self
.EndModal(wx
.ID_OK
) 
1301 ################################################################################ 
1304     print >> sys
.stderr
, 'usage: xrced [-dhiv] [file]' 
1309         if wx
.VERSION
[:3] < MinWxVersion
: 
1311 This version of XRCed may not work correctly on your version of wxWidgets. \ 
1312 Please upgrade wxWidgets to %d.%d.%d or higher.''' % MinWxVersion
) 
1314         # Process comand-line 
1317             opts
, args 
= getopt
.getopt(sys
.argv
[1:], 'dhiv') 
1325                     print 'XRCed version', version
 
1328         except getopt
.GetoptError
: 
1329             if wx
.Platform 
!= '__WXMAC__': # macs have some extra parameters 
1330                 print >> sys
.stderr
, 'Unknown option' 
1334         self
.SetAppName('xrced') 
1337         conf 
= g
.conf 
= wx
.Config(style 
= wx
.CONFIG_USE_LOCAL_FILE
) 
1338         conf
.localconf 
= None 
1339         conf
.autoRefresh 
= conf
.ReadInt('autorefresh', True) 
1340         pos 
= conf
.ReadInt('x', -1), conf
.ReadInt('y', -1) 
1341         size 
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600) 
1342         conf
.embedPanel 
= conf
.ReadInt('embedPanel', True) 
1343         conf
.showTools 
= conf
.ReadInt('showTools', True) 
1344         conf
.sashPos 
= conf
.ReadInt('sashPos', 200) 
1345         # read recently used files 
1346         recentfiles
=conf
.Read('recentFiles','') 
1349             for fil 
in recentfiles
.split('|'): 
1350                 conf
.recentfiles
[wx
.NewId()]=fil
 
1351         if not conf
.embedPanel
: 
1352             conf
.panelX 
= conf
.ReadInt('panelX', -1) 
1353             conf
.panelY 
= conf
.ReadInt('panelY', -1) 
1355             conf
.panelX 
= conf
.panelY 
= -1 
1356         conf
.panelWidth 
= conf
.ReadInt('panelWidth', 200) 
1357         conf
.panelHeight 
= conf
.ReadInt('panelHeight', 200) 
1358         conf
.panic 
= not conf
.HasEntry('nopanic') 
1360         wx
.FileSystem
.AddHandler(wx
.MemoryFSHandler()) 
1362         frame 
= Frame(pos
, size
) 
1365         # Load file after showing 
1368             frame
.open = frame
.Open(args
[0]) 
1376         wc
.WriteInt('autorefresh', conf
.autoRefresh
) 
1377         wc
.WriteInt('x', conf
.x
) 
1378         wc
.WriteInt('y', conf
.y
) 
1379         wc
.WriteInt('width', conf
.width
) 
1380         wc
.WriteInt('height', conf
.height
) 
1381         wc
.WriteInt('embedPanel', conf
.embedPanel
) 
1382         wc
.WriteInt('showTools', conf
.showTools
) 
1383         if not conf
.embedPanel
: 
1384             wc
.WriteInt('panelX', conf
.panelX
) 
1385             wc
.WriteInt('panelY', conf
.panelY
) 
1386         wc
.WriteInt('sashPos', conf
.sashPos
) 
1387         wc
.WriteInt('panelWidth', conf
.panelWidth
) 
1388         wc
.WriteInt('panelHeight', conf
.panelHeight
) 
1389         wc
.WriteInt('nopanic', True) 
1390         wc
.Write('recentFiles', '|'.join(conf
.recentfiles
.values()[-5:])) 
1394     app 
= App(0, useBestVisual
=False) 
1395     #app.SetAssertMode(wx.PYAPP_ASSERT_LOG) 
1401 if __name__ 
== '__main__':