]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/tools/XRCed/xrced.py
5e1068f57bb7789f8aa05de3c60eaddd23dc2e36
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 # 1 adds CMD command to Help menu
47 <HTML><H2>Welcome to XRC<font color="blue">ed</font></H2><H3><font color="green">DON'T PANIC :)</font></H3>
48 Read this note before clicking on anything!<P>
49 To start select tree root, then popup menu with your right mouse button,
50 select "Append Child", and then any command.<P>
51 Or just press one of the buttons on the tools palette.<P>
52 Enter XML ID, change properties, create children.<P>
53 To test your interface select Test command (View menu).<P>
54 Consult README file for the details.</HTML>
57 defaultIDs
= {xxxPanel
:'PANEL', xxxDialog
:'DIALOG', xxxFrame
:'FRAME',
58 xxxMenuBar
:'MENUBAR', xxxMenu
:'MENU', xxxToolBar
:'TOOLBAR',
59 xxxWizard
:'WIZARD', xxxBitmap
:'BITMAP', xxxIcon
:'ICON'}
61 defaultName
= 'UNTITLED.xrc'
63 ################################################################################
65 # ScrolledMessageDialog - modified from wxPython lib to set fixed-width font
66 class ScrolledMessageDialog(wx
.Dialog
):
67 def __init__(self
, parent
, msg
, caption
, pos
= wx
.DefaultPosition
, size
= (500,300)):
68 from wx
.lib
.layoutf
import Layoutf
69 wx
.Dialog
.__init
__(self
, parent
, -1, caption
, pos
, size
)
70 text
= wx
.TextCtrl(self
, -1, msg
, wx
.DefaultPosition
,
71 wx
.DefaultSize
, wx
.TE_MULTILINE | wx
.TE_READONLY
)
72 text
.SetFont(g
.modernFont())
73 dc
= wx
.WindowDC(text
)
74 # !!! possible bug - GetTextExtent without font returns sysfont dims
75 w
, h
= dc
.GetFullTextExtent(' ', g
.modernFont())[:2]
76 ok
= wx
.Button(self
, wx
.ID_OK
, "OK")
77 text
.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self
,ok
)))
78 text
.SetSize((w
* 80 + 30, h
* 40))
80 ok
.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self
,)))
81 self
.SetAutoLayout(True)
83 self
.CenterOnScreen(wx
.BOTH
)
85 ################################################################################
87 # Event handler for using during location
88 class Locator(wx
.EvtHandler
):
89 def ProcessEvent(self
, evt
):
92 class Frame(wx
.Frame
):
93 def __init__(self
, pos
, size
):
94 wx
.Frame
.__init
__(self
, None, -1, '', pos
, size
)
96 frame
= g
.frame
= self
97 bar
= self
.CreateStatusBar(2)
98 bar
.SetStatusWidths([-1, 40])
99 self
.SetIcon(images
.getIconIcon())
104 # Load our own resources
105 self
.res
= xrc
.XmlResource('')
106 # !!! Blocking of assert failure occurring in older unicode builds
108 quietlog
= wx
.LogNull()
109 self
.res
.Load(os
.path
.join(basePath
, 'xrced.xrc'))
110 except wx
._core
.PyAssertionError
:
111 print 'PyAssertionError was ignored'
114 menuBar
= wx
.MenuBar()
117 menu
.Append(wx
.ID_NEW
, '&New\tCtrl-N', 'New file')
118 menu
.AppendSeparator()
119 menu
.Append(wx
.ID_OPEN
, '&Open...\tCtrl-O', 'Open XRC file')
120 self
.recentMenu
= wx
.Menu()
121 self
.AppendRecent(self
.recentMenu
)
122 menu
.AppendMenu(-1, 'Open Recent', self
.recentMenu
, 'Open a recent file')
123 menu
.AppendSeparator()
124 menu
.Append(wx
.ID_SAVE
, '&Save\tCtrl-S', 'Save XRC file')
125 menu
.Append(wx
.ID_SAVEAS
, 'Save &As...', 'Save XRC file under different name')
126 self
.ID_GENERATE_PYTHON
= wx
.NewId()
127 menu
.Append(self
.ID_GENERATE_PYTHON
, '&Generate Python...',
128 'Generate a Python module that uses this XRC')
129 menu
.AppendSeparator()
130 menu
.Append(wx
.ID_EXIT
, '&Quit\tCtrl-Q', 'Exit application')
132 menuBar
.Append(menu
, '&File')
135 menu
.Append(wx
.ID_UNDO
, '&Undo\tCtrl-Z', 'Undo')
136 menu
.Append(wx
.ID_REDO
, '&Redo\tCtrl-Y', 'Redo')
137 menu
.AppendSeparator()
138 menu
.Append(wx
.ID_CUT
, 'Cut\tCtrl-X', 'Cut to the clipboard')
139 menu
.Append(wx
.ID_COPY
, '&Copy\tCtrl-C', 'Copy to the clipboard')
140 menu
.Append(wx
.ID_PASTE
, '&Paste\tCtrl-V', 'Paste from the clipboard')
141 self
.ID_DELETE
= wx
.NewId()
142 menu
.Append(self
.ID_DELETE
, '&Delete\tCtrl-D', 'Delete object')
143 menu
.AppendSeparator()
144 self
.ID_LOCATE
= wx
.NewId()
145 self
.ID_TOOL_LOCATE
= wx
.NewId()
146 self
.ID_TOOL_PASTE
= wx
.NewId()
147 menu
.Append(self
.ID_LOCATE
, '&Locate\tCtrl-L', 'Locate control in test window and select it')
148 menuBar
.Append(menu
, '&Edit')
151 self
.ID_EMBED_PANEL
= wx
.NewId()
152 menu
.Append(self
.ID_EMBED_PANEL
, '&Embed Panel',
153 'Toggle embedding properties panel in the main window', True)
154 menu
.Check(self
.ID_EMBED_PANEL
, conf
.embedPanel
)
155 self
.ID_SHOW_TOOLS
= wx
.NewId()
156 menu
.Append(self
.ID_SHOW_TOOLS
, 'Show &Tools', 'Toggle tools', True)
157 menu
.Check(self
.ID_SHOW_TOOLS
, conf
.showTools
)
158 menu
.AppendSeparator()
159 self
.ID_TEST
= wx
.NewId()
160 menu
.Append(self
.ID_TEST
, '&Test\tF5', 'Show test window')
161 self
.ID_REFRESH
= wx
.NewId()
162 menu
.Append(self
.ID_REFRESH
, '&Refresh\tCtrl-R', 'Refresh test window')
163 self
.ID_AUTO_REFRESH
= wx
.NewId()
164 menu
.Append(self
.ID_AUTO_REFRESH
, '&Auto-refresh\tCtrl-A',
165 'Toggle auto-refresh mode', True)
166 menu
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
167 self
.ID_TEST_HIDE
= wx
.NewId()
168 menu
.Append(self
.ID_TEST_HIDE
, '&Hide\tF6', 'Close test window')
169 menuBar
.Append(menu
, '&View')
172 self
.ID_MOVEUP
= wx
.NewId()
173 menu
.Append(self
.ID_MOVEUP
, '&Up', 'Move before previous sibling')
174 self
.ID_MOVEDOWN
= wx
.NewId()
175 menu
.Append(self
.ID_MOVEDOWN
, '&Down', 'Move after next sibling')
176 self
.ID_MOVELEFT
= wx
.NewId()
177 menu
.Append(self
.ID_MOVELEFT
, '&Make sibling', 'Make sibling of parent')
178 self
.ID_MOVERIGHT
= wx
.NewId()
179 menu
.Append(self
.ID_MOVERIGHT
, '&Make child', 'Make child of previous sibling')
180 menuBar
.Append(menu
, '&Move')
183 menu
.Append(wx
.ID_ABOUT
, '&About...', 'About XCRed')
184 self
.ID_README
= wx
.NewId()
185 menu
.Append(self
.ID_README
, '&Readme...', 'View the README file')
187 self
.ID_DEBUG_CMD
= wx
.NewId()
188 menu
.Append(self
.ID_DEBUG_CMD
, 'CMD', 'Python command line')
189 wx
.EVT_MENU(self
, self
.ID_DEBUG_CMD
, self
.OnDebugCMD
)
190 menuBar
.Append(menu
, '&Help')
192 self
.menuBar
= menuBar
193 self
.SetMenuBar(menuBar
)
196 tb
= self
.CreateToolBar(wx
.TB_HORIZONTAL | wx
.NO_BORDER | wx
.TB_FLAT
)
197 tb
.SetToolBitmapSize((24,24))
198 new_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_NORMAL_FILE
, wx
.ART_TOOLBAR
)
199 open_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_FILE_OPEN
, wx
.ART_TOOLBAR
)
200 save_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_FILE_SAVE
, wx
.ART_TOOLBAR
)
201 undo_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_UNDO
, wx
.ART_TOOLBAR
)
202 redo_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_REDO
, wx
.ART_TOOLBAR
)
203 cut_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_CUT
, wx
.ART_TOOLBAR
)
204 copy_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_COPY
, wx
.ART_TOOLBAR
)
205 paste_bmp
= wx
.ArtProvider
.GetBitmap(wx
.ART_PASTE
, wx
.ART_TOOLBAR
)
207 tb
.AddSimpleTool(wx
.ID_NEW
, new_bmp
, 'New', 'New file')
208 tb
.AddSimpleTool(wx
.ID_OPEN
, open_bmp
, 'Open', 'Open file')
209 tb
.AddSimpleTool(wx
.ID_SAVE
, save_bmp
, 'Save', 'Save file')
210 tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23), style
=wx
.LI_VERTICAL
))
211 tb
.AddSimpleTool(wx
.ID_UNDO
, undo_bmp
, 'Undo', 'Undo')
212 tb
.AddSimpleTool(wx
.ID_REDO
, redo_bmp
, 'Redo', 'Redo')
213 tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23), style
=wx
.LI_VERTICAL
))
214 tb
.AddSimpleTool(wx
.ID_CUT
, cut_bmp
, 'Cut', 'Cut')
215 tb
.AddSimpleTool(wx
.ID_COPY
, copy_bmp
, 'Copy', 'Copy')
216 tb
.AddSimpleTool(self
.ID_TOOL_PASTE
, paste_bmp
, 'Paste', 'Paste')
217 tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23), style
=wx
.LI_VERTICAL
))
218 tb
.AddSimpleTool(self
.ID_TOOL_LOCATE
,
219 images
.getLocateBitmap(), #images.getLocateArmedBitmap(),
220 'Locate', 'Locate control in test window and select it', True)
221 tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23), style
=wx
.LI_VERTICAL
))
222 tb
.AddSimpleTool(self
.ID_TEST
, images
.getTestBitmap(), 'Test', 'Test window')
223 tb
.AddSimpleTool(self
.ID_REFRESH
, images
.getRefreshBitmap(),
224 'Refresh', 'Refresh view')
225 tb
.AddSimpleTool(self
.ID_AUTO_REFRESH
, images
.getAutoRefreshBitmap(),
226 'Auto-refresh', 'Toggle auto-refresh mode', True)
227 tb
.AddControl(wx
.StaticLine(tb
, -1, size
=(-1,23), style
=wx
.LI_VERTICAL
))
228 tb
.AddSimpleTool(self
.ID_MOVEUP
, images
.getToolMoveUpBitmap(),
229 'Up', 'Move before previous sibling')
230 tb
.AddSimpleTool(self
.ID_MOVEDOWN
, images
.getToolMoveDownBitmap(),
231 'Down', 'Move after next sibling')
232 tb
.AddSimpleTool(self
.ID_MOVELEFT
, images
.getToolMoveLeftBitmap(),
233 'Make Sibling', 'Make sibling of parent')
234 tb
.AddSimpleTool(self
.ID_MOVERIGHT
, images
.getToolMoveRightBitmap(),
235 'Make Child', 'Make child of previous sibling')
236 # if wx.Platform == '__WXGTK__':
237 # tb.AddSeparator() # otherwise auto-refresh sticks in status line
238 tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
242 self
.minWidth
= tb
.GetSize()[0] # minimal width is the size of toolbar
245 wx
.EVT_MENU(self
, wx
.ID_NEW
, self
.OnNew
)
246 wx
.EVT_MENU(self
, wx
.ID_OPEN
, self
.OnOpen
)
247 wx
.EVT_MENU(self
, wx
.ID_SAVE
, self
.OnSaveOrSaveAs
)
248 wx
.EVT_MENU(self
, wx
.ID_SAVEAS
, self
.OnSaveOrSaveAs
)
249 wx
.EVT_MENU(self
, self
.ID_GENERATE_PYTHON
, self
.OnGeneratePython
)
250 wx
.EVT_MENU(self
, wx
.ID_EXIT
, self
.OnExit
)
252 wx
.EVT_MENU(self
, wx
.ID_UNDO
, self
.OnUndo
)
253 wx
.EVT_MENU(self
, wx
.ID_REDO
, self
.OnRedo
)
254 wx
.EVT_MENU(self
, wx
.ID_CUT
, self
.OnCutDelete
)
255 wx
.EVT_MENU(self
, wx
.ID_COPY
, self
.OnCopy
)
256 wx
.EVT_MENU(self
, wx
.ID_PASTE
, self
.OnPaste
)
257 wx
.EVT_MENU(self
, self
.ID_TOOL_PASTE
, self
.OnPaste
)
258 wx
.EVT_MENU(self
, self
.ID_DELETE
, self
.OnCutDelete
)
259 wx
.EVT_MENU(self
, self
.ID_LOCATE
, self
.OnLocate
)
260 wx
.EVT_MENU(self
, self
.ID_TOOL_LOCATE
, self
.OnLocate
)
262 wx
.EVT_MENU(self
, self
.ID_EMBED_PANEL
, self
.OnEmbedPanel
)
263 wx
.EVT_MENU(self
, self
.ID_SHOW_TOOLS
, self
.OnShowTools
)
264 wx
.EVT_MENU(self
, self
.ID_TEST
, self
.OnTest
)
265 wx
.EVT_MENU(self
, self
.ID_REFRESH
, self
.OnRefresh
)
266 wx
.EVT_MENU(self
, self
.ID_AUTO_REFRESH
, self
.OnAutoRefresh
)
267 wx
.EVT_MENU(self
, self
.ID_TEST_HIDE
, self
.OnTestHide
)
269 wx
.EVT_MENU(self
, self
.ID_MOVEUP
, self
.OnMoveUp
)
270 wx
.EVT_MENU(self
, self
.ID_MOVEDOWN
, self
.OnMoveDown
)
271 wx
.EVT_MENU(self
, self
.ID_MOVELEFT
, self
.OnMoveLeft
)
272 wx
.EVT_MENU(self
, self
.ID_MOVERIGHT
, self
.OnMoveRight
)
274 wx
.EVT_MENU(self
, wx
.ID_ABOUT
, self
.OnAbout
)
275 wx
.EVT_MENU(self
, self
.ID_README
, self
.OnReadme
)
278 wx
.EVT_UPDATE_UI(self
, wx
.ID_SAVE
, self
.OnUpdateUI
)
279 wx
.EVT_UPDATE_UI(self
, wx
.ID_CUT
, self
.OnUpdateUI
)
280 wx
.EVT_UPDATE_UI(self
, wx
.ID_COPY
, self
.OnUpdateUI
)
281 wx
.EVT_UPDATE_UI(self
, wx
.ID_PASTE
, self
.OnUpdateUI
)
282 wx
.EVT_UPDATE_UI(self
, self
.ID_LOCATE
, self
.OnUpdateUI
)
283 wx
.EVT_UPDATE_UI(self
, self
.ID_TOOL_LOCATE
, self
.OnUpdateUI
)
284 wx
.EVT_UPDATE_UI(self
, self
.ID_TOOL_PASTE
, self
.OnUpdateUI
)
285 wx
.EVT_UPDATE_UI(self
, wx
.ID_UNDO
, self
.OnUpdateUI
)
286 wx
.EVT_UPDATE_UI(self
, wx
.ID_REDO
, self
.OnUpdateUI
)
287 wx
.EVT_UPDATE_UI(self
, self
.ID_DELETE
, self
.OnUpdateUI
)
288 wx
.EVT_UPDATE_UI(self
, self
.ID_TEST
, self
.OnUpdateUI
)
289 wx
.EVT_UPDATE_UI(self
, self
.ID_REFRESH
, self
.OnUpdateUI
)
292 sizer
= wx
.BoxSizer(wx
.VERTICAL
)
293 sizer
.Add(wx
.StaticLine(self
, -1), 0, wx
.EXPAND
)
294 # Horizontal sizer for toolbar and splitter
295 self
.toolsSizer
= sizer1
= wx
.BoxSizer()
296 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.SP_3DSASH
)
297 self
.splitter
= splitter
298 splitter
.SetMinimumPaneSize(100)
301 g
.tree
= tree
= XML_Tree(splitter
, -1)
303 # Init pull-down menu data
305 g
.pullDownMenu
= pullDownMenu
= PullDownMenu(self
)
307 # Vertical toolbar for GUI buttons
308 g
.tools
= tools
= Tools(self
)
309 tools
.Show(conf
.showTools
)
310 if conf
.showTools
: sizer1
.Add(tools
, 0, wx
.EXPAND
)
312 tree
.RegisterKeyEvents()
314 # Miniframe for split mode
315 miniFrame
= wx
.MiniFrame(self
, -1, 'Properties & Style',
316 (conf
.panelX
, conf
.panelY
),
317 (conf
.panelWidth
, conf
.panelHeight
))
318 self
.miniFrame
= miniFrame
319 sizer2
= wx
.BoxSizer()
320 miniFrame
.SetAutoLayout(True)
321 miniFrame
.SetSizer(sizer2
)
322 wx
.EVT_CLOSE(self
.miniFrame
, self
.OnCloseMiniFrame
)
323 # Create panel for parameters
326 panel
= Panel(splitter
)
327 # Set plitter windows
328 splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
330 panel
= Panel(miniFrame
)
331 sizer2
.Add(panel
, 1, wx
.EXPAND
)
333 splitter
.Initialize(tree
)
334 sizer1
.Add(splitter
, 1, wx
.EXPAND
)
335 sizer
.Add(sizer1
, 1, wx
.EXPAND
)
336 self
.SetAutoLayout(True)
343 wx
.EVT_IDLE(self
, self
.OnIdle
)
344 wx
.EVT_CLOSE(self
, self
.OnCloseWindow
)
345 wx
.EVT_KEY_DOWN(self
, tools
.OnKeyDown
)
346 wx
.EVT_KEY_UP(self
, tools
.OnKeyUp
)
347 wx
.EVT_ICONIZE(self
, self
.OnIconize
)
349 def AppendRecent(self
, menu
):
350 # add recently used files to the menu
351 for id,name
in conf
.recentfiles
.iteritems():
353 wx
.EVT_MENU(self
,id,self
.OnRecentFile
)
356 def OnRecentFile(self
,evt
):
357 # open recently used file
358 if not self
.AskSave(): return
361 path
=conf
.recentfiles
[evt
.GetId()]
363 self
.SetStatusText('Data loaded')
365 self
.SetStatusText('Failed')
367 self
.SetStatusText('No such file')
370 def OnNew(self
, evt
):
371 if not self
.AskSave(): return
374 def OnOpen(self
, evt
):
375 if not self
.AskSave(): return
376 dlg
= wx
.FileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
),
377 '', '*.xrc', wx
.OPEN | wx
.CHANGE_DIR
)
378 if dlg
.ShowModal() == wx
.ID_OK
:
380 self
.SetStatusText('Loading...')
384 self
.SetStatusText('Data loaded')
386 self
.SetStatusText('Failed')
387 self
.SaveRecent(path
)
392 def OnSaveOrSaveAs(self
, evt
):
393 if evt
.GetId() == wx
.ID_SAVEAS
or not self
.dataFile
:
394 if self
.dataFile
: name
= ''
395 else: name
= defaultName
396 dirname
= os
.path
.abspath(os
.path
.dirname(self
.dataFile
))
397 dlg
= wx
.FileDialog(self
, 'Save As', dirname
, name
, '*.xrc',
398 wx
.SAVE | wx
.OVERWRITE_PROMPT | wx
.CHANGE_DIR
)
399 if dlg
.ShowModal() == wx
.ID_OK
:
401 if isinstance(path
, unicode):
402 path
= path
.encode(sys
.getfilesystemencoding())
409 # if we already have a localconf then it needs to be
410 # copied to a new config with the new name
412 nc
= self
.CreateLocalConf(path
)
413 flag
, key
, idx
= lc
.GetFirstEntry()
415 nc
.Write(key
, lc
.Read(key
))
416 flag
, key
, idx
= lc
.GetNextEntry(idx
)
419 # otherwise create a new one
420 conf
.localconf
= self
.CreateLocalConf(path
)
423 self
.SetStatusText('Saving...')
427 tmpFile
,tmpName
= tempfile
.mkstemp(prefix
='xrced-')
429 self
.Save(tmpName
) # save temporary file first
430 shutil
.move(tmpName
, path
)
432 if conf
.localconf
.ReadBool("autogenerate", False):
433 pypath
= conf
.localconf
.Read("filename")
434 embed
= conf
.localconf
.ReadBool("embedResource", False)
435 genGettext
= conf
.localconf
.ReadBool("genGettext", False)
436 self
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
)
438 self
.SetStatusText('Data saved')
439 self
.SaveRecent(path
)
441 self
.SetStatusText('Failed')
445 def SaveRecent(self
,path
):
446 # append to recently used files
447 if path
not in conf
.recentfiles
.values():
449 self
.recentMenu
.Append(newid
, path
)
450 wx
.EVT_MENU(self
, newid
, self
.OnRecentFile
)
451 conf
.recentfiles
[newid
] = path
453 def GeneratePython(self
, dataFile
, pypath
, embed
, genGettext
):
455 import wx
.tools
.pywxrc
456 rescomp
= wx
.tools
.pywxrc
.XmlResourceCompiler()
457 rescomp
.MakePythonModule([dataFile
], pypath
, embed
, genGettext
)
460 wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
461 wx
.LogError('Error generating python code : %s' % pypath
)
465 def OnGeneratePython(self
, evt
):
466 if self
.modified
or not conf
.localconf
:
467 wx
.MessageBox("Save the XRC file first!", "Error")
470 dlg
= PythonOptions(self
, conf
.localconf
, self
.dataFile
)
475 def OnExit(self
, evt
):
478 def OnUndo(self
, evt
):
479 # Extra check to not mess with idle updating
480 if undoMan
.CanUndo():
483 def OnRedo(self
, evt
):
484 if undoMan
.CanRedo():
487 def OnCopy(self
, evt
):
488 selected
= tree
.selection
489 if not selected
: return # key pressed event
490 xxx
= tree
.GetPyData(selected
)
491 if wx
.TheClipboard
.Open():
493 data
= wx
.CustomDataObject('XRCED')
494 # Set encoding in header
496 s
= xxx
.node
.toxml(encoding
=expat
.native_encoding
)
498 data
= wx
.CustomDataObject('XRCED_node')
500 data
.SetData(cPickle
.dumps(s
))
501 wx
.TheClipboard
.SetData(data
)
502 wx
.TheClipboard
.Close()
503 self
.SetStatusText('Copied')
505 wx
.MessageBox("Unable to open the clipboard", "Error")
507 def OnPaste(self
, evt
):
508 selected
= tree
.selection
509 if not selected
: return # key pressed event
510 # For pasting with Ctrl pressed
512 if evt
.GetId() == pullDownMenu
.ID_PASTE_SIBLING
: appendChild
= False
513 elif evt
.GetId() == self
.ID_TOOL_PASTE
:
514 if g
.tree
.ctrl
: appendChild
= False
515 else: appendChild
= not tree
.NeedInsert(selected
)
516 else: appendChild
= not tree
.NeedInsert(selected
)
517 xxx
= tree
.GetPyData(selected
)
519 # If has next item, insert, else append to parent
520 nextItem
= tree
.GetNextSibling(selected
)
521 parentLeaf
= tree
.GetItemParent(selected
)
522 # Expanded container (must have children)
523 elif tree
.IsExpanded(selected
) and tree
.GetChildrenCount(selected
, False):
524 # Insert as first child
525 nextItem
= tree
.GetFirstChild(selected
)[0]
526 parentLeaf
= selected
528 # No children or unexpanded item - appendChild stays True
529 nextItem
= wx
.TreeItemId() # no next item
530 parentLeaf
= selected
531 parent
= tree
.GetPyData(parentLeaf
).treeObject()
533 # Create a copy of clipboard pickled element
534 success
= success_node
= False
535 if wx
.TheClipboard
.Open():
536 data
= wx
.CustomDataObject('XRCED')
537 if wx
.TheClipboard
.IsSupported(data
.GetFormat()):
538 success
= wx
.TheClipboard
.GetData(data
)
539 if not success
: # try other format
540 data
= wx
.CustomDataObject('XRCED_node')
541 if wx
.TheClipboard
.IsSupported(data
.GetFormat()):
542 success_node
= wx
.TheClipboard
.GetData(data
)
543 wx
.TheClipboard
.Close()
545 if not success
and not success_node
:
547 "There is no data in the clipboard in the required format",
551 xml
= cPickle
.loads(data
.GetData()) # xml representation of element
553 elem
= minidom
.parseString(xml
).childNodes
[0]
555 elem
= g
.tree
.dom
.createComment(xml
)
557 # Tempopary xxx object to test things
558 xxx
= MakeXXXFromDOM(parent
, elem
)
560 # Check compatibility
561 if not self
.ItemsAreCompatible(parent
, xxx
.treeObject()): return
563 # Check parent and child relationships.
564 # If parent is sizer or notebook, child is of wrong class or
565 # parent is normal window, child is child container then detach child.
566 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
567 parentIsBook
= parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
]
568 if isChildContainer
and \
569 ((parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
570 (parentIsBook
and not isinstance(xxx
, xxxPage
)) or \
571 not (parent
.isSizer
or parentIsBook
)):
572 elem
.removeChild(xxx
.child
.node
) # detach child
573 elem
.unlink() # delete child container
574 elem
= xxx
.child
.node
# replace
575 # This may help garbage collection
576 xxx
.child
.parent
= None
577 isChildContainer
= False
578 # Parent is sizer or notebook, child is not child container
579 if parent
.isSizer
and not isChildContainer
and not isinstance(xxx
, xxxSpacer
):
580 # Create sizer item element
581 sizerItemElem
= MakeEmptyDOM(parent
.itemTag
)
582 sizerItemElem
.appendChild(elem
)
584 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
585 pageElem
= MakeEmptyDOM('notebookpage')
586 pageElem
.appendChild(elem
)
588 elif isinstance(parent
, xxxChoicebook
) and not isChildContainer
:
589 pageElem
= MakeEmptyDOM('choicebookpage')
590 pageElem
.appendChild(elem
)
592 elif isinstance(parent
, xxxListbook
) and not isChildContainer
:
593 pageElem
= MakeEmptyDOM('listbookpage')
594 pageElem
.appendChild(elem
)
596 # Insert new node, register undo
597 newItem
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
)
598 undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
))
599 # Scroll to show new item (!!! redundant?)
600 tree
.EnsureVisible(newItem
)
601 tree
.SelectItem(newItem
)
602 if not tree
.IsVisible(newItem
):
603 tree
.ScrollTo(newItem
)
606 if g
.testWin
and tree
.IsHighlatable(newItem
):
608 tree
.needUpdate
= True
609 tree
.pendingHighLight
= newItem
611 tree
.pendingHighLight
= None
613 self
.SetStatusText('Pasted')
616 def ItemsAreCompatible(self
, parent
, child
):
617 # Check compatibility
619 # Comments are always compatible
620 if child
.__class
__ == xxxComment
:
623 if child
.__class
__ in [xxxDialog
, xxxFrame
, xxxWizard
]:
625 if parent
.__class
__ != xxxMainNode
: error
= True
626 elif child
.__class
__ == xxxMenuBar
:
627 # Menubar can be put in frame or dialog
628 if parent
.__class
__ not in [xxxMainNode
, xxxFrame
, xxxDialog
]: error
= True
629 elif child
.__class
__ == xxxToolBar
:
630 # Toolbar can be top-level of child of panel or frame
631 if parent
.__class
__ not in [xxxMainNode
, xxxPanel
, xxxFrame
] and \
632 not parent
.isSizer
: error
= True
633 elif child
.__class
__ == xxxPanel
and parent
.__class
__ == xxxMainNode
:
635 elif child
.__class
__ == xxxSpacer
:
636 if not parent
.isSizer
: error
= True
637 elif child
.__class
__ == xxxSeparator
:
638 if not parent
.__class
__ in [xxxMenu
, xxxToolBar
]: error
= True
639 elif child
.__class
__ == xxxTool
:
640 if parent
.__class
__ != xxxToolBar
: error
= True
641 elif child
.__class
__ == xxxMenu
:
642 if not parent
.__class
__ in [xxxMainNode
, xxxMenuBar
, xxxMenu
]: error
= True
643 elif child
.__class
__ == xxxMenuItem
:
644 if not parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= True
645 elif child
.isSizer
and parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
]:
647 else: # normal controls can be almost anywhere
648 if parent
.__class
__ == xxxMainNode
or \
649 parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= True
651 if parent
.__class
__ == xxxMainNode
: parentClass
= 'root'
652 else: parentClass
= parent
.className
653 wx
.LogError('Incompatible parent/child: parent is %s, child is %s!' %
654 (parentClass
, child
.className
))
658 def OnMoveUp(self
, evt
):
659 selected
= tree
.selection
660 if not selected
: return
662 index
= tree
.ItemIndex(selected
)
663 if index
== 0: return # No previous sibling found
666 self
.lastOp
= 'MOVEUP'
667 status
= 'Moved before previous sibling'
672 parent
= tree
.GetItemParent(selected
)
673 elem
= tree
.RemoveLeaf(selected
)
674 nextItem
= tree
.GetFirstChild(parent
)[0]
675 for i
in range(index
- 1): nextItem
= tree
.GetNextSibling(nextItem
)
676 selected
= tree
.InsertNode(parent
, tree
.GetPyData(parent
).treeObject(), elem
, nextItem
)
677 newIndex
= tree
.ItemIndex(selected
)
678 tree
.SelectItem(selected
)
680 undoMan
.RegisterUndo(UndoMove(parent
, index
, parent
, newIndex
))
683 self
.SetStatusText(status
)
687 def OnMoveDown(self
, evt
):
688 selected
= tree
.selection
689 if not selected
: return
691 index
= tree
.ItemIndex(selected
)
692 next
= tree
.GetNextSibling(selected
)
696 self
.lastOp
= 'MOVEDOWN'
697 status
= 'Moved after next sibling'
702 parent
= tree
.GetItemParent(selected
)
703 elem
= tree
.RemoveLeaf(selected
)
704 nextItem
= tree
.GetFirstChild(parent
)[0]
705 for i
in range(index
+ 1): nextItem
= tree
.GetNextSibling(nextItem
)
706 selected
= tree
.InsertNode(parent
, tree
.GetPyData(parent
).treeObject(), elem
, nextItem
)
707 newIndex
= tree
.ItemIndex(selected
)
708 tree
.SelectItem(selected
)
710 undoMan
.RegisterUndo(UndoMove(parent
, index
, parent
, newIndex
))
713 self
.SetStatusText(status
)
717 def OnMoveLeft(self
, evt
):
718 selected
= tree
.selection
719 if not selected
: return
721 oldParent
= tree
.GetItemParent(selected
)
722 if not oldParent
: return
723 pparent
= tree
.GetItemParent(oldParent
)
724 if not pparent
: return
726 # Check compatibility
727 if not self
.ItemsAreCompatible(tree
.GetPyData(pparent
).treeObject(), tree
.GetPyData(selected
).treeObject()): return
730 self
.lastOp
= 'MOVELEFT'
731 status
= 'Made next sibling of parent'
733 oldIndex
= tree
.ItemIndex(selected
)
734 elem
= tree
.RemoveLeaf(selected
)
735 nextItem
= tree
.GetFirstChild(pparent
)[0]
736 parentIndex
= tree
.ItemIndex(oldParent
)
737 for i
in range(parentIndex
+ 1): nextItem
= tree
.GetNextSibling(nextItem
)
739 # Check parent and child relationships.
740 # If parent is sizer or notebook, child is of wrong class or
741 # parent is normal window, child is child container then detach child.
742 parent
= tree
.GetPyData(pparent
).treeObject()
743 xxx
= MakeXXXFromDOM(parent
, elem
)
744 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
745 if isChildContainer
and \
746 ((parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
747 (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
748 not (parent
.isSizer
or isinstance(parent
, xxxNotebook
))):
749 elem
.removeChild(xxx
.child
.node
) # detach child
750 elem
.unlink() # delete child container
751 elem
= xxx
.child
.node
# replace
752 # This may help garbage collection
753 xxx
.child
.parent
= None
754 isChildContainer
= False
755 # Parent is sizer or notebook, child is not child container
756 if parent
.isSizer
and not isChildContainer
and not isinstance(xxx
, xxxSpacer
):
757 # Create sizer item element
758 sizerItemElem
= MakeEmptyDOM('sizeritem')
759 sizerItemElem
.appendChild(elem
)
761 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
762 pageElem
= MakeEmptyDOM('notebookpage')
763 pageElem
.appendChild(elem
)
766 selected
= tree
.InsertNode(pparent
, tree
.GetPyData(pparent
).treeObject(), elem
, nextItem
)
767 newIndex
= tree
.ItemIndex(selected
)
768 tree
.SelectItem(selected
)
770 undoMan
.RegisterUndo(UndoMove(oldParent
, oldIndex
, pparent
, newIndex
))
773 self
.SetStatusText(status
)
775 def OnMoveRight(self
, evt
):
776 selected
= tree
.selection
777 if not selected
: return
779 oldParent
= tree
.GetItemParent(selected
)
780 if not oldParent
: return
782 newParent
= tree
.GetPrevSibling(selected
)
783 if not newParent
: return
785 parent
= tree
.GetPyData(newParent
).treeObject()
787 # Check compatibility
788 if not self
.ItemsAreCompatible(parent
, tree
.GetPyData(selected
).treeObject()): return
791 self
.lastOp
= 'MOVERIGHT'
792 status
= 'Made last child of previous sibling'
794 oldIndex
= tree
.ItemIndex(selected
)
795 elem
= tree
.RemoveLeaf(selected
)
797 # Check parent and child relationships.
798 # If parent is sizer or notebook, child is of wrong class or
799 # parent is normal window, child is child container then detach child.
800 xxx
= MakeXXXFromDOM(parent
, elem
)
801 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
802 if isChildContainer
and \
803 ((parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
804 (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
805 not (parent
.isSizer
or isinstance(parent
, xxxNotebook
))):
806 elem
.removeChild(xxx
.child
.node
) # detach child
807 elem
.unlink() # delete child container
808 elem
= xxx
.child
.node
# replace
809 # This may help garbage collection
810 xxx
.child
.parent
= None
811 isChildContainer
= False
812 # Parent is sizer or notebook, child is not child container
813 if parent
.isSizer
and not isChildContainer
and not isinstance(xxx
, xxxSpacer
):
814 # Create sizer item element
815 sizerItemElem
= MakeEmptyDOM('sizeritem')
816 sizerItemElem
.appendChild(elem
)
818 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
819 pageElem
= MakeEmptyDOM('notebookpage')
820 pageElem
.appendChild(elem
)
823 selected
= tree
.InsertNode(newParent
, tree
.GetPyData(newParent
).treeObject(), elem
, wx
.TreeItemId())
825 newIndex
= tree
.ItemIndex(selected
)
826 tree
.SelectItem(selected
)
828 undoMan
.RegisterUndo(UndoMove(oldParent
, oldIndex
, newParent
, newIndex
))
831 self
.SetStatusText(status
)
834 def OnCutDelete(self
, evt
):
835 selected
= tree
.selection
836 if not selected
: return # key pressed event
838 if evt
.GetId() == wx
.ID_CUT
:
840 status
= 'Removed to clipboard'
842 self
.lastOp
= 'DELETE'
846 # If deleting top-level item, delete testWin
847 if selected
== g
.testWin
.item
:
851 # Remove highlight, update testWin
852 if g
.testWin
.highLight
:
853 g
.testWin
.highLight
.Remove()
854 tree
.needUpdate
= True
857 index
= tree
.ItemFullIndex(selected
)
858 xxx
= tree
.GetPyData(selected
)
859 parent
= tree
.GetPyData(tree
.GetItemParent(selected
)).treeObject()
860 elem
= tree
.RemoveLeaf(selected
)
861 undoMan
.RegisterUndo(UndoCutDelete(index
, parent
, elem
))
862 if evt
.GetId() == wx
.ID_CUT
:
863 if wx
.TheClipboard
.Open():
865 data
= wx
.CustomDataObject('XRCED')
867 s
= elem
.toxml(encoding
=expat
.native_encoding
)
869 data
= wx
.CustomDataObject('XRCED_node')
871 data
.SetData(cPickle
.dumps(s
))
872 wx
.TheClipboard
.SetData(data
)
873 wx
.TheClipboard
.Close()
875 wx
.MessageBox("Unable to open the clipboard", "Error")
876 tree
.pendingHighLight
= None
878 tree
.selection
= None
883 self
.SetStatusText(status
)
885 def OnSubclass(self
, evt
):
886 selected
= tree
.selection
887 xxx
= tree
.GetPyData(selected
).treeObject()
889 subclass
= xxx
.subclass
890 dlg
= wx
.TextEntryDialog(self
, 'Subclass:', defaultValue
=subclass
)
891 if dlg
.ShowModal() == wx
.ID_OK
:
892 subclass
= dlg
.GetValue()
894 elem
.setAttribute('subclass', subclass
)
895 elif elem
.hasAttribute('subclass'):
896 elem
.removeAttribute('subclass')
898 xxx
.subclass
= elem
.getAttribute('subclass')
899 tree
.SetItemText(selected
, xxx
.treeName())
900 panel
.pages
[0].box
.SetLabel(xxx
.panelName())
903 def OnEmbedPanel(self
, evt
):
904 conf
.embedPanel
= evt
.IsChecked()
906 # Remember last dimentions
907 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
908 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
909 size
= self
.GetSize()
910 pos
= self
.GetPosition()
911 sizePanel
= panel
.GetSize()
912 panel
.Reparent(self
.splitter
)
913 self
.miniFrame
.GetSizer().Remove(panel
)
915 self
.SetDimensions(pos
.x
, pos
.y
, size
.width
+ sizePanel
.width
, size
.height
)
916 self
.splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
917 self
.miniFrame
.Show(False)
919 conf
.sashPos
= self
.splitter
.GetSashPosition()
920 pos
= self
.GetPosition()
921 size
= self
.GetSize()
922 sizePanel
= panel
.GetSize()
923 self
.splitter
.Unsplit(panel
)
924 sizer
= self
.miniFrame
.GetSizer()
925 panel
.Reparent(self
.miniFrame
)
927 sizer
.Add(panel
, 1, wx
.EXPAND
)
928 self
.miniFrame
.Show(True)
929 self
.miniFrame
.SetDimensions(conf
.panelX
, conf
.panelY
,
930 conf
.panelWidth
, conf
.panelHeight
)
931 self
.miniFrame
.Layout()
933 self
.SetDimensions(pos
.x
, pos
.y
,
934 max(size
.width
- sizePanel
.width
, self
.minWidth
), size
.height
)
936 def OnShowTools(self
, evt
):
937 conf
.showTools
= evt
.IsChecked()
938 g
.tools
.Show(conf
.showTools
)
940 self
.toolsSizer
.Prepend(g
.tools
, 0, wx
.EXPAND
)
942 self
.toolsSizer
.Remove(g
.tools
)
943 self
.toolsSizer
.Layout()
945 def OnTest(self
, evt
):
946 if not tree
.selection
: return # key pressed event
947 tree
.ShowTestWindow(tree
.selection
)
949 def OnTestHide(self
, evt
):
950 tree
.CloseTestWindow()
952 # Find object by relative position
953 def FindObject(self
, item
, obj
):
954 # We simply perform depth-first traversal, sinse it's too much
955 # hassle to deal with all sizer/window combinations
956 w
= tree
.FindNodeObject(item
)
957 if w
== obj
or isinstance(w
, wx
.GBSizerItem
) and w
.GetWindow() == obj
:
959 if tree
.ItemHasChildren(item
):
960 child
= tree
.GetFirstChild(item
)[0]
962 found
= self
.FindObject(child
, obj
)
963 if found
: return found
964 child
= tree
.GetNextSibling(child
)
967 def OnTestWinLeftDown(self
, evt
):
968 pos
= evt
.GetPosition()
969 self
.SetHandler(g
.testWin
)
970 g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
)
971 item
= self
.FindObject(g
.testWin
.item
, evt
.GetEventObject())
973 tree
.EnsureVisible(item
)
974 tree
.SelectItem(item
)
975 self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, False)
977 self
.SetStatusText('Selected %s' % tree
.GetItemText(item
))
979 self
.SetStatusText('Locate failed!')
981 def SetHandler(self
, w
, h
=None):
984 w
.SetCursor(wx
.CROSS_CURSOR
)
987 w
.SetCursor(wx
.NullCursor
)
988 for ch
in w
.GetChildren():
989 self
.SetHandler(ch
, h
)
991 def OnLocate(self
, evt
):
993 if evt
.GetId() == self
.ID_LOCATE
or \
994 evt
.GetId() == self
.ID_TOOL_LOCATE
and evt
.IsChecked():
995 self
.SetHandler(g
.testWin
, g
.testWin
)
996 g
.testWin
.Connect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
, self
.OnTestWinLeftDown
)
997 if evt
.GetId() == self
.ID_LOCATE
:
998 self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, True)
999 elif evt
.GetId() == self
.ID_TOOL_LOCATE
and not evt
.IsChecked():
1000 self
.SetHandler(g
.testWin
, None)
1001 g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
)
1002 self
.SetStatusText('Click somewhere in your test window now')
1004 def OnRefresh(self
, evt
):
1005 # If modified, apply first
1006 selection
= tree
.selection
1008 xxx
= tree
.GetPyData(selection
)
1009 if xxx
and panel
.IsModified():
1010 tree
.Apply(xxx
, selection
)
1013 tree
.CreateTestWin(g
.testWin
.item
)
1014 panel
.modified
= False
1015 tree
.needUpdate
= False
1017 def OnAutoRefresh(self
, evt
):
1018 conf
.autoRefresh
= evt
.IsChecked()
1019 self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1020 self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1022 def OnAbout(self
, evt
):
1026 (c) Roman Rolinsky <rollrom@users.sourceforge.net>
1027 Homepage: http://xrced.sourceforge.net\
1029 dlg
= wx
.MessageDialog(self
, str, 'About XRCed', wx
.OK | wx
.CENTRE
)
1033 def OnReadme(self
, evt
):
1034 text
= open(os
.path
.join(basePath
, 'README.txt'), 'r').read()
1035 dlg
= ScrolledMessageDialog(self
, text
, "XRCed README")
1039 # Simple emulation of python command line
1040 def OnDebugCMD(self
, evt
):
1043 exec raw_input('C:\> ')
1048 (etype
, value
, tb
) =sys
.exc_info()
1049 tblist
=traceback
.extract_tb(tb
)[1:]
1050 msg
=' '.join(traceback
.format_exception_only(etype
, value
)
1051 +traceback
.format_list(tblist
))
1054 def OnCreate(self
, evt
):
1055 selected
= tree
.selection
1056 if tree
.ctrl
: appendChild
= False
1057 else: appendChild
= not tree
.NeedInsert(selected
)
1058 xxx
= tree
.GetPyData(selected
)
1062 # If has previous item, insert after it, else append to parent
1064 parentLeaf
= tree
.GetItemParent(selected
)
1066 # If has next item, insert, else append to parent
1067 nextItem
= tree
.GetNextSibling(selected
)
1068 parentLeaf
= tree
.GetItemParent(selected
)
1069 # Expanded container (must have children)
1070 elif tree
.shift
and tree
.IsExpanded(selected
) \
1071 and tree
.GetChildrenCount(selected
, False):
1072 nextItem
= tree
.GetFirstChild(selected
)[0]
1073 parentLeaf
= selected
1075 nextItem
= wx
.TreeItemId()
1076 parentLeaf
= selected
1077 parent
= tree
.GetPyData(parentLeaf
)
1078 if parent
.hasChild
: parent
= parent
.child
1080 # Create object_ref?
1081 if evt
.GetId() == ID_NEW
.REF
:
1082 ref
= wx
.GetTextFromUser('Create reference to:', 'Create reference')
1084 xxx
= MakeEmptyRefXXX(parent
, ref
)
1085 elif evt
.GetId() == ID_NEW
.COMMENT
:
1086 xxx
= MakeEmptyCommentXXX(parent
)
1088 # Create empty element
1089 className
= pullDownMenu
.createMap
[evt
.GetId()]
1090 xxx
= MakeEmptyXXX(parent
, className
)
1092 # Insert new node, register undo
1093 if xxx
.isElement
: # true object
1094 # Set default name for top-level windows
1095 if parent
.__class
__ == xxxMainNode
:
1096 cl
= xxx
.treeObject().__class
__
1097 frame
.maxIDs
[cl
] += 1
1098 xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
]))
1099 # And for some other standard controls
1100 elif parent
.__class
__ == xxxStdDialogButtonSizer
:
1101 xxx
.setTreeName(pullDownMenu
.stdButtonIDs
[evt
.GetId()][0])
1102 # We can even set label
1103 obj
= xxx
.treeObject()
1104 elem
= g
.tree
.dom
.createElement('label')
1105 elem
.appendChild(g
.tree
.dom
.createTextNode(pullDownMenu
.stdButtonIDs
[evt
.GetId()][1]))
1106 obj
.params
['label'] = xxxParam(elem
)
1107 xxx
.treeObject().node
.appendChild(elem
)
1109 newItem
= tree
.InsertNode(parentLeaf
, parent
, xxx
.node
, nextItem
)
1110 else: # comment node
1111 newItem
= tree
.InsertNode(parentLeaf
, parent
, xxx
.node
, nextItem
)
1112 undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
))
1113 tree
.EnsureVisible(newItem
)
1114 tree
.SelectItem(newItem
)
1115 if not tree
.IsVisible(newItem
):
1116 tree
.ScrollTo(newItem
)
1119 if xxx
.isElement
and g
.testWin
and tree
.IsHighlatable(newItem
):
1120 if conf
.autoRefresh
:
1121 tree
.needUpdate
= True
1122 tree
.pendingHighLight
= newItem
1124 tree
.pendingHighLight
= None
1126 if not xxx
.isElement
:
1127 tree
.EditLabel(newItem
)
1130 # Replace one object with another
1131 def OnReplace(self
, evt
):
1132 selected
= tree
.selection
1133 xxx
= tree
.GetPyData(selected
).treeObject()
1135 parent
= elem
.parentNode
1136 undoMan
.RegisterUndo(UndoReplace(selected
))
1138 className
= pullDownMenu
.createMap
[evt
.GetId() - 1000]
1140 # Create temporary empty node (with default values)
1141 dummy
= MakeEmptyDOM(className
)
1142 if className
== 'spacer' and xxx
.className
!= 'spacer':
1144 elif xxx
.className
== 'spacer' and className
!= 'spacer':
1145 klass
= xxxSizerItem
1147 klass
= xxxDict
[className
]
1148 # Remove non-compatible children
1149 if tree
.ItemHasChildren(selected
) and not klass
.hasChildren
:
1150 tree
.DeleteChildren(selected
)
1151 nodes
= elem
.childNodes
[:]
1154 if node
.nodeType
!= minidom
.Node
.ELEMENT_NODE
: continue
1158 if not klass
.hasChildren
: remove
= True
1159 elif tag
not in klass
.allParams
and \
1160 (not klass
.hasStyle
or tag
not in klass
.styles
):
1165 elem
.removeChild(node
)
1168 # Remove sizeritem child if spacer
1169 if className
== 'spacer' and xxx
.className
!= 'spacer':
1170 sizeritem
= elem
.parentNode
1171 assert sizeritem
.getAttribute('class') == 'sizeritem'
1172 sizeritem
.removeChild(elem
)
1175 tree
.GetPyData(selected
).hasChild
= False
1176 elif xxx
.className
== 'spacer' and className
!= 'spacer':
1177 # Create sizeritem element
1178 assert xxx
.parent
.isSizer
1179 elem
.setAttribute('class', 'sizeritem')
1180 node
= MakeEmptyDOM(className
)
1181 elem
.appendChild(node
)
1182 # Replace to point to new object
1183 xxx
= xxxSizerItem(xxx
.parent
, elem
)
1185 tree
.SetPyData(selected
, xxx
)
1188 # Copy parameters present in dummy but not in elem
1189 for node
in dummy
.childNodes
:
1190 if node
.tagName
not in tags
: elem
.appendChild(node
.cloneNode(True))
1194 elem
.setAttribute('class', className
)
1195 if elem
.hasAttribute('subclass'):
1196 elem
.removeAttribute('subclass') # clear subclassing
1197 # Re-create xxx element
1198 xxx
= MakeXXXFromDOM(xxx
.parent
, elem
)
1199 # Remove incompatible style flags
1200 if 'style' in xxx
.params
:
1201 styles
= map(string
.strip
, xxx
.params
['style'].value().split('|'))
1202 newStyles
= [s
for s
in styles
if s
in klass
.winStyles
or s
in genericStyles
]
1203 if newStyles
!= styles
:
1205 value
= reduce(lambda a
,b
: a
+'|'+b
, newStyles
)
1208 xxx
.params
['style'].update(value
)
1210 # Update parent in child objects
1211 if tree
.ItemHasChildren(selected
):
1212 i
, cookie
= tree
.GetFirstChild(selected
)
1214 x
= tree
.GetPyData(i
)
1216 if x
.hasChild
: x
.child
.parent
= xxx
1217 i
, cookie
= tree
.GetNextChild(selected
, cookie
)
1220 if tree
.GetPyData(selected
).hasChild
: # child container
1221 container
= tree
.GetPyData(selected
)
1222 container
.resetChild(xxx
)
1225 tree
.SetPyData(selected
, xxx
)
1226 tree
.SetItemText(selected
, xxx
.treeName())
1227 tree
.SetItemImage(selected
, xxx
.treeImage())
1229 # Set default name for top-level windows
1230 if parent
.__class
__ == xxxMainNode
:
1231 cl
= xxx
.treeObject().__class
__
1232 frame
.maxIDs
[cl
] += 1
1233 xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
]))
1236 g
.panel
.SetData(xxx
)
1240 #undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
1242 if g
.testWin
and tree
.IsHighlatable(selected
):
1243 if conf
.autoRefresh
:
1244 tree
.needUpdate
= True
1245 tree
.pendingHighLight
= selected
1247 tree
.pendingHighLight
= None
1251 # Expand/collapse subtree
1252 def OnExpand(self
, evt
):
1253 if tree
.selection
: tree
.ExpandAll(tree
.selection
)
1254 else: tree
.ExpandAll(tree
.root
)
1255 def OnCollapse(self
, evt
):
1256 if tree
.selection
: tree
.CollapseAll(tree
.selection
)
1257 else: tree
.CollapseAll(tree
.root
)
1259 def OnPullDownHighlight(self
, evt
):
1260 menuId
= evt
.GetMenuId()
1262 menu
= evt
.GetEventObject()
1263 help = menu
.GetHelpString(menuId
)
1264 self
.SetStatusText(help)
1266 self
.SetStatusText('')
1268 def OnUpdateUI(self
, evt
):
1269 if evt
.GetId() in [wx
.ID_CUT
, wx
.ID_COPY
, self
.ID_DELETE
]:
1270 evt
.Enable(tree
.selection
is not None and tree
.selection
!= tree
.root
)
1271 elif evt
.GetId() == wx
.ID_SAVE
:
1272 evt
.Enable(self
.modified
)
1273 elif evt
.GetId() in [wx
.ID_PASTE
, self
.ID_TOOL_PASTE
]:
1274 evt
.Enable(tree
.selection
is not None)
1275 elif evt
.GetId() == self
.ID_TEST
:
1276 evt
.Enable(tree
.selection
is not None and tree
.selection
!= tree
.root
)
1277 elif evt
.GetId() in [self
.ID_LOCATE
, self
.ID_TOOL_LOCATE
]:
1278 evt
.Enable(g
.testWin
is not None)
1279 elif evt
.GetId() == wx
.ID_UNDO
: evt
.Enable(undoMan
.CanUndo())
1280 elif evt
.GetId() == wx
.ID_REDO
: evt
.Enable(undoMan
.CanRedo())
1282 def OnIdle(self
, evt
):
1283 if self
.inIdle
: return # Recursive call protection
1287 if conf
.autoRefresh
:
1289 self
.SetStatusText('Refreshing test window...')
1291 tree
.CreateTestWin(g
.testWin
.item
)
1292 self
.SetStatusText('')
1293 tree
.needUpdate
= False
1294 elif tree
.pendingHighLight
:
1296 tree
.HighLight(tree
.pendingHighLight
)
1298 # Remove highlight if any problem
1299 if g
.testWin
.highLight
:
1300 g
.testWin
.highLight
.Remove()
1301 tree
.pendingHighLight
= None
1308 # We don't let close panel window
1309 def OnCloseMiniFrame(self
, evt
):
1312 def OnIconize(self
, evt
):
1314 conf
.x
, conf
.y
= self
.GetPosition()
1315 conf
.width
, conf
.height
= self
.GetSize()
1317 conf
.sashPos
= self
.splitter
.GetSashPosition()
1319 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
1320 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
1321 self
.miniFrame
.Iconize()
1323 if not conf
.embedPanel
:
1324 self
.miniFrame
.Iconize(False)
1327 def OnCloseWindow(self
, evt
):
1328 if not self
.AskSave(): return
1329 if g
.testWin
: g
.testWin
.Destroy()
1330 if not panel
.GetPageCount() == 2:
1331 panel
.page2
.Destroy()
1333 # If we don't do this, page does not get destroyed (a bug?)
1335 if not self
.IsIconized():
1336 conf
.x
, conf
.y
= self
.GetPosition()
1337 conf
.width
, conf
.height
= self
.GetSize()
1339 conf
.sashPos
= self
.splitter
.GetSashPosition()
1341 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
1342 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
1346 def CreateLocalConf(self
, path
):
1347 name
= os
.path
.splitext(path
)[0]
1349 return wx
.FileConfig(localFilename
=name
)
1354 conf
.localconf
= None
1356 self
.SetModified(False)
1362 # Numbers for new controls
1364 for cl
in [xxxPanel
, xxxDialog
, xxxFrame
,
1365 xxxMenuBar
, xxxMenu
, xxxToolBar
,
1366 xxxWizard
, xxxBitmap
, xxxIcon
]:
1371 def SetModified(self
, state
=True):
1372 self
.modified
= state
1373 name
= os
.path
.basename(self
.dataFile
)
1374 if not name
: name
= defaultName
1376 self
.SetTitle(progname
+ ': ' + name
+ ' *')
1378 self
.SetTitle(progname
+ ': ' + name
)
1380 def Open(self
, path
):
1381 if not os
.path
.exists(path
):
1382 wx
.LogError('File does not exists: %s' % path
)
1384 # Try to read the file
1388 dom
= minidom
.parse(f
)
1390 # Set encoding global variable and default encoding
1392 g
.currentEncoding
= dom
.encoding
1393 wx
.SetDefaultPyEncoding(g
.currentEncoding
.encode())
1395 g
.currentEncoding
= ''
1397 self
.dataFile
= path
= os
.path
.abspath(path
)
1398 dir = os
.path
.dirname(path
)
1399 if dir: os
.chdir(dir)
1401 self
.SetTitle(progname
+ ': ' + os
.path
.basename(path
))
1402 conf
.localconf
= self
.CreateLocalConf(self
.dataFile
)
1404 # Nice exception printing
1405 inf
= sys
.exc_info()
1406 wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
1407 wx
.LogError('Error reading file: %s' % path
)
1412 def Indent(self
, node
, indent
= 0):
1413 if node
.nodeType
== minidom
.Node
.COMMENT_NODE
:
1414 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
1415 node
.parentNode
.insertBefore(text
, node
)
1416 return # no children
1417 # Copy child list because it will change soon
1418 children
= node
.childNodes
[:]
1419 # Main node doesn't need to be indented
1421 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
1422 node
.parentNode
.insertBefore(text
, node
)
1424 # Append newline after last child, except for text nodes
1425 if children
[-1].nodeType
== minidom
.Node
.ELEMENT_NODE
:
1426 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
1427 node
.appendChild(text
)
1428 # Indent children which are elements
1430 if n
.nodeType
== minidom
.Node
.ELEMENT_NODE
or \
1431 n
.nodeType
== minidom
.Node
.COMMENT_NODE
:
1432 self
.Indent(n
, indent
+ 2)
1434 def Save(self
, path
):
1438 if tree
.selection
and panel
.IsModified():
1439 self
.OnRefresh(wx
.CommandEvent())
1440 if g
.currentEncoding
:
1441 f
= codecs
.open(path
, 'wt', g
.currentEncoding
)
1443 f
= codecs
.open(path
, 'wt')
1444 # Make temporary copy for formatting it
1445 # !!! We can't clone dom node, it works only once
1446 #self.domCopy = tree.dom.cloneNode(True)
1447 self
.domCopy
= MyDocument()
1448 mainNode
= self
.domCopy
.appendChild(tree
.mainNode
.cloneNode(True))
1449 # Remove first child (test element)
1450 testElem
= mainNode
.firstChild
1451 mainNode
.removeChild(testElem
)
1453 self
.Indent(mainNode
)
1454 self
.domCopy
.writexml(f
, encoding
= g
.currentEncoding
)
1456 self
.domCopy
.unlink()
1458 self
.SetModified(False)
1459 panel
.SetModified(False)
1460 conf
.localconf
.Flush()
1462 inf
= sys
.exc_info()
1463 wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
1464 wx
.LogError('Error writing file: %s' % path
)
1468 if not (self
.modified
or panel
.IsModified()): return True
1469 flags
= wx
.ICON_EXCLAMATION | wx
.YES_NO | wx
.CANCEL | wx
.CENTRE
1470 dlg
= wx
.MessageDialog( self
, 'File is modified. Save before exit?',
1471 'Save before too late?', flags
)
1472 say
= dlg
.ShowModal()
1475 if say
== wx
.ID_YES
:
1476 self
.OnSaveOrSaveAs(wx
.CommandEvent(wx
.ID_SAVE
))
1477 # If save was successful, modified flag is unset
1478 if not self
.modified
: return True
1479 elif say
== wx
.ID_NO
:
1480 self
.SetModified(False)
1481 panel
.SetModified(False)
1488 ################################################################################
1490 class PythonOptions(wx
.Dialog
):
1492 def __init__(self
, parent
, cfg
, dataFile
):
1493 pre
= wx
.PreDialog()
1494 g
.frame
.res
.LoadOnDialog(pre
, parent
, "PYTHON_OPTIONS")
1495 self
.PostCreate(pre
)
1498 self
.dataFile
= dataFile
1500 self
.AutoGenerateCB
= xrc
.XRCCTRL(self
, "AutoGenerateCB")
1501 self
.EmbedCB
= xrc
.XRCCTRL(self
, "EmbedCB")
1502 self
.GettextCB
= xrc
.XRCCTRL(self
, "GettextCB")
1503 self
.MakeXRSFileCB
= xrc
.XRCCTRL(self
, "MakeXRSFileCB")
1504 self
.FileNameTC
= xrc
.XRCCTRL(self
, "FileNameTC")
1505 self
.BrowseBtn
= xrc
.XRCCTRL(self
, "BrowseBtn")
1506 self
.GenerateBtn
= xrc
.XRCCTRL(self
, "GenerateBtn")
1507 self
.SaveOptsBtn
= xrc
.XRCCTRL(self
, "SaveOptsBtn")
1509 self
.Bind(wx
.EVT_BUTTON
, self
.OnBrowse
, self
.BrowseBtn
)
1510 self
.Bind(wx
.EVT_BUTTON
, self
.OnGenerate
, self
.GenerateBtn
)
1511 self
.Bind(wx
.EVT_BUTTON
, self
.OnSaveOpts
, self
.SaveOptsBtn
)
1513 if self
.cfg
.Read("filename", "") != "":
1514 self
.FileNameTC
.SetValue(self
.cfg
.Read("filename"))
1516 name
= os
.path
.splitext(os
.path
.split(dataFile
)[1])[0]
1518 self
.FileNameTC
.SetValue(name
)
1519 self
.AutoGenerateCB
.SetValue(self
.cfg
.ReadBool("autogenerate", False))
1520 self
.EmbedCB
.SetValue(self
.cfg
.ReadBool("embedResource", False))
1521 self
.MakeXRSFileCB
.SetValue(self
.cfg
.ReadBool("makeXRS", False))
1522 self
.GettextCB
.SetValue(self
.cfg
.ReadBool("genGettext", False))
1525 def OnBrowse(self
, evt
):
1526 path
= self
.FileNameTC
.GetValue()
1527 dirname
= os
.path
.abspath(os
.path
.dirname(path
))
1528 name
= os
.path
.split(path
)[1]
1529 dlg
= wx
.FileDialog(self
, 'Save As', dirname
, name
, '*.py',
1530 wx
.SAVE | wx
.OVERWRITE_PROMPT
)
1531 if dlg
.ShowModal() == wx
.ID_OK
:
1532 path
= dlg
.GetPath()
1533 self
.FileNameTC
.SetValue(path
)
1537 def OnGenerate(self
, evt
):
1538 pypath
= self
.FileNameTC
.GetValue()
1539 embed
= self
.EmbedCB
.GetValue()
1540 genGettext
= self
.GettextCB
.GetValue()
1541 frame
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
)
1545 def OnSaveOpts(self
, evt
=None):
1546 self
.cfg
.Write("filename", self
.FileNameTC
.GetValue())
1547 self
.cfg
.WriteBool("autogenerate", self
.AutoGenerateCB
.GetValue())
1548 self
.cfg
.WriteBool("embedResource", self
.EmbedCB
.GetValue())
1549 self
.cfg
.WriteBool("makeXRS", self
.MakeXRSFileCB
.GetValue())
1550 self
.cfg
.WriteBool("genGettext", self
.GettextCB
.GetValue())
1552 self
.EndModal(wx
.ID_OK
)
1555 ################################################################################
1558 print >> sys
.stderr
, 'usage: xrced [-dhiv] [file]'
1563 if wx
.VERSION
[:3] < MinWxVersion
:
1565 This version of XRCed may not work correctly on your version of wxWidgets. \
1566 Please upgrade wxWidgets to %d.%d.%d or higher.''' % MinWxVersion
)
1568 # Process comand-line
1571 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'dhiv')
1579 print 'XRCed version', version
1582 except getopt
.GetoptError
:
1583 if wx
.Platform
!= '__WXMAC__': # macs have some extra parameters
1584 print >> sys
.stderr
, 'Unknown option'
1588 self
.SetAppName('xrced')
1591 conf
= g
.conf
= wx
.Config(style
= wx
.CONFIG_USE_LOCAL_FILE
)
1592 conf
.localconf
= None
1593 conf
.autoRefresh
= conf
.ReadInt('autorefresh', True)
1594 pos
= conf
.ReadInt('x', -1), conf
.ReadInt('y', -1)
1595 size
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600)
1596 conf
.embedPanel
= conf
.ReadInt('embedPanel', True)
1597 conf
.showTools
= conf
.ReadInt('showTools', True)
1598 conf
.sashPos
= conf
.ReadInt('sashPos', 200)
1599 # read recently used files
1600 recentfiles
=conf
.Read('recentFiles','')
1603 for fil
in recentfiles
.split('|'):
1604 conf
.recentfiles
[wx
.NewId()]=fil
1605 if not conf
.embedPanel
:
1606 conf
.panelX
= conf
.ReadInt('panelX', -1)
1607 conf
.panelY
= conf
.ReadInt('panelY', -1)
1609 conf
.panelX
= conf
.panelY
= -1
1610 conf
.panelWidth
= conf
.ReadInt('panelWidth', 200)
1611 conf
.panelHeight
= conf
.ReadInt('panelHeight', 200)
1612 conf
.panic
= not conf
.HasEntry('nopanic')
1614 wx
.FileSystem
.AddHandler(wx
.MemoryFSHandler())
1616 frame
= Frame(pos
, size
)
1619 # Load file after showing
1622 frame
.open = frame
.Open(args
[0])
1630 wc
.WriteInt('autorefresh', conf
.autoRefresh
)
1631 wc
.WriteInt('x', conf
.x
)
1632 wc
.WriteInt('y', conf
.y
)
1633 wc
.WriteInt('width', conf
.width
)
1634 wc
.WriteInt('height', conf
.height
)
1635 wc
.WriteInt('embedPanel', conf
.embedPanel
)
1636 wc
.WriteInt('showTools', conf
.showTools
)
1637 if not conf
.embedPanel
:
1638 wc
.WriteInt('panelX', conf
.panelX
)
1639 wc
.WriteInt('panelY', conf
.panelY
)
1640 wc
.WriteInt('sashPos', conf
.sashPos
)
1641 wc
.WriteInt('panelWidth', conf
.panelWidth
)
1642 wc
.WriteInt('panelHeight', conf
.panelHeight
)
1643 wc
.WriteInt('nopanic', True)
1644 wc
.Write('recentFiles', '|'.join(conf
.recentfiles
.values()[-5:]))
1648 app
= App(0, useBestVisual
=False)
1649 #app.SetAssertMode(wx.PYAPP_ASSERT_LOG)
1655 if __name__
== '__main__':