]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/tools/XRCed/xrced.py
2 # Purpose: XRC editor, main module
3 # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
9 xrced -- Simple resource editor for XRC format used by wxWidgets/wxPython
14 xrced [ -h ] [ -v ] [ XRC-file ]
18 -h output short usage info and exit
20 -v output version info and exit
24 import os
, sys
, getopt
, re
, traceback
, tempfile
, shutil
, cPickle
25 from xml
.parsers
import expat
28 from tree
import * # imports xxx which imports params
31 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\tCtrl-H', '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 # !!! frame styles are broken
315 # Miniframe for not embedded mode
316 miniFrame
= wx
.Frame(self
, -1, 'Properties & Style',
317 (conf
.panelX
, conf
.panelY
),
318 (conf
.panelWidth
, conf
.panelHeight
))
319 self
.miniFrame
= miniFrame
320 sizer2
= wx
.BoxSizer()
321 miniFrame
.SetAutoLayout(True)
322 miniFrame
.SetSizer(sizer2
)
323 wx
.EVT_CLOSE(self
.miniFrame
, self
.OnCloseMiniFrame
)
324 # Create panel for parameters
327 panel
= Panel(splitter
)
328 # Set plitter windows
329 splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
331 panel
= Panel(miniFrame
)
332 sizer2
.Add(panel
, 1, wx
.EXPAND
)
334 splitter
.Initialize(tree
)
335 sizer1
.Add(splitter
, 1, wx
.EXPAND
)
336 sizer
.Add(sizer1
, 1, wx
.EXPAND
)
337 self
.SetAutoLayout(True)
344 wx
.EVT_IDLE(self
, self
.OnIdle
)
345 wx
.EVT_CLOSE(self
, self
.OnCloseWindow
)
346 wx
.EVT_KEY_DOWN(self
, tools
.OnKeyDown
)
347 wx
.EVT_KEY_UP(self
, tools
.OnKeyUp
)
348 wx
.EVT_ICONIZE(self
, self
.OnIconize
)
350 def AppendRecent(self
, menu
):
351 # add recently used files to the menu
352 for id,name
in conf
.recentfiles
.iteritems():
354 wx
.EVT_MENU(self
,id,self
.OnRecentFile
)
357 def OnRecentFile(self
,evt
):
358 # open recently used file
359 if not self
.AskSave(): return
362 path
=conf
.recentfiles
[evt
.GetId()]
364 self
.SetStatusText('Data loaded')
366 self
.SetStatusText('Failed')
368 self
.SetStatusText('No such file')
371 def OnNew(self
, evt
):
372 if not self
.AskSave(): return
375 def OnOpen(self
, evt
):
376 if not self
.AskSave(): return
377 dlg
= wx
.FileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
),
378 '', '*.xrc', wx
.OPEN | wx
.CHANGE_DIR
)
379 if dlg
.ShowModal() == wx
.ID_OK
:
381 self
.SetStatusText('Loading...')
385 self
.SetStatusText('Data loaded')
387 self
.SetStatusText('Failed')
388 self
.SaveRecent(path
)
393 def OnSaveOrSaveAs(self
, evt
):
394 if evt
.GetId() == wx
.ID_SAVEAS
or not self
.dataFile
:
395 if self
.dataFile
: name
= ''
396 else: name
= defaultName
397 dirname
= os
.path
.abspath(os
.path
.dirname(self
.dataFile
))
398 dlg
= wx
.FileDialog(self
, 'Save As', dirname
, name
, '*.xrc',
399 wx
.SAVE | wx
.OVERWRITE_PROMPT | wx
.CHANGE_DIR
)
400 if dlg
.ShowModal() == wx
.ID_OK
:
402 if isinstance(path
, unicode):
403 path
= path
.encode(sys
.getfilesystemencoding())
410 # if we already have a localconf then it needs to be
411 # copied to a new config with the new name
413 nc
= self
.CreateLocalConf(path
)
414 flag
, key
, idx
= lc
.GetFirstEntry()
416 nc
.Write(key
, lc
.Read(key
))
417 flag
, key
, idx
= lc
.GetNextEntry(idx
)
420 # otherwise create a new one
421 conf
.localconf
= self
.CreateLocalConf(path
)
424 self
.SetStatusText('Saving...')
428 tmpFile
,tmpName
= tempfile
.mkstemp(prefix
='xrced-')
430 self
.Save(tmpName
) # save temporary file first
431 shutil
.move(tmpName
, path
)
433 if conf
.localconf
.ReadBool("autogenerate", False):
434 pypath
= conf
.localconf
.Read("filename")
435 embed
= conf
.localconf
.ReadBool("embedResource", False)
436 genGettext
= conf
.localconf
.ReadBool("genGettext", False)
437 self
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
)
439 self
.SetStatusText('Data saved')
440 self
.SaveRecent(path
)
442 self
.SetStatusText('Failed')
446 def SaveRecent(self
,path
):
447 # append to recently used files
448 if path
not in conf
.recentfiles
.values():
450 self
.recentMenu
.Append(newid
, path
)
451 wx
.EVT_MENU(self
, newid
, self
.OnRecentFile
)
452 conf
.recentfiles
[newid
] = path
454 def GeneratePython(self
, dataFile
, pypath
, embed
, genGettext
):
456 import wx
.tools
.pywxrc
457 rescomp
= wx
.tools
.pywxrc
.XmlResourceCompiler()
458 rescomp
.MakePythonModule([dataFile
], pypath
, embed
, genGettext
)
461 wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
462 wx
.LogError('Error generating python code : %s' % pypath
)
466 def OnGeneratePython(self
, evt
):
467 if self
.modified
or not conf
.localconf
:
468 wx
.MessageBox("Save the XRC file first!", "Error")
471 dlg
= PythonOptions(self
, conf
.localconf
, self
.dataFile
)
476 def OnExit(self
, evt
):
479 def OnUndo(self
, evt
):
480 # Extra check to not mess with idle updating
481 if undoMan
.CanUndo():
484 def OnRedo(self
, evt
):
485 if undoMan
.CanRedo():
488 def OnCopy(self
, evt
):
489 selected
= tree
.selection
490 if not selected
: return # key pressed event
491 xxx
= tree
.GetPyData(selected
)
492 if wx
.TheClipboard
.Open():
493 data
= wx
.CustomDataObject('XRCED')
494 # Set encoding in header
496 s
= xxx
.element
.toxml(encoding
=expat
.native_encoding
)
497 data
.SetData(cPickle
.dumps(s
))
498 wx
.TheClipboard
.SetData(data
)
499 wx
.TheClipboard
.Close()
500 self
.SetStatusText('Copied')
502 wx
.MessageBox("Unable to open the clipboard", "Error")
504 def OnPaste(self
, evt
):
505 selected
= tree
.selection
506 if not selected
: return # key pressed event
507 # For pasting with Ctrl pressed
509 if evt
.GetId() == pullDownMenu
.ID_PASTE_SIBLING
: appendChild
= False
510 elif evt
.GetId() == self
.ID_TOOL_PASTE
:
511 if g
.tree
.ctrl
: appendChild
= False
512 else: appendChild
= not tree
.NeedInsert(selected
)
513 else: appendChild
= not tree
.NeedInsert(selected
)
514 xxx
= tree
.GetPyData(selected
)
516 # If has next item, insert, else append to parent
517 nextItem
= tree
.GetNextSibling(selected
)
518 parentLeaf
= tree
.GetItemParent(selected
)
519 # Expanded container (must have children)
520 elif tree
.IsExpanded(selected
) and tree
.GetChildrenCount(selected
, False):
521 # Insert as first child
522 nextItem
= tree
.GetFirstChild(selected
)[0]
523 parentLeaf
= selected
525 # No children or unexpanded item - appendChild stays True
526 nextItem
= wx
.TreeItemId() # no next item
527 parentLeaf
= selected
528 parent
= tree
.GetPyData(parentLeaf
).treeObject()
530 # Create a copy of clipboard pickled element
532 if wx
.TheClipboard
.Open():
533 data
= wx
.CustomDataObject('XRCED')
534 if wx
.TheClipboard
.IsSupported(data
.GetFormat()):
535 success
= wx
.TheClipboard
.GetData(data
)
536 wx
.TheClipboard
.Close()
540 "There is no data in the clipboard in the required format",
544 xml
= cPickle
.loads(data
.GetData()) # xml representation of element
545 elem
= minidom
.parseString(xml
).childNodes
[0]
547 # Tempopary xxx object to test things
548 xxx
= MakeXXXFromDOM(parent
, elem
)
550 # Check compatibility
551 if not self
.ItemsAreCompatible(parent
, xxx
.treeObject()): return
553 # Check parent and child relationships.
554 # If parent is sizer or notebook, child is of wrong class or
555 # parent is normal window, child is child container then detach child.
556 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
557 parentIsBook
= parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
]
558 if isChildContainer
and \
559 ((parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
560 (parentIsBook
and not isinstance(xxx
, xxxPage
)) or \
561 not (parent
.isSizer
or parentIsBook
)):
562 elem
.removeChild(xxx
.child
.element
) # detach child
563 elem
.unlink() # delete child container
564 elem
= xxx
.child
.element
# replace
565 # This may help garbage collection
566 xxx
.child
.parent
= None
567 isChildContainer
= False
568 # Parent is sizer or notebook, child is not child container
569 if parent
.isSizer
and not isChildContainer
and not isinstance(xxx
, xxxSpacer
):
570 # Create sizer item element
571 sizerItemElem
= MakeEmptyDOM(parent
.itemTag
)
572 sizerItemElem
.appendChild(elem
)
574 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
575 pageElem
= MakeEmptyDOM('notebookpage')
576 pageElem
.appendChild(elem
)
578 elif isinstance(parent
, xxxChoicebook
) and not isChildContainer
:
579 pageElem
= MakeEmptyDOM('choicebookpage')
580 pageElem
.appendChild(elem
)
582 elif isinstance(parent
, xxxListbook
) and not isChildContainer
:
583 pageElem
= MakeEmptyDOM('listbookpage')
584 pageElem
.appendChild(elem
)
586 # Insert new node, register undo
587 newItem
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
)
588 undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
))
589 # Scroll to show new item (!!! redundant?)
590 tree
.EnsureVisible(newItem
)
591 tree
.SelectItem(newItem
)
592 if not tree
.IsVisible(newItem
):
593 tree
.ScrollTo(newItem
)
596 if g
.testWin
and tree
.IsHighlatable(newItem
):
598 tree
.needUpdate
= True
599 tree
.pendingHighLight
= newItem
601 tree
.pendingHighLight
= None
603 self
.SetStatusText('Pasted')
606 def ItemsAreCompatible(self
, parent
, child
):
607 # Check compatibility
610 if child
.__class
__ in [xxxDialog
, xxxFrame
, xxxWizard
]:
612 if parent
.__class
__ != xxxMainNode
: error
= True
613 elif child
.__class
__ == xxxMenuBar
:
614 # Menubar can be put in frame or dialog
615 if parent
.__class
__ not in [xxxMainNode
, xxxFrame
, xxxDialog
]: error
= True
616 elif child
.__class
__ == xxxToolBar
:
617 # Toolbar can be top-level of child of panel or frame
618 if parent
.__class
__ not in [xxxMainNode
, xxxPanel
, xxxFrame
] and \
619 not parent
.isSizer
: error
= True
620 elif child
.__class
__ == xxxPanel
and parent
.__class
__ == xxxMainNode
:
622 elif child
.__class
__ == xxxSpacer
:
623 if not parent
.isSizer
: error
= True
624 elif child
.__class
__ == xxxSeparator
:
625 if not parent
.__class
__ in [xxxMenu
, xxxToolBar
]: error
= True
626 elif child
.__class
__ == xxxTool
:
627 if parent
.__class
__ != xxxToolBar
: error
= True
628 elif child
.__class
__ == xxxMenu
:
629 if not parent
.__class
__ in [xxxMainNode
, xxxMenuBar
, xxxMenu
]: error
= True
630 elif child
.__class
__ == xxxMenuItem
:
631 if not parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= True
632 elif child
.isSizer
and parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
]:
634 else: # normal controls can be almost anywhere
635 if parent
.__class
__ == xxxMainNode
or \
636 parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= True
638 if parent
.__class
__ == xxxMainNode
: parentClass
= 'root'
639 else: parentClass
= parent
.className
640 wx
.LogError('Incompatible parent/child: parent is %s, child is %s!' %
641 (parentClass
, child
.className
))
645 def OnMoveUp(self
, evt
):
646 selected
= tree
.selection
647 if not selected
: return
649 index
= tree
.ItemIndex(selected
)
650 if index
== 0: return # No previous sibling found
653 self
.lastOp
= 'MOVEUP'
654 status
= 'Moved before previous sibling'
659 parent
= tree
.GetItemParent(selected
)
660 elem
= tree
.RemoveLeaf(selected
)
661 nextItem
= tree
.GetFirstChild(parent
)[0]
662 for i
in range(index
- 1): nextItem
= tree
.GetNextSibling(nextItem
)
663 selected
= tree
.InsertNode(parent
, tree
.GetPyData(parent
).treeObject(), elem
, nextItem
)
664 newIndex
= tree
.ItemIndex(selected
)
665 tree
.SelectItem(selected
)
667 undoMan
.RegisterUndo(UndoMove(parent
, index
, parent
, newIndex
))
670 self
.SetStatusText(status
)
674 def OnMoveDown(self
, evt
):
675 selected
= tree
.selection
676 if not selected
: return
678 index
= tree
.ItemIndex(selected
)
679 next
= tree
.GetNextSibling(selected
)
683 self
.lastOp
= 'MOVEDOWN'
684 status
= 'Moved after next sibling'
689 parent
= tree
.GetItemParent(selected
)
690 elem
= tree
.RemoveLeaf(selected
)
691 nextItem
= tree
.GetFirstChild(parent
)[0]
692 for i
in range(index
+ 1): nextItem
= tree
.GetNextSibling(nextItem
)
693 selected
= tree
.InsertNode(parent
, tree
.GetPyData(parent
).treeObject(), elem
, nextItem
)
694 newIndex
= tree
.ItemIndex(selected
)
695 tree
.SelectItem(selected
)
697 undoMan
.RegisterUndo(UndoMove(parent
, index
, parent
, newIndex
))
700 self
.SetStatusText(status
)
704 def OnMoveLeft(self
, evt
):
705 selected
= tree
.selection
706 if not selected
: return
708 oldParent
= tree
.GetItemParent(selected
)
709 if not oldParent
: return
710 pparent
= tree
.GetItemParent(oldParent
)
711 if not pparent
: return
713 # Check compatibility
714 if not self
.ItemsAreCompatible(tree
.GetPyData(pparent
).treeObject(), tree
.GetPyData(selected
).treeObject()): return
717 self
.lastOp
= 'MOVELEFT'
718 status
= 'Made next sibling of parent'
720 oldIndex
= tree
.ItemIndex(selected
)
721 elem
= tree
.RemoveLeaf(selected
)
722 nextItem
= tree
.GetFirstChild(pparent
)[0]
723 parentIndex
= tree
.ItemIndex(oldParent
)
724 for i
in range(parentIndex
+ 1): nextItem
= tree
.GetNextSibling(nextItem
)
726 # Check parent and child relationships.
727 # If parent is sizer or notebook, child is of wrong class or
728 # parent is normal window, child is child container then detach child.
729 parent
= tree
.GetPyData(pparent
).treeObject()
730 xxx
= MakeXXXFromDOM(parent
, elem
)
731 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
732 if isChildContainer
and \
733 ((parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
734 (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
735 not (parent
.isSizer
or isinstance(parent
, xxxNotebook
))):
736 elem
.removeChild(xxx
.child
.element
) # detach child
737 elem
.unlink() # delete child container
738 elem
= xxx
.child
.element
# replace
739 # This may help garbage collection
740 xxx
.child
.parent
= None
741 isChildContainer
= False
742 # Parent is sizer or notebook, child is not child container
743 if parent
.isSizer
and not isChildContainer
and not isinstance(xxx
, xxxSpacer
):
744 # Create sizer item element
745 sizerItemElem
= MakeEmptyDOM('sizeritem')
746 sizerItemElem
.appendChild(elem
)
748 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
749 pageElem
= MakeEmptyDOM('notebookpage')
750 pageElem
.appendChild(elem
)
753 selected
= tree
.InsertNode(pparent
, tree
.GetPyData(pparent
).treeObject(), elem
, nextItem
)
754 newIndex
= tree
.ItemIndex(selected
)
755 tree
.SelectItem(selected
)
757 undoMan
.RegisterUndo(UndoMove(oldParent
, oldIndex
, pparent
, newIndex
))
760 self
.SetStatusText(status
)
762 def OnMoveRight(self
, evt
):
763 selected
= tree
.selection
764 if not selected
: return
766 oldParent
= tree
.GetItemParent(selected
)
767 if not oldParent
: return
769 newParent
= tree
.GetPrevSibling(selected
)
770 if not newParent
: return
772 parent
= tree
.GetPyData(newParent
).treeObject()
774 # Check compatibility
775 if not self
.ItemsAreCompatible(parent
, tree
.GetPyData(selected
).treeObject()): return
778 self
.lastOp
= 'MOVERIGHT'
779 status
= 'Made last child of previous sibling'
781 oldIndex
= tree
.ItemIndex(selected
)
782 elem
= tree
.RemoveLeaf(selected
)
784 # Check parent and child relationships.
785 # If parent is sizer or notebook, child is of wrong class or
786 # parent is normal window, child is child container then detach child.
787 xxx
= MakeXXXFromDOM(parent
, elem
)
788 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
789 if isChildContainer
and \
790 ((parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
791 (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
792 not (parent
.isSizer
or isinstance(parent
, xxxNotebook
))):
793 elem
.removeChild(xxx
.child
.element
) # detach child
794 elem
.unlink() # delete child container
795 elem
= xxx
.child
.element
# replace
796 # This may help garbage collection
797 xxx
.child
.parent
= None
798 isChildContainer
= False
799 # Parent is sizer or notebook, child is not child container
800 if parent
.isSizer
and not isChildContainer
and not isinstance(xxx
, xxxSpacer
):
801 # Create sizer item element
802 sizerItemElem
= MakeEmptyDOM('sizeritem')
803 sizerItemElem
.appendChild(elem
)
805 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
806 pageElem
= MakeEmptyDOM('notebookpage')
807 pageElem
.appendChild(elem
)
810 selected
= tree
.InsertNode(newParent
, tree
.GetPyData(newParent
).treeObject(), elem
, wx
.TreeItemId())
812 newIndex
= tree
.ItemIndex(selected
)
813 tree
.SelectItem(selected
)
815 undoMan
.RegisterUndo(UndoMove(oldParent
, oldIndex
, newParent
, newIndex
))
818 self
.SetStatusText(status
)
821 def OnCutDelete(self
, evt
):
822 selected
= tree
.selection
823 if not selected
: return # key pressed event
825 if evt
.GetId() == wx
.ID_CUT
:
827 status
= 'Removed to clipboard'
829 self
.lastOp
= 'DELETE'
833 # If deleting top-level item, delete testWin
834 if selected
== g
.testWin
.item
:
838 # Remove highlight, update testWin
839 if g
.testWin
.highLight
:
840 g
.testWin
.highLight
.Remove()
841 tree
.needUpdate
= True
844 index
= tree
.ItemFullIndex(selected
)
845 parent
= tree
.GetPyData(tree
.GetItemParent(selected
)).treeObject()
846 elem
= tree
.RemoveLeaf(selected
)
847 undoMan
.RegisterUndo(UndoCutDelete(index
, parent
, elem
))
848 if evt
.GetId() == wx
.ID_CUT
:
849 if wx
.TheClipboard
.Open():
850 data
= wx
.CustomDataObject('XRCED')
852 s
= elem
.toxml(encoding
=expat
.native_encoding
)
853 data
.SetData(cPickle
.dumps(s
))
854 wx
.TheClipboard
.SetData(data
)
855 wx
.TheClipboard
.Close()
857 wx
.MessageBox("Unable to open the clipboard", "Error")
858 tree
.pendingHighLight
= None
860 tree
.selection
= None
865 self
.SetStatusText(status
)
867 def OnSubclass(self
, evt
):
868 selected
= tree
.selection
869 xxx
= tree
.GetPyData(selected
).treeObject()
871 subclass
= xxx
.subclass
872 dlg
= wx
.TextEntryDialog(self
, 'Subclass:', defaultValue
=subclass
)
873 if dlg
.ShowModal() == wx
.ID_OK
:
874 subclass
= dlg
.GetValue()
876 elem
.setAttribute('subclass', subclass
)
877 elif elem
.hasAttribute('subclass'):
878 elem
.removeAttribute('subclass')
880 xxx
.subclass
= elem
.getAttribute('subclass')
881 tree
.SetItemText(selected
, xxx
.treeName())
882 panel
.pages
[0].box
.SetLabel(xxx
.panelName())
885 def OnEmbedPanel(self
, evt
):
886 conf
.embedPanel
= evt
.IsChecked()
888 # Remember last dimentions
889 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
890 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
891 size
= self
.GetSize()
892 pos
= self
.GetPosition()
893 sizePanel
= panel
.GetSize()
894 panel
.Reparent(self
.splitter
)
895 self
.miniFrame
.GetSizer().Remove(panel
)
897 self
.SetDimensions(pos
.x
, pos
.y
, size
.width
+ sizePanel
.width
, size
.height
)
898 self
.splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
899 self
.miniFrame
.Show(False)
901 conf
.sashPos
= self
.splitter
.GetSashPosition()
902 pos
= self
.GetPosition()
903 size
= self
.GetSize()
904 sizePanel
= panel
.GetSize()
905 self
.splitter
.Unsplit(panel
)
906 sizer
= self
.miniFrame
.GetSizer()
907 panel
.Reparent(self
.miniFrame
)
909 sizer
.Add(panel
, 1, wx
.EXPAND
)
910 self
.miniFrame
.Show(True)
911 self
.miniFrame
.SetDimensions(conf
.panelX
, conf
.panelY
,
912 conf
.panelWidth
, conf
.panelHeight
)
914 self
.SetDimensions(pos
.x
, pos
.y
,
915 max(size
.width
- sizePanel
.width
, self
.minWidth
), size
.height
)
917 def OnShowTools(self
, evt
):
918 conf
.showTools
= evt
.IsChecked()
919 g
.tools
.Show(conf
.showTools
)
921 self
.toolsSizer
.Prepend(g
.tools
, 0, wx
.EXPAND
)
923 self
.toolsSizer
.Remove(g
.tools
)
924 self
.toolsSizer
.Layout()
926 def OnTest(self
, evt
):
927 if not tree
.selection
: return # key pressed event
928 tree
.ShowTestWindow(tree
.selection
)
930 def OnTestHide(self
, evt
):
931 tree
.CloseTestWindow()
933 # Find object by relative position
934 def FindObject(self
, item
, obj
):
935 # We simply perform depth-first traversal, sinse it's too much
936 # hassle to deal with all sizer/window combinations
937 w
= tree
.FindNodeObject(item
)
938 if w
== obj
or isinstance(w
, wx
.GBSizerItem
) and w
.GetWindow() == obj
:
940 if tree
.ItemHasChildren(item
):
941 child
= tree
.GetFirstChild(item
)[0]
943 found
= self
.FindObject(child
, obj
)
944 if found
: return found
945 child
= tree
.GetNextSibling(child
)
948 def OnTestWinLeftDown(self
, evt
):
949 pos
= evt
.GetPosition()
950 self
.SetHandler(g
.testWin
)
951 g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
)
952 item
= self
.FindObject(g
.testWin
.item
, evt
.GetEventObject())
954 tree
.EnsureVisible(item
)
955 tree
.SelectItem(item
)
956 self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, False)
958 self
.SetStatusText('Selected %s' % tree
.GetItemText(item
))
960 self
.SetStatusText('Locate failed!')
962 def SetHandler(self
, w
, h
=None):
965 w
.SetCursor(wx
.CROSS_CURSOR
)
968 w
.SetCursor(wx
.NullCursor
)
969 for ch
in w
.GetChildren():
970 self
.SetHandler(ch
, h
)
972 def OnLocate(self
, evt
):
974 if evt
.GetId() == self
.ID_LOCATE
or \
975 evt
.GetId() == self
.ID_TOOL_LOCATE
and evt
.IsChecked():
976 self
.SetHandler(g
.testWin
, g
.testWin
)
977 g
.testWin
.Connect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
, self
.OnTestWinLeftDown
)
978 if evt
.GetId() == self
.ID_LOCATE
:
979 self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, True)
980 elif evt
.GetId() == self
.ID_TOOL_LOCATE
and not evt
.IsChecked():
981 self
.SetHandler(g
.testWin
, None)
982 g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
)
983 self
.SetStatusText('Click somewhere in your test window now')
985 def OnRefresh(self
, evt
):
986 # If modified, apply first
987 selection
= tree
.selection
989 xxx
= tree
.GetPyData(selection
)
990 if xxx
and panel
.IsModified():
991 tree
.Apply(xxx
, selection
)
994 tree
.CreateTestWin(g
.testWin
.item
)
995 panel
.modified
= False
996 tree
.needUpdate
= False
998 def OnAutoRefresh(self
, evt
):
999 conf
.autoRefresh
= evt
.IsChecked()
1000 self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1001 self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1003 def OnAbout(self
, evt
):
1007 (c) Roman Rolinsky <rollrom@users.sourceforge.net>
1008 Homepage: http://xrced.sourceforge.net\
1010 dlg
= wx
.MessageDialog(self
, str, 'About XRCed', wx
.OK | wx
.CENTRE
)
1014 def OnReadme(self
, evt
):
1015 text
= open(os
.path
.join(basePath
, 'README.txt'), 'r').read()
1016 dlg
= ScrolledMessageDialog(self
, text
, "XRCed README")
1020 # Simple emulation of python command line
1021 def OnDebugCMD(self
, evt
):
1024 exec raw_input('C:\> ')
1029 (etype
, value
, tb
) =sys
.exc_info()
1030 tblist
=traceback
.extract_tb(tb
)[1:]
1031 msg
=' '.join(traceback
.format_exception_only(etype
, value
)
1032 +traceback
.format_list(tblist
))
1035 def OnCreate(self
, evt
):
1036 selected
= tree
.selection
1037 if tree
.ctrl
: appendChild
= False
1038 else: appendChild
= not tree
.NeedInsert(selected
)
1039 xxx
= tree
.GetPyData(selected
)
1043 # If has previous item, insert after it, else append to parent
1045 parentLeaf
= tree
.GetItemParent(selected
)
1047 # If has next item, insert, else append to parent
1048 nextItem
= tree
.GetNextSibling(selected
)
1049 parentLeaf
= tree
.GetItemParent(selected
)
1050 # Expanded container (must have children)
1051 elif tree
.shift
and tree
.IsExpanded(selected
) \
1052 and tree
.GetChildrenCount(selected
, False):
1053 nextItem
= tree
.GetFirstChild(selected
)[0]
1054 parentLeaf
= selected
1056 nextItem
= wx
.TreeItemId()
1057 parentLeaf
= selected
1058 parent
= tree
.GetPyData(parentLeaf
)
1059 if parent
.hasChild
: parent
= parent
.child
1061 # Create object_ref?
1062 if evt
.GetId() == ID_NEW
.REF
:
1063 ref
= wx
.GetTextFromUser('Create reference to:', 'Create reference')
1065 xxx
= MakeEmptyRefXXX(parent
, ref
)
1067 # Create empty element
1068 className
= pullDownMenu
.createMap
[evt
.GetId()]
1069 xxx
= MakeEmptyXXX(parent
, className
)
1071 # Set default name for top-level windows
1072 if parent
.__class
__ == xxxMainNode
:
1073 cl
= xxx
.treeObject().__class
__
1074 frame
.maxIDs
[cl
] += 1
1075 xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
]))
1076 # And for some other standard controls
1077 elif parent
.__class
__ == xxxStdDialogButtonSizer
:
1078 xxx
.setTreeName(pullDownMenu
.stdButtonIDs
[evt
.GetId()][0])
1079 # We can even set label
1080 obj
= xxx
.treeObject()
1081 elem
= g
.tree
.dom
.createElement('label')
1082 elem
.appendChild(g
.tree
.dom
.createTextNode(pullDownMenu
.stdButtonIDs
[evt
.GetId()][1]))
1083 obj
.params
['label'] = xxxParam(elem
)
1084 xxx
.treeObject().element
.appendChild(elem
)
1086 # Insert new node, register undo
1088 newItem
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
)
1089 undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
))
1090 tree
.EnsureVisible(newItem
)
1091 tree
.SelectItem(newItem
)
1092 if not tree
.IsVisible(newItem
):
1093 tree
.ScrollTo(newItem
)
1096 if g
.testWin
and tree
.IsHighlatable(newItem
):
1097 if conf
.autoRefresh
:
1098 tree
.needUpdate
= True
1099 tree
.pendingHighLight
= newItem
1101 tree
.pendingHighLight
= None
1105 # Replace one object with another
1106 def OnReplace(self
, evt
):
1107 selected
= tree
.selection
1108 xxx
= tree
.GetPyData(selected
).treeObject()
1110 parent
= elem
.parentNode
1111 undoMan
.RegisterUndo(UndoReplace(selected
))
1113 className
= pullDownMenu
.createMap
[evt
.GetId() - 1000]
1115 # Create temporary empty node (with default values)
1116 dummy
= MakeEmptyDOM(className
)
1117 if className
== 'spacer' and xxx
.className
!= 'spacer':
1119 elif xxx
.className
== 'spacer' and className
!= 'spacer':
1120 klass
= xxxSizerItem
1122 klass
= xxxDict
[className
]
1123 # Remove non-compatible children
1124 if tree
.ItemHasChildren(selected
) and not klass
.hasChildren
:
1125 tree
.DeleteChildren(selected
)
1126 nodes
= elem
.childNodes
[:]
1129 if node
.nodeType
!= minidom
.Node
.ELEMENT_NODE
: continue
1133 if not klass
.hasChildren
: remove
= True
1134 elif tag
not in klass
.allParams
and \
1135 (not klass
.hasStyle
or tag
not in klass
.styles
):
1140 elem
.removeChild(node
)
1143 # Remove sizeritem child if spacer
1144 if className
== 'spacer' and xxx
.className
!= 'spacer':
1145 sizeritem
= elem
.parentNode
1146 assert sizeritem
.getAttribute('class') == 'sizeritem'
1147 sizeritem
.removeChild(elem
)
1150 tree
.GetPyData(selected
).hasChild
= False
1151 elif xxx
.className
== 'spacer' and className
!= 'spacer':
1152 # Create sizeritem element
1153 assert xxx
.parent
.isSizer
1154 elem
.setAttribute('class', 'sizeritem')
1155 node
= MakeEmptyDOM(className
)
1156 elem
.appendChild(node
)
1157 # Replace to point to new object
1158 xxx
= xxxSizerItem(xxx
.parent
, elem
)
1160 tree
.SetPyData(selected
, xxx
)
1163 # Copy parameters present in dummy but not in elem
1164 for node
in dummy
.childNodes
:
1165 if node
.tagName
not in tags
: elem
.appendChild(node
.cloneNode(True))
1169 elem
.setAttribute('class', className
)
1170 if elem
.hasAttribute('subclass'):
1171 elem
.removeAttribute('subclass') # clear subclassing
1172 # Re-create xxx element
1173 xxx
= MakeXXXFromDOM(xxx
.parent
, elem
)
1174 # Remove incompatible style flags
1175 if 'style' in xxx
.params
:
1176 styles
= map(string
.strip
, xxx
.params
['style'].value().split('|'))
1177 newStyles
= [s
for s
in styles
if s
in klass
.winStyles
or s
in genericStyles
]
1178 if newStyles
!= styles
:
1180 value
= reduce(lambda a
,b
: a
+'|'+b
, newStyles
)
1183 xxx
.params
['style'].update(value
)
1185 # Update parent in child objects
1186 if tree
.ItemHasChildren(selected
):
1187 i
, cookie
= tree
.GetFirstChild(selected
)
1189 x
= tree
.GetPyData(i
)
1191 if x
.hasChild
: x
.child
.parent
= xxx
1192 i
, cookie
= tree
.GetNextChild(selected
, cookie
)
1195 if tree
.GetPyData(selected
).hasChild
: # child container
1196 container
= tree
.GetPyData(selected
)
1197 container
.resetChild(xxx
)
1200 tree
.SetPyData(selected
, xxx
)
1201 tree
.SetItemText(selected
, xxx
.treeName())
1202 tree
.SetItemImage(selected
, xxx
.treeImage())
1204 # Set default name for top-level windows
1205 if parent
.__class
__ == xxxMainNode
:
1206 cl
= xxx
.treeObject().__class
__
1207 frame
.maxIDs
[cl
] += 1
1208 xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
]))
1211 g
.panel
.SetData(xxx
)
1215 #undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
1217 if g
.testWin
and tree
.IsHighlatable(selected
):
1218 if conf
.autoRefresh
:
1219 tree
.needUpdate
= True
1220 tree
.pendingHighLight
= selected
1222 tree
.pendingHighLight
= None
1226 # Expand/collapse subtree
1227 def OnExpand(self
, evt
):
1228 if tree
.selection
: tree
.ExpandAll(tree
.selection
)
1229 else: tree
.ExpandAll(tree
.root
)
1230 def OnCollapse(self
, evt
):
1231 if tree
.selection
: tree
.CollapseAll(tree
.selection
)
1232 else: tree
.CollapseAll(tree
.root
)
1234 def OnPullDownHighlight(self
, evt
):
1235 menuId
= evt
.GetMenuId()
1237 menu
= evt
.GetEventObject()
1238 help = menu
.GetHelpString(menuId
)
1239 self
.SetStatusText(help)
1241 self
.SetStatusText('')
1243 def OnUpdateUI(self
, evt
):
1244 if evt
.GetId() in [wx
.ID_CUT
, wx
.ID_COPY
, self
.ID_DELETE
]:
1245 evt
.Enable(tree
.selection
is not None and tree
.selection
!= tree
.root
)
1246 elif evt
.GetId() == wx
.ID_SAVE
:
1247 evt
.Enable(self
.modified
)
1248 elif evt
.GetId() in [wx
.ID_PASTE
, self
.ID_TOOL_PASTE
]:
1249 evt
.Enable(tree
.selection
is not None)
1250 elif evt
.GetId() == self
.ID_TEST
:
1251 evt
.Enable(tree
.selection
is not None and tree
.selection
!= tree
.root
)
1252 elif evt
.GetId() in [self
.ID_LOCATE
, self
.ID_TOOL_LOCATE
]:
1253 evt
.Enable(g
.testWin
is not None)
1254 elif evt
.GetId() == wx
.ID_UNDO
: evt
.Enable(undoMan
.CanUndo())
1255 elif evt
.GetId() == wx
.ID_REDO
: evt
.Enable(undoMan
.CanRedo())
1257 def OnIdle(self
, evt
):
1258 if self
.inIdle
: return # Recursive call protection
1262 if conf
.autoRefresh
:
1264 self
.SetStatusText('Refreshing test window...')
1266 tree
.CreateTestWin(g
.testWin
.item
)
1267 self
.SetStatusText('')
1268 tree
.needUpdate
= False
1269 elif tree
.pendingHighLight
:
1271 tree
.HighLight(tree
.pendingHighLight
)
1273 # Remove highlight if any problem
1274 if g
.testWin
.highLight
:
1275 g
.testWin
.highLight
.Remove()
1276 tree
.pendingHighLight
= None
1283 # We don't let close panel window
1284 def OnCloseMiniFrame(self
, evt
):
1287 def OnIconize(self
, evt
):
1288 conf
.x
, conf
.y
= self
.GetPosition()
1289 conf
.width
, conf
.height
= self
.GetSize()
1291 conf
.sashPos
= self
.splitter
.GetSashPosition()
1293 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
1294 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
1295 self
.miniFrame
.Iconize()
1298 def OnCloseWindow(self
, evt
):
1299 if not self
.AskSave(): return
1300 if g
.testWin
: g
.testWin
.Destroy()
1301 if not panel
.GetPageCount() == 2:
1302 panel
.page2
.Destroy()
1304 # If we don't do this, page does not get destroyed (a bug?)
1306 if not self
.IsIconized():
1307 conf
.x
, conf
.y
= self
.GetPosition()
1308 conf
.width
, conf
.height
= self
.GetSize()
1310 conf
.sashPos
= self
.splitter
.GetSashPosition()
1312 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
1313 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
1317 def CreateLocalConf(self
, path
):
1318 name
= os
.path
.splitext(path
)[0]
1320 return wx
.FileConfig(localFilename
=name
)
1325 conf
.localconf
= None
1327 self
.SetModified(False)
1333 # Numbers for new controls
1335 for cl
in [xxxPanel
, xxxDialog
, xxxFrame
,
1336 xxxMenuBar
, xxxMenu
, xxxToolBar
,
1337 xxxWizard
, xxxBitmap
, xxxIcon
]:
1340 def SetModified(self
, state
=True):
1341 self
.modified
= state
1342 name
= os
.path
.basename(self
.dataFile
)
1343 if not name
: name
= defaultName
1345 self
.SetTitle(progname
+ ': ' + name
+ ' *')
1347 self
.SetTitle(progname
+ ': ' + name
)
1349 def Open(self
, path
):
1350 if not os
.path
.exists(path
):
1351 wx
.LogError('File does not exists: %s' % path
)
1353 # Try to read the file
1357 dom
= minidom
.parse(f
)
1359 # Set encoding global variable and default encoding
1361 g
.currentEncoding
= dom
.encoding
1362 wx
.SetDefaultPyEncoding(g
.currentEncoding
.encode())
1364 g
.currentEncoding
= ''
1366 self
.dataFile
= path
= os
.path
.abspath(path
)
1367 dir = os
.path
.dirname(path
)
1368 if dir: os
.chdir(dir)
1370 self
.SetTitle(progname
+ ': ' + os
.path
.basename(path
))
1371 conf
.localconf
= self
.CreateLocalConf(self
.dataFile
)
1373 # Nice exception printing
1374 inf
= sys
.exc_info()
1375 wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
1376 wx
.LogError('Error reading file: %s' % path
)
1381 def Indent(self
, node
, indent
= 0):
1382 # Copy child list because it will change soon
1383 children
= node
.childNodes
[:]
1384 # Main node doesn't need to be indented
1386 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
1387 node
.parentNode
.insertBefore(text
, node
)
1389 # Append newline after last child, except for text nodes
1390 if children
[-1].nodeType
== minidom
.Node
.ELEMENT_NODE
:
1391 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
1392 node
.appendChild(text
)
1393 # Indent children which are elements
1395 if n
.nodeType
== minidom
.Node
.ELEMENT_NODE
:
1396 self
.Indent(n
, indent
+ 2)
1398 def Save(self
, path
):
1402 if tree
.selection
and panel
.IsModified():
1403 self
.OnRefresh(wx
.CommandEvent())
1404 if g
.currentEncoding
:
1405 f
= codecs
.open(path
, 'wt', g
.currentEncoding
)
1407 f
= codecs
.open(path
, 'wt')
1408 # Make temporary copy for formatting it
1409 # !!! We can't clone dom node, it works only once
1410 #self.domCopy = tree.dom.cloneNode(True)
1411 self
.domCopy
= MyDocument()
1412 mainNode
= self
.domCopy
.appendChild(tree
.mainNode
.cloneNode(True))
1413 # Remove first child (test element)
1414 testElem
= mainNode
.firstChild
1415 mainNode
.removeChild(testElem
)
1417 self
.Indent(mainNode
)
1418 self
.domCopy
.writexml(f
, encoding
= g
.currentEncoding
)
1420 self
.domCopy
.unlink()
1422 self
.SetModified(False)
1423 panel
.SetModified(False)
1424 conf
.localconf
.Flush()
1426 inf
= sys
.exc_info()
1427 wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
1428 wx
.LogError('Error writing file: %s' % path
)
1432 if not (self
.modified
or panel
.IsModified()): return True
1433 flags
= wx
.ICON_EXCLAMATION | wx
.YES_NO | wx
.CANCEL | wx
.CENTRE
1434 dlg
= wx
.MessageDialog( self
, 'File is modified. Save before exit?',
1435 'Save before too late?', flags
)
1436 say
= dlg
.ShowModal()
1439 if say
== wx
.ID_YES
:
1440 self
.OnSaveOrSaveAs(wx
.CommandEvent(wx
.ID_SAVE
))
1441 # If save was successful, modified flag is unset
1442 if not self
.modified
: return True
1443 elif say
== wx
.ID_NO
:
1444 self
.SetModified(False)
1445 panel
.SetModified(False)
1452 ################################################################################
1454 class PythonOptions(wx
.Dialog
):
1456 def __init__(self
, parent
, cfg
, dataFile
):
1457 pre
= wx
.PreDialog()
1458 g
.frame
.res
.LoadOnDialog(pre
, parent
, "PYTHON_OPTIONS")
1459 self
.PostCreate(pre
)
1462 self
.dataFile
= dataFile
1464 self
.AutoGenerateCB
= xrc
.XRCCTRL(self
, "AutoGenerateCB")
1465 self
.EmbedCB
= xrc
.XRCCTRL(self
, "EmbedCB")
1466 self
.GettextCB
= xrc
.XRCCTRL(self
, "GettextCB")
1467 self
.MakeXRSFileCB
= xrc
.XRCCTRL(self
, "MakeXRSFileCB")
1468 self
.FileNameTC
= xrc
.XRCCTRL(self
, "FileNameTC")
1469 self
.BrowseBtn
= xrc
.XRCCTRL(self
, "BrowseBtn")
1470 self
.GenerateBtn
= xrc
.XRCCTRL(self
, "GenerateBtn")
1471 self
.SaveOptsBtn
= xrc
.XRCCTRL(self
, "SaveOptsBtn")
1473 self
.Bind(wx
.EVT_BUTTON
, self
.OnBrowse
, self
.BrowseBtn
)
1474 self
.Bind(wx
.EVT_BUTTON
, self
.OnGenerate
, self
.GenerateBtn
)
1475 self
.Bind(wx
.EVT_BUTTON
, self
.OnSaveOpts
, self
.SaveOptsBtn
)
1477 if self
.cfg
.Read("filename", "") != "":
1478 self
.FileNameTC
.SetValue(self
.cfg
.Read("filename"))
1480 name
= os
.path
.splitext(os
.path
.split(dataFile
)[1])[0]
1482 self
.FileNameTC
.SetValue(name
)
1483 self
.AutoGenerateCB
.SetValue(self
.cfg
.ReadBool("autogenerate", False))
1484 self
.EmbedCB
.SetValue(self
.cfg
.ReadBool("embedResource", False))
1485 self
.MakeXRSFileCB
.SetValue(self
.cfg
.ReadBool("makeXRS", False))
1486 self
.GettextCB
.SetValue(self
.cfg
.ReadBool("genGettext", False))
1489 def OnBrowse(self
, evt
):
1490 path
= self
.FileNameTC
.GetValue()
1491 dirname
= os
.path
.abspath(os
.path
.dirname(path
))
1492 name
= os
.path
.split(path
)[1]
1493 dlg
= wx
.FileDialog(self
, 'Save As', dirname
, name
, '*.py',
1494 wx
.SAVE | wx
.OVERWRITE_PROMPT
)
1495 if dlg
.ShowModal() == wx
.ID_OK
:
1496 path
= dlg
.GetPath()
1497 self
.FileNameTC
.SetValue(path
)
1501 def OnGenerate(self
, evt
):
1502 pypath
= self
.FileNameTC
.GetValue()
1503 embed
= self
.EmbedCB
.GetValue()
1504 genGettext
= self
.GettextCB
.GetValue()
1505 frame
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
)
1509 def OnSaveOpts(self
, evt
=None):
1510 self
.cfg
.Write("filename", self
.FileNameTC
.GetValue())
1511 self
.cfg
.WriteBool("autogenerate", self
.AutoGenerateCB
.GetValue())
1512 self
.cfg
.WriteBool("embedResource", self
.EmbedCB
.GetValue())
1513 self
.cfg
.WriteBool("makeXRS", self
.MakeXRSFileCB
.GetValue())
1514 self
.cfg
.WriteBool("genGettext", self
.GettextCB
.GetValue())
1516 self
.EndModal(wx
.ID_OK
)
1519 ################################################################################
1522 print >> sys
.stderr
, 'usage: xrced [-dhiv] [file]'
1527 if wx
.VERSION
[:3] < MinWxVersion
:
1529 This version of XRCed may not work correctly on your version of wxWidgets. \
1530 Please upgrade wxWidgets to %d.%d.%d or higher.''' % MinWxVersion
)
1532 # Process comand-line
1535 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'dhiv')
1543 print 'XRCed version', version
1546 except getopt
.GetoptError
:
1547 if wx
.Platform
!= '__WXMAC__': # macs have some extra parameters
1548 print >> sys
.stderr
, 'Unknown option'
1552 self
.SetAppName('xrced')
1555 conf
= g
.conf
= wx
.Config(style
= wx
.CONFIG_USE_LOCAL_FILE
)
1556 conf
.localconf
= None
1557 conf
.autoRefresh
= conf
.ReadInt('autorefresh', True)
1558 pos
= conf
.ReadInt('x', -1), conf
.ReadInt('y', -1)
1559 size
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600)
1560 conf
.embedPanel
= conf
.ReadInt('embedPanel', True)
1561 conf
.showTools
= conf
.ReadInt('showTools', True)
1562 conf
.sashPos
= conf
.ReadInt('sashPos', 200)
1563 # read recently used files
1564 recentfiles
=conf
.Read('recentFiles','')
1567 for fil
in recentfiles
.split('|'):
1568 conf
.recentfiles
[wx
.NewId()]=fil
1569 if not conf
.embedPanel
:
1570 conf
.panelX
= conf
.ReadInt('panelX', -1)
1571 conf
.panelY
= conf
.ReadInt('panelY', -1)
1573 conf
.panelX
= conf
.panelY
= -1
1574 conf
.panelWidth
= conf
.ReadInt('panelWidth', 200)
1575 conf
.panelHeight
= conf
.ReadInt('panelHeight', 200)
1576 conf
.panic
= not conf
.HasEntry('nopanic')
1578 wx
.FileSystem
.AddHandler(wx
.MemoryFSHandler())
1580 frame
= Frame(pos
, size
)
1583 # Load file after showing
1586 frame
.open = frame
.Open(args
[0])
1594 wc
.WriteInt('autorefresh', conf
.autoRefresh
)
1595 wc
.WriteInt('x', conf
.x
)
1596 wc
.WriteInt('y', conf
.y
)
1597 wc
.WriteInt('width', conf
.width
)
1598 wc
.WriteInt('height', conf
.height
)
1599 wc
.WriteInt('embedPanel', conf
.embedPanel
)
1600 wc
.WriteInt('showTools', conf
.showTools
)
1601 if not conf
.embedPanel
:
1602 wc
.WriteInt('panelX', conf
.panelX
)
1603 wc
.WriteInt('panelY', conf
.panelY
)
1604 wc
.WriteInt('sashPos', conf
.sashPos
)
1605 wc
.WriteInt('panelWidth', conf
.panelWidth
)
1606 wc
.WriteInt('panelHeight', conf
.panelHeight
)
1607 wc
.WriteInt('nopanic', True)
1608 wc
.Write('recentFiles', '|'.join(conf
.recentfiles
.values()[-5:]))
1612 app
= App(0, useBestVisual
=False)
1613 #app.SetAssertMode(wx.PYAPP_ASSERT_LOG)
1619 if __name__
== '__main__':