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