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 from params 
import genericStyles
 
  32 # Cleanup recursive import sideeffects, otherwise we can't create undoMan 
  34 undo
.ParamPage 
= ParamPage
 
  35 undoMan 
= g
.undoMan 
= UndoManager() 
  37 # Set application path for loading resources 
  38 if __name__ 
== '__main__': 
  39     basePath 
= os
.path
.dirname(sys
.argv
[0]) 
  41     basePath 
= os
.path
.dirname(__file__
) 
  43 # Remember system path 
  46 # 1 adds CMD command to Help menu 
  50 <HTML><H2>Welcome to XRC<font color="blue">ed</font></H2><H3><font color="green">DON'T PANIC :)</font></H3> 
  51 Read this note before clicking on anything!<P> 
  52 To start select tree root, then popup menu with your right mouse button, 
  53 select "Append Child", and then any command.<P> 
  54 Or just press one of the buttons on the tools palette.<P> 
  55 Enter XML ID, change properties, create children.<P> 
  56 To test your interface select Test command (View menu).<P> 
  57 Consult README.txt file for the details.</HTML> 
  60 defaultIDs 
= {xxxPanel
:'PANEL', xxxDialog
:'DIALOG', xxxFrame
:'FRAME', 
  61               xxxMenuBar
:'MENUBAR', xxxMenu
:'MENU', xxxToolBar
:'TOOLBAR', 
  62               xxxWizard
:'WIZARD', xxxBitmap
:'BITMAP', xxxIcon
:'ICON'} 
  64 defaultName 
= 'UNTITLED.xrc' 
  66 ################################################################################ 
  68 # ScrolledMessageDialog - modified from wxPython lib to set fixed-width font 
  69 class ScrolledMessageDialog(wx
.Dialog
): 
  70     def __init__(self
, parent
, msg
, caption
, pos 
= wx
.DefaultPosition
, size 
= (500,300)): 
  71         from wx
.lib
.layoutf 
import Layoutf
 
  72         wx
.Dialog
.__init
__(self
, parent
, -1, caption
, pos
, size
) 
  73         text 
= wx
.TextCtrl(self
, -1, msg
, wx
.DefaultPosition
, 
  74                              wx
.DefaultSize
, wx
.TE_MULTILINE | wx
.TE_READONLY
) 
  75         text
.SetFont(g
.modernFont()) 
  76         dc 
= wx
.WindowDC(text
) 
  77         w
, h 
= dc
.GetFullTextExtent(' ', g
.modernFont())[:2] 
  78         ok 
= wx
.Button(self
, wx
.ID_OK
, "OK") 
  80         text
.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self
,ok
))) 
  81         text
.SetSize((w 
* 80 + 30, h 
* 40)) 
  82         text
.ShowPosition(1)            # scroll to the first line 
  83         ok
.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!35', (self
,))) 
  84         self
.SetAutoLayout(True) 
  86         self
.CenterOnScreen(wx
.BOTH
) 
  88 ################################################################################ 
  90 # Event handler for using during location 
  91 class Locator(wx
.EvtHandler
): 
  92     def ProcessEvent(self
, evt
): 
  95 class TaskBarIcon(wx
.TaskBarIcon
): 
  96     def __init__(self
, frame
): 
  97         wx
.TaskBarIcon
.__init
__(self
) 
 100         self
.SetIcon(images
.getIconIcon(), "XRCed") 
 102 # ArtProvider for toolbar icons 
 103 class ToolArtProvider(wx
.ArtProvider
): 
 105         wx
.ArtProvider
.__init
__(self
) 
 107             'ART_LOCATE': images
.getLocateImage(), 
 108             'ART_TEST': images
.getTestImage(), 
 109             'ART_REFRESH': images
.getRefreshImage(), 
 110             'ART_AUTO_REFRESH': images
.getAutoRefreshImage(), 
 111             'ART_MOVEUP': images
.getMoveUpImage(), 
 112             'ART_MOVEDOWN': images
.getMoveDownImage(), 
 113             'ART_MOVELEFT': images
.getMoveLeftImage(), 
 114             'ART_MOVERIGHT': images
.getMoveRightImage() 
 116         if wx
.Platform 
in ['__WXMAC__', '__WXMSW__']: 
 118                     wx
.ART_NORMAL_FILE
: images
.getNewImage(), 
 119                     wx
.ART_FILE_OPEN
: images
.getOpenImage(), 
 120                     wx
.ART_FILE_SAVE
: images
.getSaveImage(), 
 121                     wx
.ART_UNDO
: images
.getUndoImage(), 
 122                     wx
.ART_REDO
: images
.getRedoImage(), 
 123                     wx
.ART_CUT
: images
.getCutImage(), 
 124                     wx
.ART_COPY
: images
.getCopyImage(), 
 125                     wx
.ART_PASTE
: images
.getPasteImage() 
 127     def CreateBitmap(self
, id, client
, size
): 
 129         if id in self
.images
: 
 130             img 
= self
.images
[id] 
 131             # Alpha not implemented completely there 
 132             if wx
.Platform 
in ['__WXMAC__', '__WXMSW__']: 
 133                 img
.ConvertAlphaToMask() 
 134             bmp 
= wx
.BitmapFromImage(img
) 
 137 class Frame(wx
.Frame
): 
 138     def __init__(self
, pos
, size
): 
 139         wx
.Frame
.__init
__(self
, None, -1, '', pos
, size
) 
 141         frame 
= g
.frame 
= self
 
 142         bar 
= self
.CreateStatusBar(2) 
 143         bar
.SetStatusWidths([-1, 40]) 
 144         self
.SetIcon(images
.getIconIcon()) 
 146             self
.tbicon 
= TaskBarIcon(self
) 
 153         # Load our own resources 
 154         self
.res 
= xrc
.EmptyXmlResource() 
 155         # !!! Blocking of assert failure occurring in older unicode builds 
 157             quietlog 
= wx
.LogNull() 
 158             self
.res
.Load(os
.path
.join(basePath
, 'xrced.xrc')) 
 159         except wx
._core
.PyAssertionError
: 
 160             print 'PyAssertionError was ignored' 
 163         menuBar 
= wx
.MenuBar() 
 166         menu
.Append(wx
.ID_NEW
, '&New\tCtrl-N', 'New file') 
 167         menu
.AppendSeparator() 
 168         menu
.Append(wx
.ID_OPEN
, '&Open...\tCtrl-O', 'Open XRC file') 
 170         self
.recentMenu 
= wx
.Menu() 
 171         g
.fileHistory
.UseMenu(self
.recentMenu
) 
 172         g
.fileHistory
.AddFilesToMenu() 
 173         self
.Bind(wx
.EVT_MENU
, self
.OnRecentFile
, id=wx
.ID_FILE1
, id2
=wx
.ID_FILE9
) 
 174         menu
.AppendMenu(-1, 'Open &Recent', self
.recentMenu
, 'Open a recent file') 
 176         menu
.AppendSeparator() 
 177         menu
.Append(wx
.ID_SAVE
, '&Save\tCtrl-S', 'Save XRC file') 
 178         menu
.Append(wx
.ID_SAVEAS
, 'Save &As...', 'Save XRC file under different name') 
 179         self
.ID_GENERATE_PYTHON 
= wx
.NewId() 
 180         menu
.Append(self
.ID_GENERATE_PYTHON
, '&Generate Python...',  
 181                     'Generate a Python module that uses this XRC') 
 182         menu
.AppendSeparator() 
 183         self
.ID_PREFS 
= wx
.NewId() 
 184         menu
.Append(self
.ID_PREFS
, 'Preferences...', 'Change XRCed settings') 
 185         menu
.AppendSeparator() 
 186         menu
.Append(wx
.ID_EXIT
, '&Quit\tCtrl-Q', 'Exit application') 
 188         menuBar
.Append(menu
, '&File') 
 191         menu
.Append(wx
.ID_UNDO
, '&Undo\tCtrl-Z', 'Undo') 
 192         menu
.Append(wx
.ID_REDO
, '&Redo\tCtrl-Y', 'Redo') 
 193         menu
.AppendSeparator() 
 194         menu
.Append(wx
.ID_CUT
, 'Cut\tCtrl-X', 'Cut to the clipboard') 
 195         menu
.Append(wx
.ID_COPY
, '&Copy\tCtrl-C', 'Copy to the clipboard') 
 196         menu
.Append(wx
.ID_PASTE
, '&Paste\tCtrl-V', 'Paste from the clipboard') 
 197         self
.ID_DELETE 
= wx
.NewId() 
 198         menu
.Append(self
.ID_DELETE
, '&Delete\tCtrl-D', 'Delete object') 
 199         menu
.AppendSeparator() 
 200         self
.ID_LOCATE 
= wx
.NewId() 
 201         self
.ID_TOOL_LOCATE 
= wx
.NewId() 
 202         self
.ART_LOCATE 
= 'ART_LOCATE' 
 203         self
.ID_TOOL_PASTE 
= wx
.NewId() 
 204         menu
.Append(self
.ID_LOCATE
, '&Locate\tCtrl-L', 'Locate control in test window and select it') 
 205         menuBar
.Append(menu
, '&Edit') 
 207         self
.ID_EMBED_PANEL 
= wx
.NewId() 
 208         menu
.Append(self
.ID_EMBED_PANEL
, '&Embed Panel', 
 209                     'Toggle embedding properties panel in the main window', True) 
 210         menu
.Check(self
.ID_EMBED_PANEL
, conf
.embedPanel
) 
 211         self
.ID_SHOW_TOOLS 
= wx
.NewId() 
 212         menu
.Append(self
.ID_SHOW_TOOLS
, 'Show &Tools', 'Toggle tools', True) 
 213         menu
.Check(self
.ID_SHOW_TOOLS
, conf
.showTools
) 
 214         menu
.AppendSeparator() 
 215         self
.ID_TEST 
= wx
.NewId() 
 216         self
.ART_TEST 
= 'ART_TEST' 
 217         menu
.Append(self
.ID_TEST
, '&Test\tF5', 'Show test window') 
 218         self
.ID_REFRESH 
= wx
.NewId() 
 219         self
.ART_REFRESH 
= 'ART_REFRESH' 
 220         menu
.Append(self
.ID_REFRESH
, '&Refresh\tCtrl-R', 'Refresh test window') 
 221         self
.ID_AUTO_REFRESH 
= wx
.NewId() 
 222         self
.ART_AUTO_REFRESH 
= 'ART_AUTO_REFRESH' 
 223         menu
.Append(self
.ID_AUTO_REFRESH
, '&Auto-refresh\tAlt-A', 
 224                     'Toggle auto-refresh mode', True) 
 225         menu
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 226         self
.ID_TEST_HIDE 
= wx
.NewId() 
 227         menu
.Append(self
.ID_TEST_HIDE
, '&Hide\tF6', 'Close test window') 
 228         menuBar
.Append(menu
, '&View') 
 231         self
.ID_MOVEUP 
= wx
.NewId() 
 232         self
.ART_MOVEUP 
= 'ART_MOVEUP' 
 233         menu
.Append(self
.ID_MOVEUP
, '&Up', 'Move before previous sibling') 
 234         self
.ID_MOVEDOWN 
= wx
.NewId() 
 235         self
.ART_MOVEDOWN 
= 'ART_MOVEDOWN' 
 236         menu
.Append(self
.ID_MOVEDOWN
, '&Down', 'Move after next sibling') 
 237         self
.ID_MOVELEFT 
= wx
.NewId() 
 238         self
.ART_MOVELEFT 
= 'ART_MOVELEFT' 
 239         menu
.Append(self
.ID_MOVELEFT
, '&Make sibling', 'Make sibling of parent') 
 240         self
.ID_MOVERIGHT 
= wx
.NewId() 
 241         self
.ART_MOVERIGHT 
= 'ART_MOVERIGHT' 
 242         menu
.Append(self
.ID_MOVERIGHT
, '&Make child', 'Make child of previous sibling') 
 243         menuBar
.Append(menu
, '&Move') 
 246         menu
.Append(wx
.ID_ABOUT
, '&About...', 'About XCRed') 
 247         self
.ID_README 
= wx
.NewId() 
 248         menu
.Append(self
.ID_README
, '&Readme...\tF1', 'View the README file') 
 250             self
.ID_DEBUG_CMD 
= wx
.NewId() 
 251             menu
.Append(self
.ID_DEBUG_CMD
, 'CMD', 'Python command line') 
 252             wx
.EVT_MENU(self
, self
.ID_DEBUG_CMD
, self
.OnDebugCMD
) 
 253         menuBar
.Append(menu
, '&Help') 
 255         self
.menuBar 
= menuBar
 
 256         self
.SetMenuBar(menuBar
) 
 259         tb 
= self
.CreateToolBar(wx
.TB_HORIZONTAL | wx
.NO_BORDER | wx
.TB_FLAT
) 
 260         if wx
.Platform 
!= '__WXMAC__': 
 261             # Redefine AddSeparator on wxGTK and wxMSW to add vertical line 
 263                 tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23),  
 264                                             style
=wx
.LI_VERTICAL
)) 
 265             tb
.AddSeparator 
= _AddSeparator
 
 267         # Use tango icons and slightly wider bitmap size on Mac 
 268         if wx
.Platform 
in ['__WXMAC__', '__WXMSW__']: 
 269             tb
.SetToolBitmapSize((26,26)) 
 271             tb
.SetToolBitmapSize((24,24)) 
 272         new_bmp  
= wx
.ArtProvider
.GetBitmap(wx
.ART_NORMAL_FILE
, wx
.ART_TOOLBAR
) 
 273         open_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_FILE_OPEN
, wx
.ART_TOOLBAR
) 
 274         save_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_FILE_SAVE
, wx
.ART_TOOLBAR
) 
 275         undo_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_UNDO
, wx
.ART_TOOLBAR
) 
 276         redo_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_REDO
, wx
.ART_TOOLBAR
) 
 277         cut_bmp  
= wx
.ArtProvider
.GetBitmap(wx
.ART_CUT
, wx
.ART_TOOLBAR
) 
 278         copy_bmp 
= wx
.ArtProvider
.GetBitmap(wx
.ART_COPY
, wx
.ART_TOOLBAR
) 
 279         paste_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_PASTE
, wx
.ART_TOOLBAR
) 
 280         tb
.AddSimpleTool(wx
.ID_NEW
, new_bmp
, 'New', 'New file') 
 281         tb
.AddSimpleTool(wx
.ID_OPEN
, open_bmp
, 'Open', 'Open file') 
 282         tb
.AddSimpleTool(wx
.ID_SAVE
, save_bmp
, 'Save', 'Save file') 
 284         tb
.AddSimpleTool(wx
.ID_UNDO
, undo_bmp
, 'Undo', 'Undo') 
 285         tb
.AddSimpleTool(wx
.ID_REDO
, redo_bmp
, 'Redo', 'Redo') 
 287         tb
.AddSimpleTool(wx
.ID_CUT
, cut_bmp
, 'Cut', 'Cut') 
 288         tb
.AddSimpleTool(wx
.ID_COPY
, copy_bmp
, 'Copy', 'Copy') 
 289         tb
.AddSimpleTool(self
.ID_TOOL_PASTE
, paste_bmp
, 'Paste', 'Paste') 
 291         bmp 
= wx
.ArtProvider
.GetBitmap(self
.ART_LOCATE
, wx
.ART_TOOLBAR
) 
 292         tb
.AddSimpleTool(self
.ID_TOOL_LOCATE
, bmp
, 
 293                          'Locate', 'Locate control in test window and select it', True) 
 294         bmp 
= wx
.ArtProvider
.GetBitmap(self
.ART_TEST
, wx
.ART_TOOLBAR
) 
 295         tb
.AddSimpleTool(self
.ID_TEST
, bmp
, 'Test', 'Test window') 
 296         bmp 
= wx
.ArtProvider
.GetBitmap(self
.ART_REFRESH
, wx
.ART_TOOLBAR
) 
 297         tb
.AddSimpleTool(self
.ID_REFRESH
, bmp
, 'Refresh', 'Refresh view') 
 298         bmp 
= wx
.ArtProvider
.GetBitmap(self
.ART_AUTO_REFRESH
, wx
.ART_TOOLBAR
) 
 299         tb
.AddSimpleTool(self
.ID_AUTO_REFRESH
, bmp
, 
 300                          'Auto-refresh', 'Toggle auto-refresh mode', True) 
 302         bmp 
= wx
.ArtProvider
.GetBitmap(self
.ART_MOVEUP
, wx
.ART_TOOLBAR
) 
 303         tb
.AddSimpleTool(self
.ID_MOVEUP
, bmp
, 
 304                          'Up', 'Move before previous sibling') 
 305         bmp 
= wx
.ArtProvider
.GetBitmap(self
.ART_MOVEDOWN
, wx
.ART_TOOLBAR
) 
 306         tb
.AddSimpleTool(self
.ID_MOVEDOWN
, bmp
, 
 307                          'Down', 'Move after next sibling') 
 308         bmp 
= wx
.ArtProvider
.GetBitmap(self
.ART_MOVELEFT
, wx
.ART_TOOLBAR
) 
 309         tb
.AddSimpleTool(self
.ID_MOVELEFT
, bmp
, 
 310                          'Make Sibling', 'Make sibling of parent') 
 311         bmp 
= wx
.ArtProvider
.GetBitmap(self
.ART_MOVERIGHT
, wx
.ART_TOOLBAR
) 
 312         tb
.AddSimpleTool(self
.ID_MOVERIGHT
, bmp
, 
 313                          'Make Child', 'Make child of previous sibling') 
 314         tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
 318         self
.minWidth 
= tb
.GetSize()[0] # minimal width is the size of toolbar 
 321         wx
.EVT_MENU(self
, wx
.ID_NEW
, self
.OnNew
) 
 322         wx
.EVT_MENU(self
, wx
.ID_OPEN
, self
.OnOpen
) 
 323         wx
.EVT_MENU(self
, wx
.ID_SAVE
, self
.OnSaveOrSaveAs
) 
 324         wx
.EVT_MENU(self
, wx
.ID_SAVEAS
, self
.OnSaveOrSaveAs
) 
 325         wx
.EVT_MENU(self
, self
.ID_GENERATE_PYTHON
, self
.OnGeneratePython
) 
 326         wx
.EVT_MENU(self
, self
.ID_PREFS
, self
.OnPrefs
) 
 327         wx
.EVT_MENU(self
, wx
.ID_EXIT
, self
.OnExit
) 
 329         wx
.EVT_MENU(self
, wx
.ID_UNDO
, self
.OnUndo
) 
 330         wx
.EVT_MENU(self
, wx
.ID_REDO
, self
.OnRedo
) 
 331         wx
.EVT_MENU(self
, wx
.ID_CUT
, self
.OnCutDelete
) 
 332         wx
.EVT_MENU(self
, wx
.ID_COPY
, self
.OnCopy
) 
 333         wx
.EVT_MENU(self
, wx
.ID_PASTE
, self
.OnPaste
) 
 334         wx
.EVT_MENU(self
, self
.ID_TOOL_PASTE
, self
.OnPaste
) 
 335         wx
.EVT_MENU(self
, self
.ID_DELETE
, self
.OnCutDelete
) 
 336         wx
.EVT_MENU(self
, self
.ID_LOCATE
, self
.OnLocate
) 
 337         wx
.EVT_MENU(self
, self
.ID_TOOL_LOCATE
, self
.OnLocate
) 
 339         wx
.EVT_MENU(self
, self
.ID_EMBED_PANEL
, self
.OnEmbedPanel
) 
 340         wx
.EVT_MENU(self
, self
.ID_SHOW_TOOLS
, self
.OnShowTools
) 
 341         wx
.EVT_MENU(self
, self
.ID_TEST
, self
.OnTest
) 
 342         wx
.EVT_MENU(self
, self
.ID_REFRESH
, self
.OnRefresh
) 
 343         wx
.EVT_MENU(self
, self
.ID_AUTO_REFRESH
, self
.OnAutoRefresh
) 
 344         wx
.EVT_MENU(self
, self
.ID_TEST_HIDE
, self
.OnTestHide
) 
 346         wx
.EVT_MENU(self
, self
.ID_MOVEUP
, self
.OnMoveUp
) 
 347         wx
.EVT_MENU(self
, self
.ID_MOVEDOWN
, self
.OnMoveDown
) 
 348         wx
.EVT_MENU(self
, self
.ID_MOVELEFT
, self
.OnMoveLeft
) 
 349         wx
.EVT_MENU(self
, self
.ID_MOVERIGHT
, self
.OnMoveRight
)         
 351         wx
.EVT_MENU(self
, wx
.ID_ABOUT
, self
.OnAbout
) 
 352         wx
.EVT_MENU(self
, self
.ID_README
, self
.OnReadme
) 
 355         wx
.EVT_UPDATE_UI(self
, wx
.ID_SAVE
, self
.OnUpdateUI
) 
 356         wx
.EVT_UPDATE_UI(self
, wx
.ID_CUT
, self
.OnUpdateUI
) 
 357         wx
.EVT_UPDATE_UI(self
, wx
.ID_COPY
, self
.OnUpdateUI
) 
 358         wx
.EVT_UPDATE_UI(self
, wx
.ID_PASTE
, self
.OnUpdateUI
) 
 359         wx
.EVT_UPDATE_UI(self
, self
.ID_LOCATE
, self
.OnUpdateUI
) 
 360         wx
.EVT_UPDATE_UI(self
, self
.ID_TOOL_LOCATE
, self
.OnUpdateUI
) 
 361         wx
.EVT_UPDATE_UI(self
, self
.ID_TOOL_PASTE
, self
.OnUpdateUI
) 
 362         wx
.EVT_UPDATE_UI(self
, wx
.ID_UNDO
, self
.OnUpdateUI
) 
 363         wx
.EVT_UPDATE_UI(self
, wx
.ID_REDO
, self
.OnUpdateUI
) 
 364         wx
.EVT_UPDATE_UI(self
, self
.ID_DELETE
, self
.OnUpdateUI
) 
 365         wx
.EVT_UPDATE_UI(self
, self
.ID_TEST
, self
.OnUpdateUI
) 
 366         wx
.EVT_UPDATE_UI(self
, self
.ID_MOVEUP
, self
.OnUpdateUI
) 
 367         wx
.EVT_UPDATE_UI(self
, self
.ID_MOVEDOWN
, self
.OnUpdateUI
) 
 368         wx
.EVT_UPDATE_UI(self
, self
.ID_MOVELEFT
, self
.OnUpdateUI
) 
 369         wx
.EVT_UPDATE_UI(self
, self
.ID_MOVERIGHT
, self
.OnUpdateUI
) 
 370         wx
.EVT_UPDATE_UI(self
, self
.ID_REFRESH
, self
.OnUpdateUI
) 
 373         sizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 374         #sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) 
 375         # Horizontal sizer for toolbar and splitter 
 376         self
.toolsSizer 
= sizer1 
= wx
.BoxSizer() 
 377         splitter 
= wx
.SplitterWindow(self
, -1, style
=wx
.SP_3DSASH
) 
 378         self
.splitter 
= splitter
 
 379         splitter
.SetMinimumPaneSize(100) 
 382         g
.tree 
= tree 
= XML_Tree(splitter
, -1) 
 384         # Init pull-down menu data 
 386         g
.pullDownMenu 
= pullDownMenu 
= PullDownMenu(self
) 
 388         # Vertical toolbar for GUI buttons 
 389         g
.tools 
= tools 
= Tools(self
) 
 390         tools
.Show(conf
.showTools
) 
 391         if conf
.showTools
: sizer1
.Add(tools
, 0, wx
.EXPAND
) 
 393         tree
.RegisterKeyEvents() 
 395         # Miniframe for split mode 
 396         miniFrame 
= wx
.MiniFrame(self
, -1, 'Properties & Style', 
 397                                  (conf
.panelX
, conf
.panelY
), 
 398                                  (conf
.panelWidth
, conf
.panelHeight
)) 
 399         self
.miniFrame 
= miniFrame
 
 400         sizer2 
= wx
.BoxSizer() 
 401         miniFrame
.SetSizer(sizer2
) 
 402         # Create panel for parameters 
 405             panel 
= Panel(splitter
) 
 406             # Set plitter windows 
 407             splitter
.SplitVertically(tree
, panel
, conf
.sashPos
) 
 409             panel 
= Panel(miniFrame
) 
 410             sizer2
.Add(panel
, 1, wx
.EXPAND
) 
 412             splitter
.Initialize(tree
) 
 413         if wx
.Platform 
== '__WXMAC__': 
 414             sizer1
.Add(splitter
, 1, wx
.EXPAND|wx
.RIGHT
, 5) 
 416             sizer1
.Add(splitter
, 1, wx
.EXPAND
) 
 417         sizer
.Add(sizer1
, 1, wx
.EXPAND
) 
 418         self
.SetAutoLayout(True) 
 422         wx
.EVT_IDLE(self
, self
.OnIdle
) 
 423         wx
.EVT_CLOSE(self
, self
.OnCloseWindow
) 
 424         wx
.EVT_KEY_DOWN(self
, tools
.OnKeyDown
) 
 425         wx
.EVT_KEY_UP(self
, tools
.OnKeyUp
) 
 426         wx
.EVT_ICONIZE(self
, self
.OnIconize
) 
 428     def OnRecentFile(self
,evt
): 
 429         # open recently used file 
 430         if not self
.AskSave(): return 
 433         # get the pathname based on the menu ID 
 434         fileNum 
= evt
.GetId() - wx
.ID_FILE1
 
 435         path 
= g
.fileHistory
.GetHistoryFile(fileNum
) 
 438             self
.SetStatusText('Data loaded') 
 439             # add it back to the history so it will be moved up the list 
 440             self
.SaveRecent(path
) 
 442             self
.SetStatusText('Failed') 
 446     def OnNew(self
, evt
): 
 447         if not self
.AskSave(): return 
 450     def OnOpen(self
, evt
): 
 451         if not self
.AskSave(): return 
 452         dlg 
= wx
.FileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
), 
 453                            '', '*.xrc', wx
.OPEN | wx
.CHANGE_DIR
) 
 454         if dlg
.ShowModal() == wx
.ID_OK
: 
 456             self
.SetStatusText('Loading...') 
 460                     self
.SetStatusText('Data loaded') 
 461                     self
.SaveRecent(path
) 
 463                     self
.SetStatusText('Failed') 
 468     def OnSaveOrSaveAs(self
, evt
): 
 469         if evt
.GetId() == wx
.ID_SAVEAS 
or not self
.dataFile
: 
 470             if self
.dataFile
: name 
= '' 
 471             else: name 
= defaultName
 
 472             dirname 
= os
.path
.abspath(os
.path
.dirname(self
.dataFile
)) 
 473             dlg 
= wx
.FileDialog(self
, 'Save As', dirname
, name
, '*.xrc', 
 474                                wx
.SAVE | wx
.OVERWRITE_PROMPT | wx
.CHANGE_DIR
) 
 475             if dlg
.ShowModal() == wx
.ID_OK
: 
 477                 if isinstance(path
, unicode): 
 478                     path 
= path
.encode(sys
.getfilesystemencoding()) 
 485                 # if we already have a localconf then it needs to be 
 486                 # copied to a new config with the new name 
 488                 nc 
= self
.CreateLocalConf(path
) 
 489                 flag
, key
, idx 
= lc
.GetFirstEntry() 
 491                     nc
.Write(key
, lc
.Read(key
)) 
 492                     flag
, key
, idx 
= lc
.GetNextEntry(idx
) 
 495                 # otherwise create a new one 
 496                 conf
.localconf 
= self
.CreateLocalConf(path
) 
 499         self
.SetStatusText('Saving...') 
 503                 tmpFile
,tmpName 
= tempfile
.mkstemp(prefix
='xrced-') 
 505                 self
.Save(tmpName
) # save temporary file first 
 506                 shutil
.move(tmpName
, path
) 
 508                 self
.SetModified(False) 
 509                 if conf
.localconf
.ReadBool("autogenerate", False): 
 510                     pypath 
= conf
.localconf
.Read("filename") 
 511                     embed 
= conf
.localconf
.ReadBool("embedResource", False) 
 512                     genGettext 
= conf
.localconf
.ReadBool("genGettext", False) 
 513                     self
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
) 
 515                 self
.SetStatusText('Data saved') 
 516                 self
.SaveRecent(path
) 
 518                 self
.SetStatusText('Failed') 
 522     def SaveRecent(self
,path
): 
 523         # append to recently used files 
 524         g
.fileHistory
.AddFileToHistory(path
) 
 526     def GeneratePython(self
, dataFile
, pypath
, embed
, genGettext
): 
 528             import wx
.tools
.pywxrc
 
 529             rescomp 
= wx
.tools
.pywxrc
.XmlResourceCompiler() 
 530             rescomp
.MakePythonModule([dataFile
], pypath
, embed
, genGettext
) 
 533             wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1]) 
 534             wx
.LogError('Error generating python code : %s' % pypath
) 
 538     def OnGeneratePython(self
, evt
): 
 539         if self
.modified 
or not conf
.localconf
: 
 540             wx
.MessageBox("Save the XRC file first!", "Error") 
 543         dlg 
= PythonOptions(self
, conf
.localconf
, self
.dataFile
) 
 547     def OnPrefs(self
, evt
): 
 548         dlg 
= PrefsDialog(self
) 
 549         if dlg
.ShowModal() == wx
.ID_OK
: 
 550             # Fetch new preferences 
 551             for id,cdp 
in dlg
.checkControls
.items(): 
 553                 if dlg
.FindWindowById(id).IsChecked(): 
 554                     d
[p
] = str(c
.GetValue()) 
 555                 elif p 
in d
: del d
[p
] 
 556             g
.conf
.allowExec 
= ('ask', 'yes', 'no')[dlg
.radio_allow_exec
.GetSelection()] 
 559     def OnExit(self
, evt
): 
 562     def OnUndo(self
, evt
): 
 563         # Extra check to not mess with idle updating 
 564         if undoMan
.CanUndo(): 
 566             g
.panel
.SetModified(False) 
 567             if not undoMan
.CanUndo(): 
 568                 self
.SetModified(False) 
 570     def OnRedo(self
, evt
): 
 571         if undoMan
.CanRedo(): 
 573             self
.SetModified(True) 
 575     def OnCopy(self
, evt
): 
 576         selected 
= tree
.selection
 
 577         if not selected
: return         # key pressed event 
 578         xxx 
= tree
.GetPyData(selected
) 
 579         if wx
.TheClipboard
.Open(): 
 581                 data 
= wx
.CustomDataObject('XRCED') 
 582                 # Set encoding in header 
 584                 s 
= xxx
.node
.toxml(encoding
=expat
.native_encoding
) 
 586                 data 
= wx
.CustomDataObject('XRCED_node') 
 588             data
.SetData(cPickle
.dumps(s
)) 
 589             wx
.TheClipboard
.SetData(data
) 
 590             wx
.TheClipboard
.Close() 
 591             self
.SetStatusText('Copied') 
 593             wx
.MessageBox("Unable to open the clipboard", "Error") 
 595     def OnPaste(self
, evt
): 
 596         selected 
= tree
.selection
 
 597         if not selected
: return         # key pressed event 
 598         # For pasting with Ctrl pressed 
 600         if evt
.GetId() == pullDownMenu
.ID_PASTE_SIBLING
: appendChild 
= False 
 601         elif evt
.GetId() == self
.ID_TOOL_PASTE
: 
 602             if g
.tree
.ctrl
: appendChild 
= False 
 603             else: appendChild 
= not tree
.NeedInsert(selected
) 
 604         else: appendChild 
= not tree
.NeedInsert(selected
) 
 605         xxx 
= tree
.GetPyData(selected
) 
 607             # If has next item, insert, else append to parent 
 608             nextItem 
= tree
.GetNextSibling(selected
) 
 609             parentLeaf 
= tree
.GetItemParent(selected
) 
 610         # Expanded container (must have children) 
 611         elif tree
.IsExpanded(selected
) and tree
.GetChildrenCount(selected
, False): 
 612             # Insert as first child 
 613             nextItem 
= tree
.GetFirstChild(selected
)[0] 
 614             parentLeaf 
= selected
 
 616             # No children or unexpanded item - appendChild stays True 
 617             nextItem 
= wx
.TreeItemId()   # no next item 
 618             parentLeaf 
= selected
 
 619         parent 
= tree
.GetPyData(parentLeaf
).treeObject() 
 621         # Create a copy of clipboard pickled element 
 622         success 
= success_node 
= False 
 623         if wx
.TheClipboard
.Open(): 
 625                 data 
= wx
.CustomDataObject('XRCED') 
 626                 if wx
.TheClipboard
.IsSupported(data
.GetFormat()): 
 628                         success 
= wx
.TheClipboard
.GetData(data
) 
 630                         # there is a problem if XRCED_node is in clipboard 
 631                         # but previous SetData was for XRCED 
 633                 if not success
:             # try other format 
 634                     data 
= wx
.CustomDataObject('XRCED_node') 
 635                     if wx
.TheClipboard
.IsSupported(data
.GetFormat()): 
 636                         success_node 
= wx
.TheClipboard
.GetData(data
) 
 638                 wx
.TheClipboard
.Close() 
 640         if not success 
and not success_node
: 
 642                 "There is no data in the clipboard in the required format", 
 646         xml 
= cPickle
.loads(data
.GetData()) # xml representation of element 
 648             elem 
= minidom
.parseString(xml
).childNodes
[0] 
 650             elem 
= g
.tree
.dom
.createComment(xml
) 
 652         # Tempopary xxx object to test things 
 653         xxx 
= MakeXXXFromDOM(parent
, elem
) 
 655         # Check compatibility 
 656         if not self
.ItemsAreCompatible(parent
, xxx
.treeObject()): return 
 658         # Check parent and child relationships. 
 659         # If parent is sizer or notebook, child is of wrong class or 
 660         # parent is normal window, child is child container then detach child. 
 661         isChildContainer 
= isinstance(xxx
, xxxChildContainer
) 
 662         parentIsBook 
= parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
] 
 663         if isChildContainer 
and \
 
 664            ((parent
.isSizer 
and not isinstance(xxx
, xxxSizerItem
)) or \
 
 665             (parentIsBook 
and not isinstance(xxx
, xxxPage
)) or \
 
 666            not (parent
.isSizer 
or parentIsBook
)): 
 667             elem
.removeChild(xxx
.child
.node
) # detach child 
 668             elem
.unlink()           # delete child container 
 669             elem 
= xxx
.child
.node 
# replace 
 670             # This may help garbage collection 
 671             xxx
.child
.parent 
= None 
 672             isChildContainer 
= False 
 673         # Parent is sizer or notebook, child is not child container 
 674         if parent
.isSizer 
and not isChildContainer 
and not isinstance(xxx
, xxxSpacer
): 
 675             # Create sizer item element 
 676             sizerItemElem 
= MakeEmptyDOM(parent
.itemTag
) 
 677             sizerItemElem
.appendChild(elem
) 
 679         elif isinstance(parent
, xxxNotebook
) and not isChildContainer
: 
 680             pageElem 
= MakeEmptyDOM('notebookpage') 
 681             pageElem
.appendChild(elem
) 
 683         elif isinstance(parent
, xxxChoicebook
) and not isChildContainer
: 
 684             pageElem 
= MakeEmptyDOM('choicebookpage') 
 685             pageElem
.appendChild(elem
) 
 687         elif isinstance(parent
, xxxListbook
) and not isChildContainer
: 
 688             pageElem 
= MakeEmptyDOM('listbookpage') 
 689             pageElem
.appendChild(elem
) 
 691         # Insert new node, register undo 
 692         newItem 
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
) 
 693         undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
)) 
 694         # Scroll to show new item (!!! redundant?) 
 695         tree
.EnsureVisible(newItem
) 
 696         tree
.SelectItem(newItem
) 
 697         if not tree
.IsVisible(newItem
): 
 698             tree
.ScrollTo(newItem
) 
 701         if g
.testWin 
and tree
.IsHighlatable(newItem
): 
 703                 tree
.needUpdate 
= True 
 704                 tree
.pendingHighLight 
= newItem
 
 706                 tree
.pendingHighLight 
= None 
 708         self
.SetStatusText('Pasted') 
 711     def ItemsAreCompatible(self
, parent
, child
): 
 712         # Check compatibility 
 714         # Comments are always compatible 
 715         if child
.__class
__ == xxxComment
: 
 718         if child
.__class
__ in [xxxDialog
, xxxFrame
, xxxWizard
]: 
 720             if parent
.__class
__ != xxxMainNode
: error 
= True 
 721         elif child
.__class
__ == xxxMenuBar
: 
 722             # Menubar can be put in frame or dialog 
 723             if parent
.__class
__ not in [xxxMainNode
, xxxFrame
, xxxDialog
]: error 
= True 
 724         elif child
.__class
__ == xxxToolBar
: 
 725             # Toolbar can be top-level of child of panel or frame 
 726             if parent
.__class
__ not in [xxxMainNode
, xxxPanel
, xxxFrame
] and \
 
 727                not parent
.isSizer
: error 
= True 
 728         elif not parent
.hasChildren
: 
 730         elif child
.__class
__ == xxxPanel 
and parent
.__class
__ == xxxMainNode
: 
 732         elif child
.__class
__ == xxxSpacer
: 
 733             if not parent
.isSizer
: error 
= True 
 734         elif child
.__class
__ == xxxSeparator
: 
 735             if not parent
.__class
__ in [xxxMenu
, xxxToolBar
]: error 
= True 
 736         elif child
.__class
__ == xxxTool
: 
 737             if parent
.__class
__ != xxxToolBar
: error 
= True 
 738         elif child
.__class
__ == xxxMenu
: 
 739             if not parent
.__class
__ in [xxxMainNode
, xxxMenuBar
, xxxMenu
]: error 
= True 
 740         elif child
.__class
__ == xxxMenuItem
: 
 741             if not parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error 
= True 
 742         elif child
.isSizer 
and parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
]: 
 744         else:                           # normal controls can be almost anywhere 
 745             if parent
.__class
__ == xxxMainNode 
or \
 
 746                parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error 
= True 
 748             if parent
.__class
__ == xxxMainNode
: parentClass 
= 'root' 
 749             else: parentClass 
= parent
.className
 
 750             wx
.LogError('Incompatible parent/child: parent is %s, child is %s!' % 
 751                        (parentClass
, child
.className
)) 
 755     def OnMoveUp(self
, evt
): 
 756         selected 
= tree
.selection
 
 757         if not selected
: return 
 759         index 
= tree
.ItemIndex(selected
) 
 760         if index 
== 0: return # No previous sibling found 
 762         # Remove highlight, update testWin 
 763         if g
.testWin 
and g
.testWin
.highLight
: 
 764             g
.testWin
.highLight
.Remove() 
 765             tree
.needUpdate 
= True 
 768         self
.lastOp 
= 'MOVEUP' 
 769         status 
= 'Moved before previous sibling' 
 775         parent 
= tree
.GetItemParent(selected
) 
 776         elem 
= tree
.RemoveLeaf(selected
) 
 777         nextItem 
= tree
.GetFirstChild(parent
)[0] 
 778         for i 
in range(index 
- 1): nextItem 
= tree
.GetNextSibling(nextItem
) 
 779         selected 
= tree
.InsertNode(parent
, tree
.GetPyData(parent
).treeObject(), elem
, nextItem
) 
 780         newIndex 
= tree
.ItemIndex(selected
) 
 781         tree
.SelectItem(selected
) 
 783         undoMan
.RegisterUndo(UndoMove(parent
, index
, parent
, newIndex
)) 
 786         self
.SetStatusText(status
) 
 790     def OnMoveDown(self
, evt
): 
 791         selected 
= tree
.selection
 
 792         if not selected
: return 
 794         index 
= tree
.ItemIndex(selected
) 
 795         next 
= tree
.GetNextSibling(selected
) 
 798         # Remove highlight, update testWin 
 799         if g
.testWin 
and g
.testWin
.highLight
: 
 800             g
.testWin
.highLight
.Remove() 
 801             tree
.needUpdate 
= True 
 804         self
.lastOp 
= 'MOVEDOWN' 
 805         status 
= 'Moved after next sibling' 
 811         parent 
= tree
.GetItemParent(selected
) 
 812         elem 
= tree
.RemoveLeaf(selected
) 
 813         nextItem 
= tree
.GetFirstChild(parent
)[0] 
 814         for i 
in range(index 
+ 1): nextItem 
= tree
.GetNextSibling(nextItem
) 
 815         selected 
= tree
.InsertNode(parent
, tree
.GetPyData(parent
).treeObject(), elem
, nextItem
) 
 816         newIndex 
= tree
.ItemIndex(selected
) 
 817         tree
.SelectItem(selected
) 
 819         undoMan
.RegisterUndo(UndoMove(parent
, index
, parent
, newIndex
)) 
 822         self
.SetStatusText(status
) 
 826     def OnMoveLeft(self
, evt
): 
 827         selected 
= tree
.selection
 
 828         if not selected
: return 
 830         oldParent 
= tree
.GetItemParent(selected
) 
 831         if not oldParent
: return 
 832         pparent 
= tree
.GetItemParent(oldParent
) 
 833         if not pparent
: return 
 835         # Check compatibility 
 836         if not self
.ItemsAreCompatible(tree
.GetPyData(pparent
).treeObject(), tree
.GetPyData(selected
).treeObject()): return 
 838         if g
.testWin 
and g
.testWin
.highLight
: 
 839             g
.testWin
.highLight
.Remove() 
 840             tree
.needUpdate 
= True 
 843         self
.lastOp 
= 'MOVELEFT' 
 844         status 
= 'Made next sibling of parent' 
 850         oldIndex 
= tree
.ItemIndex(selected
) 
 851         elem 
= tree
.RemoveLeaf(selected
) 
 852         nextItem 
= tree
.GetFirstChild(pparent
)[0] 
 853         parentIndex 
= tree
.ItemIndex(oldParent
) 
 854         for i 
in range(parentIndex 
+ 1): nextItem 
= tree
.GetNextSibling(nextItem
) 
 856         # Check parent and child relationships. 
 857         # If parent is sizer or notebook, child is of wrong class or 
 858         # parent is normal window, child is child container then detach child. 
 859         parent 
= tree
.GetPyData(pparent
).treeObject() 
 860         xxx 
= MakeXXXFromDOM(parent
, elem
) 
 861         isChildContainer 
= isinstance(xxx
, xxxChildContainer
) 
 862         if isChildContainer 
and \
 
 863            ((parent
.isSizer 
and not isinstance(xxx
, xxxSizerItem
)) or \
 
 864             (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
 
 865            not (parent
.isSizer 
or isinstance(parent
, xxxNotebook
))): 
 866             elem
.removeChild(xxx
.child
.node
) # detach child 
 867             elem
.unlink()           # delete child container 
 868             elem 
= xxx
.child
.node 
# replace 
 869             # This may help garbage collection 
 870             xxx
.child
.parent 
= None 
 871             isChildContainer 
= False 
 872         # Parent is sizer or notebook, child is not child container 
 873         if parent
.isSizer 
and not isChildContainer 
and not isinstance(xxx
, xxxSpacer
): 
 874             # Create sizer item element 
 875             sizerItemElem 
= MakeEmptyDOM('sizeritem') 
 876             sizerItemElem
.appendChild(elem
) 
 878         elif isinstance(parent
, xxxNotebook
) and not isChildContainer
: 
 879             pageElem 
= MakeEmptyDOM('notebookpage') 
 880             pageElem
.appendChild(elem
) 
 883         selected 
= tree
.InsertNode(pparent
, tree
.GetPyData(pparent
).treeObject(), elem
, nextItem
) 
 884         newIndex 
= tree
.ItemIndex(selected
) 
 885         tree
.SelectItem(selected
) 
 887         undoMan
.RegisterUndo(UndoMove(oldParent
, oldIndex
, pparent
, newIndex
)) 
 890         self
.SetStatusText(status
) 
 892     def OnMoveRight(self
, evt
): 
 893         selected 
= tree
.selection
 
 894         if not selected
: return 
 896         oldParent 
= tree
.GetItemParent(selected
) 
 897         if not oldParent
: return 
 899         newParent 
= tree
.GetPrevSibling(selected
) 
 900         if not newParent
: return 
 902         parent 
= tree
.GetPyData(newParent
).treeObject() 
 904         # Check compatibility 
 905         if not self
.ItemsAreCompatible(parent
, tree
.GetPyData(selected
).treeObject()): return 
 907         # Remove highlight, update testWin 
 908         if g
.testWin 
and g
.testWin
.highLight
: 
 909             g
.testWin
.highLight
.Remove() 
 910             tree
.needUpdate 
= True 
 917         self
.lastOp 
= 'MOVERIGHT' 
 918         status 
= 'Made last child of previous sibling' 
 920         oldIndex 
= tree
.ItemIndex(selected
) 
 921         elem 
= tree
.RemoveLeaf(selected
) 
 923         # Check parent and child relationships. 
 924         # If parent is sizer or notebook, child is of wrong class or 
 925         # parent is normal window, child is child container then detach child. 
 926         xxx 
= MakeXXXFromDOM(parent
, elem
) 
 927         isChildContainer 
= isinstance(xxx
, xxxChildContainer
) 
 928         if isChildContainer 
and \
 
 929            ((parent
.isSizer 
and not isinstance(xxx
, xxxSizerItem
)) or \
 
 930             (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
 
 931            not (parent
.isSizer 
or isinstance(parent
, xxxNotebook
))): 
 932             elem
.removeChild(xxx
.child
.node
) # detach child 
 933             elem
.unlink()           # delete child container 
 934             elem 
= xxx
.child
.node 
# replace 
 935             # This may help garbage collection 
 936             xxx
.child
.parent 
= None 
 937             isChildContainer 
= False 
 938         # Parent is sizer or notebook, child is not child container 
 939         if parent
.isSizer 
and not isChildContainer 
and not isinstance(xxx
, xxxSpacer
): 
 940             # Create sizer item element 
 941             sizerItemElem 
= MakeEmptyDOM('sizeritem') 
 942             sizerItemElem
.appendChild(elem
) 
 944         elif isinstance(parent
, xxxNotebook
) and not isChildContainer
: 
 945             pageElem 
= MakeEmptyDOM('notebookpage') 
 946             pageElem
.appendChild(elem
) 
 949         selected 
= tree
.InsertNode(newParent
, tree
.GetPyData(newParent
).treeObject(), elem
, wx
.TreeItemId()) 
 951         newIndex 
= tree
.ItemIndex(selected
) 
 952         tree
.Expand(selected
) 
 953         tree
.SelectItem(selected
) 
 955         undoMan
.RegisterUndo(UndoMove(oldParent
, oldIndex
, newParent
, newIndex
)) 
 958         self
.SetStatusText(status
) 
 960     def OnCutDelete(self
, evt
): 
 961         selected 
= tree
.selection
 
 962         if not selected
: return         # key pressed event 
 964         if evt
.GetId() == wx
.ID_CUT
: 
 966             status 
= 'Removed to clipboard' 
 968             self
.lastOp 
= 'DELETE' 
 972             # If deleting top-level item, delete testWin 
 973             if selected 
== g
.testWin
.item
: 
 977                 # Remove highlight, update testWin 
 978                 if g
.testWin
.highLight
: 
 979                     g
.testWin
.highLight
.Remove() 
 980                 tree
.needUpdate 
= True 
 983         index 
= tree
.ItemFullIndex(selected
) 
 984         xxx 
= tree
.GetPyData(selected
) 
 985         parent 
= tree
.GetPyData(tree
.GetItemParent(selected
)).treeObject() 
 987         elem 
= tree
.RemoveLeaf(selected
) 
 988         undoMan
.RegisterUndo(UndoCutDelete(index
, parent
, elem
)) 
 989         if evt
.GetId() == wx
.ID_CUT
: 
 990             if wx
.TheClipboard
.Open(): 
 992                     data 
= wx
.CustomDataObject('XRCED') 
 994                     s 
= elem
.toxml(encoding
=expat
.native_encoding
) 
 996                     data 
= wx
.CustomDataObject('XRCED_node') 
 998                 data
.SetData(cPickle
.dumps(s
)) 
 999                 wx
.TheClipboard
.SetData(data
) 
1000                 wx
.TheClipboard
.Close() 
1002                 wx
.MessageBox("Unable to open the clipboard", "Error") 
1003         tree
.pendingHighLight 
= None 
1007         self
.SetStatusText(status
) 
1009     def OnSubclass(self
, evt
): 
1010         selected 
= tree
.selection
 
1011         xxx 
= tree
.GetPyData(selected
).treeObject() 
1013         subclass 
= xxx
.subclass
 
1014         dlg 
= wx
.TextEntryDialog(self
, 'Subclass:', defaultValue
=subclass
) 
1015         if dlg
.ShowModal() == wx
.ID_OK
: 
1016             subclass 
= dlg
.GetValue() 
1018                 elem
.setAttribute('subclass', subclass
) 
1019             elif elem
.hasAttribute('subclass'): 
1020                 elem
.removeAttribute('subclass') 
1022             xxx
.subclass 
= elem
.getAttribute('subclass') 
1023             tree
.SetItemText(selected
, xxx
.treeName()) 
1024             panel
.pages
[0].box
.SetLabel(xxx
.panelName()) 
1027     def OnEmbedPanel(self
, evt
): 
1028         conf
.embedPanel 
= evt
.IsChecked() 
1030             # Remember last dimentions 
1031             conf
.panelX
, conf
.panelY 
= self
.miniFrame
.GetPosition() 
1032             conf
.panelWidth
, conf
.panelHeight 
= self
.miniFrame
.GetSize() 
1033             size 
= self
.GetSize() 
1034             pos 
= self
.GetPosition() 
1035             sizePanel 
= panel
.GetSize() 
1036             panel
.Reparent(self
.splitter
) 
1037             self
.miniFrame
.GetSizer().Remove(panel
) 
1039             self
.SetDimensions(pos
.x
, pos
.y
, size
.width 
+ sizePanel
.width
, size
.height
) 
1040             self
.splitter
.SplitVertically(tree
, panel
, conf
.sashPos
) 
1041             self
.miniFrame
.Show(False) 
1043             conf
.sashPos 
= self
.splitter
.GetSashPosition() 
1044             pos 
= self
.GetPosition() 
1045             size 
= self
.GetSize() 
1046             sizePanel 
= panel
.GetSize() 
1047             self
.splitter
.Unsplit(panel
) 
1048             sizer 
= self
.miniFrame
.GetSizer() 
1049             panel
.Reparent(self
.miniFrame
) 
1051             sizer
.Add(panel
, 1, wx
.EXPAND
) 
1052             self
.miniFrame
.Show(True) 
1053             self
.miniFrame
.SetDimensions(conf
.panelX
, conf
.panelY
, 
1054                                          conf
.panelWidth
, conf
.panelHeight
) 
1055             self
.miniFrame
.Layout() 
1057             self
.SetDimensions(pos
.x
, pos
.y
, 
1058                                max(size
.width 
- sizePanel
.width
, self
.minWidth
), size
.height
) 
1060     def OnShowTools(self
, evt
): 
1061         conf
.showTools 
= evt
.IsChecked() 
1062         g
.tools
.Show(conf
.showTools
) 
1064             self
.toolsSizer
.Prepend(g
.tools
, 0, wx
.EXPAND
) 
1066             self
.toolsSizer
.Remove(g
.tools
) 
1067         self
.toolsSizer
.Layout() 
1069     def OnTest(self
, evt
): 
1070         if not tree
.selection
: return   # key pressed event 
1071         tree
.ShowTestWindow(tree
.selection
) 
1073     def OnTestHide(self
, evt
): 
1074         tree
.CloseTestWindow() 
1076     # Find object by relative position 
1077     def FindObject(self
, item
, obj
): 
1078         # We simply perform depth-first traversal, sinse it's too much 
1079         # hassle to deal with all sizer/window combinations 
1080         w 
= tree
.FindNodeObject(item
) 
1081         if w 
== obj 
or isinstance(w
, wx
.GBSizerItem
) and w
.GetWindow() == obj
: 
1083         if tree
.ItemHasChildren(item
): 
1084             child 
= tree
.GetFirstChild(item
)[0] 
1086                 found 
= self
.FindObject(child
, obj
) 
1087                 if found
: return found
 
1088                 child 
= tree
.GetNextSibling(child
) 
1091     # Click event after locate activated 
1092     def OnTestWinLeftDown(self
, evt
): 
1093         # Restore normal event processing 
1094         self
.SetHandler(g
.testWin
) 
1095         g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
) 
1096         item 
= self
.FindObject(g
.testWin
.item
, evt
.GetEventObject()) 
1098             tree
.EnsureVisible(item
) 
1099             tree
.SelectItem(item
) 
1100         self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, False) 
1102             self
.SetStatusText('Selected %s' % tree
.GetItemText(item
)) 
1104             self
.SetStatusText('Locate failed!') 
1106     def SetHandler(self
, w
, h
=None): 
1108             w
.SetEventHandler(h
) 
1109             w
.SetCursor(wx
.CROSS_CURSOR
) 
1111             w
.SetEventHandler(w
) 
1112             w
.SetCursor(wx
.NullCursor
) 
1113         for ch 
in w
.GetChildren(): 
1114             self
.SetHandler(ch
, h
) 
1116     def OnLocate(self
, evt
): 
1118             if evt
.GetId() == self
.ID_LOCATE 
or \
 
1119                evt
.GetId() == self
.ID_TOOL_LOCATE 
and evt
.IsChecked(): 
1120                 self
.SetHandler(g
.testWin
, g
.testWin
) 
1121                 g
.testWin
.Connect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
, self
.OnTestWinLeftDown
) 
1122                 if evt
.GetId() == self
.ID_LOCATE
: 
1123                     self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, True) 
1124             elif evt
.GetId() == self
.ID_TOOL_LOCATE 
and not evt
.IsChecked(): 
1125                 self
.SetHandler(g
.testWin
, None) 
1126                 g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
) 
1127             self
.SetStatusText('Click somewhere in your test window now') 
1129     def OnRefresh(self
, evt
): 
1130         # If modified, apply first 
1131         selection 
= tree
.selection
 
1133             xxx 
= tree
.GetPyData(selection
) 
1134             if xxx 
and panel
.IsModified(): 
1135                 tree
.Apply(xxx
, selection
) 
1138             tree
.CreateTestWin(g
.testWin
.item
) 
1139         panel
.modified 
= False 
1140         tree
.needUpdate 
= False 
1142     def OnAutoRefresh(self
, evt
): 
1143         conf
.autoRefresh 
= evt
.IsChecked() 
1144         self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
1145         self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
) 
1147     def OnAbout(self
, evt
): 
1151 (c) Roman Rolinsky <rollrom@users.sourceforge.net> 
1152 Homepage: http://xrced.sourceforge.net\ 
1154         dlg 
= wx
.MessageDialog(self
, str, 'About XRCed', wx
.OK | wx
.CENTRE
) 
1158     def OnReadme(self
, evt
): 
1159         text 
= open(os
.path
.join(basePath
, 'README.txt'), 'r').read() 
1160         dlg 
= ScrolledMessageDialog(self
, text
, "XRCed README") 
1164     # Simple emulation of python command line 
1165     def OnDebugCMD(self
, evt
): 
1168                 exec raw_input('C:\> ') 
1173                 (etype
, value
, tb
) =sys
.exc_info() 
1174                 tblist 
=traceback
.extract_tb(tb
)[1:] 
1175                 msg 
=' '.join(traceback
.format_exception_only(etype
, value
) 
1176                         +traceback
.format_list(tblist
)) 
1179     def OnCreate(self
, evt
): 
1180         # Ignore fake events generated while dragging 
1182             g
.tools
.drag 
= False 
1184         selected 
= tree
.selection
 
1185         if tree
.ctrl
: appendChild 
= False 
1186         else: appendChild 
= not tree
.NeedInsert(selected
) 
1187         xxx 
= tree
.GetPyData(selected
) 
1191                 # If has previous item, insert after it, else append to parent 
1193                 parentLeaf 
= tree
.GetItemParent(selected
) 
1195                 # If has next item, insert, else append to parent 
1196                 nextItem 
= tree
.GetNextSibling(selected
) 
1197                 parentLeaf 
= tree
.GetItemParent(selected
) 
1198         # Expanded container (must have children) 
1199         elif tree
.shift 
and tree
.IsExpanded(selected
) \
 
1200            and tree
.GetChildrenCount(selected
, False): 
1201             nextItem 
= tree
.GetFirstChild(selected
)[0] 
1202             parentLeaf 
= selected
 
1204             nextItem 
= wx
.TreeItemId() 
1205             parentLeaf 
= selected
 
1206         parent 
= tree
.GetPyData(parentLeaf
) 
1207         if parent
.hasChild
: parent 
= parent
.child
 
1209         self
.CreateXXX(parent
, parentLeaf
, nextItem
, evt
.GetId()) 
1211     # Actual method to create object and add to XML and wx trees 
1212     def CreateXXX(self
, parent
, parentLeaf
, nextItem
, id): 
1213         selected 
= tree
.selection
 
1214         # Create object_ref? 
1215         if id == ID_NEW
.REF
: 
1216             ref 
= wx
.GetTextFromUser('Create reference to:', 'Create reference') 
1218             xxx 
= MakeEmptyRefXXX(parent
, ref
) 
1219         elif id == ID_NEW
.COMMENT
: 
1220             xxx 
= MakeEmptyCommentXXX(parent
) 
1222             # Create empty element 
1223             if id >= ID_NEW
.CUSTOM
: 
1224                 className 
= pullDownMenu
.customMap
[id] 
1226                 className 
= pullDownMenu
.createMap
[id] 
1227             xxx 
= MakeEmptyXXX(parent
, className
) 
1229         # Insert new node, register undo 
1230         if xxx
.isElement
:                 # true object 
1231             # Set default name for top-level windows 
1232             if parent
.__class
__ == xxxMainNode
: 
1233                 cl 
= xxx
.treeObject().__class
__ 
1234                 frame
.maxIDs
[cl
] += 1 
1235                 xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
])) 
1236             # And for some other standard controls 
1237             elif parent
.__class
__ == xxxStdDialogButtonSizer
: 
1238                 # ... we can even set automatically tree name 
1239                 xxx
.setTreeName(pullDownMenu
.stdButtonIDs
[id][0]) 
1240                 obj 
= xxx
.treeObject() 
1242                 elem 
= g
.tree
.dom
.createElement('label') 
1243                 elem
.appendChild(g
.tree
.dom
.createTextNode(pullDownMenu
.stdButtonIDs
[id][1])) 
1244                 obj
.params
['label'] = xxxParam(elem
) 
1245                 xxx
.treeObject().node
.appendChild(elem
) 
1246             # Else, set label if exists to class name 
1247             elif 'label' in xxx
.treeObject().allParams
: 
1249                 if label
[:2] == 'wx': label 
= label
[2:] 
1250                 xxx
.treeObject().set('label', label
.upper()) 
1251         # For comment nodes, simply add node 
1252         newItem 
= tree
.InsertNode(parentLeaf
, parent
, xxx
.node
, nextItem
) 
1253         undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
)) 
1254         tree
.EnsureVisible(newItem
) 
1255         tree
.SelectItem(newItem
) 
1256         if not tree
.IsVisible(newItem
): 
1257             tree
.ScrollTo(newItem
) 
1260         if xxx
.isElement 
and g
.testWin 
and tree
.IsHighlatable(newItem
): 
1261             if conf
.autoRefresh
: 
1262                 tree
.needUpdate 
= True 
1263                 tree
.pendingHighLight 
= newItem
 
1265                 tree
.pendingHighLight 
= None 
1267         if not xxx
.isElement
: 
1268             tree
.EditLabel(newItem
) 
1272     # Replace one object with another 
1273     def OnReplace(self
, evt
): 
1274         selected 
= tree
.selection
 
1275         xxx 
= tree
.GetPyData(selected
).treeObject() 
1277         parent 
= elem
.parentNode
 
1278         undoMan
.RegisterUndo(UndoReplace(selected
)) 
1280         className 
= pullDownMenu
.createMap
[evt
.GetId() - 1000] 
1282         # Create temporary empty node (with default values) 
1283         dummy 
= MakeEmptyDOM(className
) 
1284         if className 
== 'spacer' and xxx
.className 
!= 'spacer': 
1286         elif xxx
.className 
== 'spacer' and className 
!= 'spacer': 
1287             klass 
= xxxSizerItem
 
1289             klass 
= xxxDict
[className
] 
1290         # Remove non-compatible children 
1291         if tree
.ItemHasChildren(selected
) and not klass
.hasChildren
: 
1292             tree
.DeleteChildren(selected
) 
1293         nodes 
= elem
.childNodes
[:] 
1296             if node
.nodeType 
!= minidom
.Node
.ELEMENT_NODE
: continue 
1300                 if not klass
.hasChildren
:  remove 
= True 
1301             elif tag 
not in klass
.allParams 
and \
 
1302                      (not klass
.hasStyle 
or tag 
not in klass
.styles
): 
1307                 elem
.removeChild(node
) 
1310         # Remove sizeritem child if spacer 
1311         if className 
== 'spacer' and xxx
.className 
!= 'spacer': 
1312             sizeritem 
= elem
.parentNode
 
1313             assert sizeritem
.getAttribute('class') == 'sizeritem' 
1314             sizeritem
.removeChild(elem
) 
1317             tree
.GetPyData(selected
).hasChild 
= False 
1318         elif xxx
.className 
== 'spacer' and className 
!= 'spacer': 
1319             # Create sizeritem element 
1320             assert xxx
.parent
.isSizer
 
1321             elem
.setAttribute('class', 'sizeritem') 
1322             node 
= MakeEmptyDOM(className
) 
1323             elem
.appendChild(node
) 
1324             # Replace to point to new object 
1325             xxx 
= xxxSizerItem(xxx
.parent
, elem
) 
1327             tree
.SetPyData(selected
, xxx
) 
1330             # Copy parameters present in dummy but not in elem 
1331             for node 
in dummy
.childNodes
: 
1332                 if node
.tagName 
not in tags
:  elem
.appendChild(node
.cloneNode(True)) 
1336         elem
.setAttribute('class', className
) 
1337         if elem
.hasAttribute('subclass'): 
1338             elem
.removeAttribute('subclass') # clear subclassing 
1339         # Re-create xxx element 
1340         xxx 
= MakeXXXFromDOM(xxx
.parent
, elem
) 
1341         # Remove incompatible style flags 
1342         if 'style' in xxx
.params
: 
1343             styles 
= map(string
.strip
, xxx
.params
['style'].value().split('|')) 
1344             newStyles 
= [s 
for s 
in styles 
if s 
in klass
.winStyles 
or s 
in genericStyles
] 
1345             if newStyles 
!= styles
: 
1347                     value 
= reduce(lambda a
,b
: a
+'|'+b
, newStyles
) 
1350                 xxx
.params
['style'].update(value
) 
1352         # Update parent in child objects 
1353         if tree
.ItemHasChildren(selected
): 
1354             i
, cookie 
= tree
.GetFirstChild(selected
) 
1356                 x 
= tree
.GetPyData(i
) 
1358                 if x
.hasChild
: x
.child
.parent 
= xxx
 
1359                 i
, cookie 
= tree
.GetNextChild(selected
, cookie
) 
1362         if tree
.GetPyData(selected
).hasChild
: # child container 
1363             container 
= tree
.GetPyData(selected
) 
1364             container
.resetChild(xxx
) 
1367             tree
.SetPyData(selected
, xxx
) 
1368         tree
.SetItemText(selected
, xxx
.treeName()) 
1369         tree
.SetItemImage(selected
, xxx
.treeImage()) 
1371         # Set default name for top-level windows 
1372         if parent
.__class
__ == xxxMainNode
: 
1373             cl 
= xxx
.treeObject().__class
__ 
1374             frame
.maxIDs
[cl
] += 1 
1375             xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
])) 
1378         g
.panel
.SetData(xxx
) 
1382         #undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected)) 
1384         if g
.testWin 
and tree
.IsHighlatable(selected
): 
1385             if conf
.autoRefresh
: 
1386                 tree
.needUpdate 
= True 
1387                 tree
.pendingHighLight 
= selected
 
1389                 tree
.pendingHighLight 
= None 
1393     # Expand/collapse subtree 
1394     def OnExpand(self
, evt
): 
1395         if tree
.selection
: tree
.ExpandAll(tree
.selection
) 
1396         else: tree
.ExpandAll(tree
.root
) 
1397     def OnCollapse(self
, evt
): 
1398         if tree
.selection
: tree
.CollapseAll(tree
.selection
) 
1399         else: tree
.CollapseAll(tree
.root
) 
1401     def OnPullDownHighlight(self
, evt
): 
1402         menuId 
= evt
.GetMenuId() 
1404             menu 
= evt
.GetEventObject() 
1406                 help = menu
.GetHelpString(menuId
) 
1407                 self
.SetStatusText(help) 
1409                 self
.SetStatusText('') 
1411             self
.SetStatusText('') 
1413     def OnUpdateUI(self
, evt
): 
1414         if evt
.GetId() in [wx
.ID_CUT
, wx
.ID_COPY
, self
.ID_DELETE
]: 
1415             evt
.Enable(tree
.selection 
is not None and tree
.selection 
!= tree
.root
) 
1416         elif evt
.GetId() == wx
.ID_SAVE
: 
1417             evt
.Enable(self
.modified
) 
1418         elif evt
.GetId() in [wx
.ID_PASTE
, self
.ID_TOOL_PASTE
]: 
1419             evt
.Enable(tree
.selection 
is not None) 
1420         elif evt
.GetId() in [self
.ID_TEST
, 
1421                              self
.ID_MOVEUP
, self
.ID_MOVEDOWN
, 
1422                              self
.ID_MOVELEFT
, self
.ID_MOVERIGHT
]: 
1423             evt
.Enable(tree
.selection 
is not None and tree
.selection 
!= tree
.root
) 
1424         elif evt
.GetId() in [self
.ID_LOCATE
, self
.ID_TOOL_LOCATE
, 
1426             evt
.Enable(g
.testWin 
is not None) 
1427         elif evt
.GetId() == wx
.ID_UNDO
:  evt
.Enable(undoMan
.CanUndo()) 
1428         elif evt
.GetId() == wx
.ID_REDO
:  evt
.Enable(undoMan
.CanRedo()) 
1430     def OnIdle(self
, evt
): 
1431         if self
.inIdle
: return          # Recursive call protection 
1433         #print 'onidle',tree.needUpdate,tree.pendingHighLight 
1436                 if conf
.autoRefresh
: 
1438                         #self.SetStatusText('Refreshing test window...') 
1440                         tree
.CreateTestWin(g
.testWin
.item
) 
1441                         #self.SetStatusText('') 
1442                     tree
.needUpdate 
= False 
1443             elif tree
.pendingHighLight
: 
1445                     tree
.HighLight(tree
.pendingHighLight
) 
1447                     # Remove highlight if any problem 
1448                     if g
.testWin 
and g
.testWin
.highLight
: 
1449                         g
.testWin
.highLight
.Remove() 
1450                     tree
.pendingHighLight 
= None 
1457     def OnIconize(self
, evt
): 
1459             conf
.x
, conf
.y 
= self
.GetPosition() 
1460             conf
.width
, conf
.height 
= self
.GetSize() 
1462                 conf
.sashPos 
= self
.splitter
.GetSashPosition() 
1464                 conf
.panelX
, conf
.panelY 
= self
.miniFrame
.GetPosition() 
1465                 conf
.panelWidth
, conf
.panelHeight 
= self
.miniFrame
.GetSize() 
1466                 self
.miniFrame
.Show(False) 
1468             if not conf
.embedPanel
: 
1469                 self
.miniFrame
.Show(True) 
1472     def OnCloseWindow(self
, evt
): 
1473         if not self
.AskSave(): return 
1474         if g
.testWin
: g
.testWin
.Destroy() 
1475         if not panel
.GetPageCount() == 2: 
1476             panel
.page2
.Destroy() 
1478             # If we don't do this, page does not get destroyed (a bug?) 
1480         if not self
.IsIconized(): 
1481             conf
.x
, conf
.y 
= self
.GetPosition() 
1482             if wx
.Platform 
== '__WXMAC__': 
1483                 conf
.width
, conf
.height 
= self
.GetClientSize() 
1485                 conf
.width
, conf
.height 
= self
.GetSize() 
1487                 conf
.sashPos 
= self
.splitter
.GetSashPosition() 
1489                 conf
.panelX
, conf
.panelY 
= self
.miniFrame
.GetPosition() 
1490                 conf
.panelWidth
, conf
.panelHeight 
= self
.miniFrame
.GetSize() 
1493     def CreateLocalConf(self
, path
): 
1494         name 
= os
.path
.splitext(path
)[0] 
1496         return wx
.FileConfig(localFilename
=name
) 
1500         conf
.localconf 
= None 
1502         self
.SetModified(False) 
1508         # Numbers for new controls 
1510         for cl 
in [xxxPanel
, xxxDialog
, xxxFrame
, 
1511                    xxxMenuBar
, xxxMenu
, xxxToolBar
, 
1512                    xxxWizard
, xxxBitmap
, xxxIcon
]: 
1514         # Restore handlers, menu, etc. to initial 
1515         setHandlers(self
.handlers
[:]) 
1516         g
.pullDownMenu
.custom 
= self
.custom
[:] 
1517         # Remove modules imported from comment directives 
1518         map(sys
.modules
.pop
, [m 
for m 
in sys
.modules 
if m 
not in self
.modules
]) 
1519         xxxParamComment
.locals = {}     # clear local namespace 
1520         xxxParamComment
.allow 
= None    # clear execution state 
1522     def SetModified(self
, state
=True): 
1523         self
.modified 
= state
 
1524         name 
= os
.path
.basename(self
.dataFile
) 
1525         if not name
: name 
= defaultName
 
1527             self
.SetTitle(progname 
+ ': ' + name 
+ ' *') 
1529             self
.SetTitle(progname 
+ ': ' + name
) 
1531     def Open(self
, path
): 
1532         if not os
.path
.exists(path
): 
1533             wx
.LogError('File does not exists: %s' % path
) 
1535         # Try to read the file 
1539             dom 
= minidom
.parse(f
) 
1541             # Set encoding global variable and default encoding 
1543                 g
.currentEncoding 
= dom
.encoding
 
1544                 wx
.SetDefaultPyEncoding(g
.currentEncoding
.encode()) 
1546                 g
.currentEncoding 
= '' 
1548             self
.dataFile 
= path 
= os
.path
.abspath(path
) 
1549             dir = os
.path
.dirname(path
) 
1550             if dir: os
.chdir(dir) 
1551             # Allow importing modules from the same directory 
1552             sys
.path 
= sys_path 
+ [dir] 
1554             self
.SetTitle(progname 
+ ': ' + os
.path
.basename(path
)) 
1555             conf
.localconf 
= self
.CreateLocalConf(self
.dataFile
) 
1557             # Nice exception printing 
1558             inf 
= sys
.exc_info() 
1559             wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1]) 
1560             wx
.LogError('Error reading file: %s' % path
) 
1565     def Indent(self
, node
, indent 
= 0): 
1566         if node
.nodeType 
== minidom
.Node
.COMMENT_NODE
: 
1567             text 
= self
.domCopy
.createTextNode('\n' + ' ' * indent
) 
1568             node
.parentNode
.insertBefore(text
, node
) 
1569             return                      # no children 
1570         # Copy child list because it will change soon 
1571         children 
= node
.childNodes
[:] 
1572         # Main node doesn't need to be indented 
1574             text 
= self
.domCopy
.createTextNode('\n' + ' ' * indent
) 
1575             node
.parentNode
.insertBefore(text
, node
) 
1577             # Append newline after last child, except for text nodes 
1578             if children
[-1].nodeType 
== minidom
.Node
.ELEMENT_NODE
: 
1579                 text 
= self
.domCopy
.createTextNode('\n' + ' ' * indent
) 
1580                 node
.appendChild(text
) 
1581             # Indent children which are elements 
1583                 if n
.nodeType 
== minidom
.Node
.ELEMENT_NODE 
or \
 
1584                        n
.nodeType 
== minidom
.Node
.COMMENT_NODE
: 
1585                     self
.Indent(n
, indent 
+ 2) 
1587     def Save(self
, path
): 
1591             if tree
.selection 
and panel
.IsModified(): 
1592                 self
.OnRefresh(wx
.CommandEvent()) 
1593             if g
.currentEncoding
: 
1594                 f 
= codecs
.open(path
, 'wt', g
.currentEncoding
) 
1596                 f 
= codecs
.open(path
, 'wt') 
1597             # Make temporary copy for formatting it 
1598             # !!! We can't clone dom node, it works only once 
1599             #self.domCopy = tree.dom.cloneNode(True) 
1600             self
.domCopy 
= MyDocument() 
1601             mainNode 
= self
.domCopy
.appendChild(tree
.mainNode
.cloneNode(True)) 
1602             # Remove first child (test element) 
1603             testElem 
= mainNode
.firstChild
 
1604             mainNode
.removeChild(testElem
) 
1606             self
.Indent(mainNode
) 
1607             self
.domCopy
.writexml(f
, encoding 
= g
.currentEncoding
) 
1609             self
.domCopy
.unlink() 
1611             self
.SetModified(False) 
1612             panel
.SetModified(False) 
1613             conf
.localconf
.Flush() 
1615             inf 
= sys
.exc_info() 
1616             wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1]) 
1617             wx
.LogError('Error writing file: %s' % path
) 
1621         if not (self
.modified 
or panel
.IsModified()): return True 
1622         flags 
= wx
.ICON_EXCLAMATION | wx
.YES_NO | wx
.CANCEL | wx
.CENTRE
 
1623         dlg 
= wx
.MessageDialog( self
, 'File is modified. Save before exit?', 
1624                                'Save before too late?', flags 
) 
1625         say 
= dlg
.ShowModal() 
1628         if say 
== wx
.ID_YES
: 
1629             self
.OnSaveOrSaveAs(wx
.CommandEvent(wx
.ID_SAVE
)) 
1630             # If save was successful, modified flag is unset 
1631             if not self
.modified
: return True 
1632         elif say 
== wx
.ID_NO
: 
1633             self
.SetModified(False) 
1634             panel
.SetModified(False) 
1638 ################################################################################ 
1640 class PythonOptions(wx
.Dialog
): 
1642     def __init__(self
, parent
, cfg
, dataFile
): 
1643         pre 
= wx
.PreDialog() 
1644         g
.frame
.res
.LoadOnDialog(pre
, parent
, "PYTHON_OPTIONS") 
1645         self
.PostCreate(pre
) 
1648         self
.dataFile 
= dataFile
 
1650         self
.AutoGenerateCB 
= xrc
.XRCCTRL(self
, "AutoGenerateCB") 
1651         self
.EmbedCB 
= xrc
.XRCCTRL(self
, "EmbedCB") 
1652         self
.GettextCB 
= xrc
.XRCCTRL(self
, "GettextCB") 
1653         self
.MakeXRSFileCB 
= xrc
.XRCCTRL(self
, "MakeXRSFileCB") 
1654         self
.FileNameTC 
= xrc
.XRCCTRL(self
, "FileNameTC") 
1655         self
.BrowseBtn 
= xrc
.XRCCTRL(self
, "BrowseBtn") 
1656         self
.GenerateBtn 
= xrc
.XRCCTRL(self
, "GenerateBtn") 
1657         self
.SaveOptsBtn 
= xrc
.XRCCTRL(self
, "SaveOptsBtn") 
1659         self
.Bind(wx
.EVT_BUTTON
, self
.OnBrowse
, self
.BrowseBtn
) 
1660         self
.Bind(wx
.EVT_BUTTON
, self
.OnGenerate
, self
.GenerateBtn
) 
1661         self
.Bind(wx
.EVT_BUTTON
, self
.OnSaveOpts
, self
.SaveOptsBtn
) 
1663         if self
.cfg
.Read("filename", "") != "": 
1664             self
.FileNameTC
.SetValue(self
.cfg
.Read("filename")) 
1666             name 
= os
.path
.splitext(os
.path
.split(dataFile
)[1])[0] 
1668             self
.FileNameTC
.SetValue(name
) 
1669         self
.AutoGenerateCB
.SetValue(self
.cfg
.ReadBool("autogenerate", False)) 
1670         self
.EmbedCB
.SetValue(self
.cfg
.ReadBool("embedResource", False)) 
1671         self
.MakeXRSFileCB
.SetValue(self
.cfg
.ReadBool("makeXRS", False)) 
1672         self
.GettextCB
.SetValue(self
.cfg
.ReadBool("genGettext", False)) 
1675     def OnBrowse(self
, evt
): 
1676         path 
= self
.FileNameTC
.GetValue() 
1677         dirname 
= os
.path
.abspath(os
.path
.dirname(path
)) 
1678         name 
= os
.path
.split(path
)[1] 
1679         dlg 
= wx
.FileDialog(self
, 'Save As', dirname
, name
, '*.py', 
1680                                wx
.SAVE | wx
.OVERWRITE_PROMPT
) 
1681         if dlg
.ShowModal() == wx
.ID_OK
: 
1682             path 
= dlg
.GetPath() 
1683             self
.FileNameTC
.SetValue(path
) 
1687     def OnGenerate(self
, evt
): 
1688         pypath 
= self
.FileNameTC
.GetValue() 
1689         embed 
= self
.EmbedCB
.GetValue() 
1690         genGettext 
= self
.GettextCB
.GetValue() 
1691         frame
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
) 
1695     def OnSaveOpts(self
, evt
=None): 
1696         self
.cfg
.Write("filename", self
.FileNameTC
.GetValue()) 
1697         self
.cfg
.WriteBool("autogenerate", self
.AutoGenerateCB
.GetValue()) 
1698         self
.cfg
.WriteBool("embedResource", self
.EmbedCB
.GetValue()) 
1699         self
.cfg
.WriteBool("makeXRS", self
.MakeXRSFileCB
.GetValue()) 
1700         self
.cfg
.WriteBool("genGettext", self
.GettextCB
.GetValue()) 
1702         self
.EndModal(wx
.ID_OK
) 
1704 ################################################################################ 
1706 class PrefsDialog(wx
.Dialog
): 
1708     def __init__(self
, parent
): 
1709         pre 
= wx
.PreDialog() 
1710         g
.frame
.res
.LoadOnDialog(pre
, parent
, "DIALOG_PREFS") 
1711         self
.PostCreate(pre
) 
1712         self
.checkControls 
= {} # map of check IDs to (control,dict,param) 
1714         ##xxx = sys.modules['xxx'] 
1716         d 
= xxx
.xxxSizerItem
.defaults_panel
 
1718         self
.check_proportion_panel 
= xrc
.XRCCTRL(self
, 'check_proportion_panel') 
1719         id = self
.check_proportion_panel
.GetId() 
1720         wx
.EVT_CHECKBOX(self
, id, self
.OnCheck
) 
1721         self
.checkControls
[id] = (xrc
.XRCCTRL(self
, 'spin_proportion_panel'), 
1724         self
.check_flag_panel 
= xrc
.XRCCTRL(self
, 'check_flag_panel') 
1725         id = self
.check_flag_panel
.GetId() 
1726         wx
.EVT_CHECKBOX(self
, id, self
.OnCheck
) 
1727         self
.checkControls
[id] = (xrc
.XRCCTRL(self
, 'text_flag_panel'), 
1730         d 
= xxx
.xxxSizerItem
.defaults_control
 
1732         self
.check_proportion_panel 
= xrc
.XRCCTRL(self
, 'check_proportion_control') 
1733         id = self
.check_proportion_panel
.GetId() 
1734         wx
.EVT_CHECKBOX(self
, id, self
.OnCheck
) 
1735         self
.checkControls
[id] = (xrc
.XRCCTRL(self
, 'spin_proportion_control'), 
1738         self
.check_flag_panel 
= xrc
.XRCCTRL(self
, 'check_flag_control') 
1739         id = self
.check_flag_panel
.GetId() 
1740         wx
.EVT_CHECKBOX(self
, id, self
.OnCheck
) 
1741         self
.checkControls
[id] = (xrc
.XRCCTRL(self
, 'text_flag_control'), 
1744         for id,cdp 
in self
.checkControls
.items(): 
1747                 if isinstance(c
, wx
.SpinCtrl
): 
1748                     c
.SetValue(int(d
[p
])) 
1751                 self
.FindWindowById(id).SetValue(True) 
1755         self
.radio_allow_exec 
= xrc
.XRCCTRL(self
, 'radio_allow_exec') 
1757             radio 
= {'ask': 0, 'yes':1, 'no':2}
[g
.conf
.allowExec
] 
1760         self
.radio_allow_exec
.SetSelection(radio
) 
1762     def OnCheck(self
, evt
): 
1763         self
.checkControls
[evt
.GetId()][0].Enable(evt
.IsChecked()) 
1766 ################################################################################ 
1768 # Parse string in form var1=val1[,var2=val2]* as dictionary 
1769 def ReadDictFromString(s
): 
1771     for vv 
in s
.split(','): 
1772         var
,val 
= vv
.split(':') 
1773         d
[var
.strip()] = val
 
1776 # Transform dictionary with strings into one string 
1777 def DictToString(d
): 
1778     return ','.join(map(':'.join
, d
.items())) 
1781     print >> sys
.stderr
, 'usage: xrced [-dhiv] [file]' 
1786         if wx
.VERSION
[:3] < MinWxVersion
: 
1788 This version of XRCed may not work correctly on your version of wxWidgets. \ 
1789 Please upgrade wxWidgets to %d.%d.%d or higher.''' % MinWxVersion
) 
1791         # Process comand-line 
1794             opts
, args 
= getopt
.getopt(sys
.argv
[1:], 'dhiv') 
1802                     print 'XRCed version', version
 
1805         except getopt
.GetoptError
: 
1806             if wx
.Platform 
!= '__WXMAC__': # macs have some extra parameters 
1807                 print >> sys
.stderr
, 'Unknown option' 
1811         self
.SetAppName('xrced') 
1814         conf 
= g
.conf 
= wx
.Config(style 
= wx
.CONFIG_USE_LOCAL_FILE
) 
1815         conf
.localconf 
= None 
1816         conf
.autoRefresh 
= conf
.ReadInt('autorefresh', True) 
1817         pos 
= conf
.ReadInt('x', -1), conf
.ReadInt('y', -1) 
1818         size 
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600) 
1819         conf
.embedPanel 
= conf
.ReadInt('embedPanel', True) 
1820         conf
.showTools 
= conf
.ReadInt('showTools', True) 
1821         conf
.sashPos 
= conf
.ReadInt('sashPos', 200) 
1823         # read recently used files 
1824         g
.fileHistory 
= wx
.FileHistory() 
1825         g
.fileHistory
.Load(conf
) 
1827         if not conf
.embedPanel
: 
1828             conf
.panelX 
= conf
.ReadInt('panelX', -1) 
1829             conf
.panelY 
= conf
.ReadInt('panelY', -1) 
1831             conf
.panelX 
= conf
.panelY 
= -1 
1832         conf
.panelWidth 
= conf
.ReadInt('panelWidth', 200) 
1833         conf
.panelHeight 
= conf
.ReadInt('panelHeight', 200) 
1834         conf
.panic 
= not conf
.HasEntry('nopanic') 
1836         conf
.allowExec 
= conf
.Read('Prefs/allowExec', 'ask') 
1837         p 
= 'Prefs/sizeritem_defaults_panel' 
1839         if conf
.HasEntry(p
): 
1840             ##sys.modules['xxx'].xxxSizerItem.defaults_panel = ReadDictFromString(conf.Read(p)) 
1841             xxx
.xxxSizerItem
.defaults_panel 
= ReadDictFromString(conf
.Read(p
)) 
1842         p 
= 'Prefs/sizeritem_defaults_control' 
1843         if conf
.HasEntry(p
): 
1844             ##sys.modules['xxx'].xxxSizerItem.defaults_control = ReadDictFromString(conf.Read(p)) 
1845             xxx
.xxxSizerItem
.defaults_control 
= ReadDictFromString(conf
.Read(p
)) 
1848         wx
.FileSystem
.AddHandler(wx
.MemoryFSHandler()) 
1849         self
.toolArtProvider 
= ToolArtProvider() 
1850         wx
.ArtProvider
.Push(self
.toolArtProvider
) 
1852         frame 
= Frame(pos
, size
) 
1853         # Mac does not set the correct size 
1854         if wx
.Platform 
== '__WXMAC__': 
1855             frame
.SetClientSize(size
) 
1859         plugins 
= os
.getenv('XRCEDPATH') 
1863                 for dir in plugins
.split(':'): 
1864                     if os
.path
.isdir(dir) and \
 
1865                        os
.path
.isfile(os
.path
.join(dir, '__init__.py')): 
1867                         dir = os
.path
.abspath(os
.path
.normpath(dir)) 
1868                         sys
.path 
= sys_path 
+ [os
.path
.dirname(dir)] 
1871                             __import__(os
.path
.basename(dir), globals(), locals(), ['*']) 
1873                             print traceback
.print_exc() 
1876         # Store important data 
1877         frame
.handlers 
= getHandlers()[:] 
1878         frame
.custom 
= g
.pullDownMenu
.custom
[:] 
1879         frame
.modules 
= sys
.modules
.copy() 
1884         # Load file after showing 
1887             frame
.open = frame
.Open(args
[0]) 
1895         wc
.WriteInt('autorefresh', conf
.autoRefresh
) 
1896         wc
.WriteInt('x', conf
.x
) 
1897         wc
.WriteInt('y', conf
.y
) 
1898         wc
.WriteInt('width', conf
.width
) 
1899         wc
.WriteInt('height', conf
.height
) 
1900         wc
.WriteInt('embedPanel', conf
.embedPanel
) 
1901         wc
.WriteInt('showTools', conf
.showTools
) 
1902         if not conf
.embedPanel
: 
1903             wc
.WriteInt('panelX', conf
.panelX
) 
1904             wc
.WriteInt('panelY', conf
.panelY
) 
1905         wc
.WriteInt('sashPos', conf
.sashPos
) 
1906         wc
.WriteInt('panelWidth', conf
.panelWidth
) 
1907         wc
.WriteInt('panelHeight', conf
.panelHeight
) 
1908         wc
.WriteInt('nopanic', 1) 
1909         g
.fileHistory
.Save(wc
) 
1911         wc
.DeleteGroup('Prefs') 
1912         wc
.Write('Prefs/allowExec', conf
.allowExec
) 
1914         ##v = sys.modules['xxx'].xxxSizerItem.defaults_panel 
1915         v 
= xxx
.xxxSizerItem
.defaults_panel
 
1916         if v
: wc
.Write('Prefs/sizeritem_defaults_panel', DictToString(v
)) 
1917         ###v = sys.modules['xxx'].xxxSizerItem.defaults_control 
1918         v 
= xxx
.xxxSizerItem
.defaults_control
 
1919         if v
: wc
.Write('Prefs/sizeritem_defaults_control', DictToString(v
)) 
1924     app 
= App(0, useBestVisual
=False) 
1925     #app.SetAssertMode(wx.PYAPP_ASSERT_LOG) 
1931 if __name__ 
== '__main__':