]>
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
:
382 # if we already have a localconf then it needs to be
383 # copied to a new config with the new name
385 nc
= self
.CreateLocalConf(path
)
386 flag
, key
, idx
= lc
.GetFirstEntry()
388 nc
.Write(key
, lc
.Read(key
))
389 flag
, key
, idx
= lc
.GetNextEntry(idx
)
392 # otherwise create a new one
393 conf
.localconf
= self
.CreateLocalConf(path
)
396 self
.SetStatusText('Saving...')
400 tmpFile
,tmpName
= tempfile
.mkstemp(prefix
='xrced-')
402 self
.Save(tmpName
) # save temporary file first
403 shutil
.move(tmpName
, path
)
405 if conf
.localconf
.ReadBool("autogenerate", False):
406 pypath
= conf
.localconf
.Read("filename")
407 embed
= conf
.localconf
.ReadBool("embedResource", False)
408 genGettext
= conf
.localconf
.ReadBool("genGettext", False)
409 self
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
)
411 self
.SetStatusText('Data saved')
412 self
.SaveRecent(path
)
414 self
.SetStatusText('Failed')
418 def SaveRecent(self
,path
):
419 # append to recently used files
420 if path
not in conf
.recentfiles
.values():
422 self
.recentMenu
.Append(newid
, path
)
423 wx
.EVT_MENU(self
, newid
, self
.OnRecentFile
)
424 conf
.recentfiles
[newid
] = path
426 def GeneratePython(self
, dataFile
, pypath
, embed
, genGettext
):
428 import wx
.tools
.pywxrc
429 rescomp
= wx
.tools
.pywxrc
.XmlResourceCompiler()
430 rescomp
.MakePythonModule([dataFile
], pypath
, embed
, genGettext
)
433 wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
434 wx
.LogError('Error generating python code : %s' % pypath
)
438 def OnGeneratePython(self
, evt
):
439 if self
.modified
or not conf
.localconf
:
440 wx
.MessageBox("Save the XRC file first!", "Error")
443 dlg
= PythonOptions(self
, conf
.localconf
, self
.dataFile
)
448 def OnExit(self
, evt
):
451 def OnUndo(self
, evt
):
452 # Extra check to not mess with idle updating
453 if undoMan
.CanUndo():
456 def OnRedo(self
, evt
):
457 if undoMan
.CanRedo():
460 def OnCopy(self
, evt
):
461 selected
= tree
.selection
462 if not selected
: return # key pressed event
463 xxx
= tree
.GetPyData(selected
)
464 if wx
.TheClipboard
.Open():
465 data
= wx
.CustomDataObject('XRCED')
466 # Set encoding in header
468 s
= xxx
.element
.toxml(encoding
=expat
.native_encoding
)
469 data
.SetData(cPickle
.dumps(s
))
470 wx
.TheClipboard
.SetData(data
)
471 wx
.TheClipboard
.Close()
472 self
.SetStatusText('Copied')
474 wx
.MessageBox("Unable to open the clipboard", "Error")
476 def OnPaste(self
, evt
):
477 selected
= tree
.selection
478 if not selected
: return # key pressed event
479 # For pasting with Ctrl pressed
481 if evt
.GetId() == pullDownMenu
.ID_PASTE_SIBLING
: appendChild
= False
482 elif evt
.GetId() == self
.ID_TOOL_PASTE
:
483 if g
.tree
.ctrl
: appendChild
= False
484 else: appendChild
= not tree
.NeedInsert(selected
)
485 else: appendChild
= not tree
.NeedInsert(selected
)
486 xxx
= tree
.GetPyData(selected
)
488 # If has next item, insert, else append to parent
489 nextItem
= tree
.GetNextSibling(selected
)
490 parentLeaf
= tree
.GetItemParent(selected
)
491 # Expanded container (must have children)
492 elif tree
.IsExpanded(selected
) and tree
.GetChildrenCount(selected
, False):
493 # Insert as first child
494 nextItem
= tree
.GetFirstChild(selected
)[0]
495 parentLeaf
= selected
497 # No children or unexpanded item - appendChild stays True
498 nextItem
= wx
.TreeItemId() # no next item
499 parentLeaf
= selected
500 parent
= tree
.GetPyData(parentLeaf
).treeObject()
502 # Create a copy of clipboard pickled element
504 if wx
.TheClipboard
.Open():
505 data
= wx
.CustomDataObject('XRCED')
506 if wx
.TheClipboard
.IsSupported(data
.GetFormat()):
507 success
= wx
.TheClipboard
.GetData(data
)
508 wx
.TheClipboard
.Close()
512 "There is no data in the clipboard in the required format",
516 xml
= cPickle
.loads(data
.GetData()) # xml representation of element
517 elem
= minidom
.parseString(xml
).childNodes
[0]
518 # Tempopary xxx object to test things
519 xxx
= MakeXXXFromDOM(parent
, elem
)
520 # Check compatibility
524 if x
.__class
__ in [xxxDialog
, xxxFrame
, xxxWizard
]:
526 if parent
.__class
__ != xxxMainNode
: error
= True
527 elif x
.__class
__ == xxxMenuBar
:
528 # Menubar can be put in frame or dialog
529 if parent
.__class
__ not in [xxxMainNode
, xxxFrame
, xxxDialog
]: error
= True
530 elif x
.__class
__ == xxxToolBar
:
531 # Toolbar can be top-level of child of panel or frame
532 if parent
.__class
__ not in [xxxMainNode
, xxxPanel
, xxxFrame
] and \
533 not parent
.isSizer
: error
= True
534 elif x
.__class
__ == xxxPanel
and parent
.__class
__ == xxxMainNode
:
536 elif x
.__class
__ == xxxSpacer
:
537 if not parent
.isSizer
: error
= True
538 elif x
.__class
__ == xxxSeparator
:
539 if not parent
.__class
__ in [xxxMenu
, xxxToolBar
]: error
= True
540 elif x
.__class
__ == xxxTool
:
541 if parent
.__class
__ != xxxToolBar
: error
= True
542 elif x
.__class
__ == xxxMenu
:
543 if not parent
.__class
__ in [xxxMainNode
, xxxMenuBar
, xxxMenu
]: error
= True
544 elif x
.__class
__ == xxxMenuItem
:
545 if not parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= True
546 elif x
.isSizer
and parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
]:
548 else: # normal controls can be almost anywhere
549 if parent
.__class
__ == xxxMainNode
or \
550 parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= True
552 if parent
.__class
__ == xxxMainNode
: parentClass
= 'root'
553 else: parentClass
= parent
.className
554 wx
.LogError('Incompatible parent/child: parent is %s, child is %s!' %
555 (parentClass
, x
.className
))
558 # Check parent and child relationships.
559 # If parent is sizer or notebook, child is of wrong class or
560 # parent is normal window, child is child container then detach child.
561 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
562 parentIsBook
= parent
.__class
__ in [xxxNotebook
, xxxChoicebook
, xxxListbook
]
563 if isChildContainer
and \
564 ((parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
565 (parentIsBook
and not isinstance(xxx
, xxxPage
)) or \
566 not (parent
.isSizer
or parentIsBook
)):
567 elem
.removeChild(xxx
.child
.element
) # detach child
568 elem
.unlink() # delete child container
569 elem
= xxx
.child
.element
# replace
570 # This may help garbage collection
571 xxx
.child
.parent
= None
572 isChildContainer
= False
573 # Parent is sizer or notebook, child is not child container
574 if parent
.isSizer
and not isChildContainer
and not isinstance(xxx
, xxxSpacer
):
575 # Create sizer item element
576 sizerItemElem
= MakeEmptyDOM(parent
.itemTag
)
577 sizerItemElem
.appendChild(elem
)
579 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
580 pageElem
= MakeEmptyDOM('notebookpage')
581 pageElem
.appendChild(elem
)
583 elif isinstance(parent
, xxxChoicebook
) and not isChildContainer
:
584 pageElem
= MakeEmptyDOM('choicebookpage')
585 pageElem
.appendChild(elem
)
587 elif isinstance(parent
, xxxListbook
) and not isChildContainer
:
588 pageElem
= MakeEmptyDOM('listbookpage')
589 pageElem
.appendChild(elem
)
591 # Insert new node, register undo
592 newItem
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
)
593 undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
))
594 # Scroll to show new item (!!! redundant?)
595 tree
.EnsureVisible(newItem
)
596 tree
.SelectItem(newItem
)
597 if not tree
.IsVisible(newItem
):
598 tree
.ScrollTo(newItem
)
601 if g
.testWin
and tree
.IsHighlatable(newItem
):
603 tree
.needUpdate
= True
604 tree
.pendingHighLight
= newItem
606 tree
.pendingHighLight
= None
608 self
.SetStatusText('Pasted')
611 def OnCutDelete(self
, evt
):
612 selected
= tree
.selection
613 if not selected
: return # key pressed event
615 if evt
.GetId() == wx
.ID_CUT
:
617 status
= 'Removed to clipboard'
619 self
.lastOp
= 'DELETE'
623 # If deleting top-level item, delete testWin
624 if selected
== g
.testWin
.item
:
628 # Remove highlight, update testWin
629 if g
.testWin
.highLight
:
630 g
.testWin
.highLight
.Remove()
631 tree
.needUpdate
= True
634 index
= tree
.ItemFullIndex(selected
)
635 parent
= tree
.GetPyData(tree
.GetItemParent(selected
)).treeObject()
636 elem
= tree
.RemoveLeaf(selected
)
637 undoMan
.RegisterUndo(UndoCutDelete(index
, parent
, elem
))
638 if evt
.GetId() == wx
.ID_CUT
:
639 if wx
.TheClipboard
.Open():
640 data
= wx
.CustomDataObject('XRCED')
642 s
= elem
.toxml(encoding
=expat
.native_encoding
)
643 data
.SetData(cPickle
.dumps(s
))
644 wx
.TheClipboard
.SetData(data
)
645 wx
.TheClipboard
.Close()
647 wx
.MessageBox("Unable to open the clipboard", "Error")
648 tree
.pendingHighLight
= None
650 tree
.selection
= None
655 self
.SetStatusText(status
)
657 def OnSubclass(self
, evt
):
658 selected
= tree
.selection
659 xxx
= tree
.GetPyData(selected
).treeObject()
661 subclass
= xxx
.subclass
662 dlg
= wx
.TextEntryDialog(self
, 'Subclass:', defaultValue
=subclass
)
663 if dlg
.ShowModal() == wx
.ID_OK
:
664 subclass
= dlg
.GetValue()
666 elem
.setAttribute('subclass', subclass
)
667 elif elem
.hasAttribute('subclass'):
668 elem
.removeAttribute('subclass')
670 xxx
.subclass
= elem
.getAttribute('subclass')
671 tree
.SetItemText(selected
, xxx
.treeName())
672 panel
.pages
[0].box
.SetLabel(xxx
.panelName())
675 def OnEmbedPanel(self
, evt
):
676 conf
.embedPanel
= evt
.IsChecked()
678 # Remember last dimentions
679 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
680 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
681 size
= self
.GetSize()
682 pos
= self
.GetPosition()
683 sizePanel
= panel
.GetSize()
684 panel
.Reparent(self
.splitter
)
685 self
.miniFrame
.GetSizer().Remove(panel
)
687 self
.SetDimensions(pos
.x
, pos
.y
, size
.width
+ sizePanel
.width
, size
.height
)
688 self
.splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
689 self
.miniFrame
.Show(False)
691 conf
.sashPos
= self
.splitter
.GetSashPosition()
692 pos
= self
.GetPosition()
693 size
= self
.GetSize()
694 sizePanel
= panel
.GetSize()
695 self
.splitter
.Unsplit(panel
)
696 sizer
= self
.miniFrame
.GetSizer()
697 panel
.Reparent(self
.miniFrame
)
699 sizer
.Add(panel
, 1, wx
.EXPAND
)
700 self
.miniFrame
.Show(True)
701 self
.miniFrame
.SetDimensions(conf
.panelX
, conf
.panelY
,
702 conf
.panelWidth
, conf
.panelHeight
)
704 self
.SetDimensions(pos
.x
, pos
.y
,
705 max(size
.width
- sizePanel
.width
, self
.minWidth
), size
.height
)
707 def OnShowTools(self
, evt
):
708 conf
.showTools
= evt
.IsChecked()
709 g
.tools
.Show(conf
.showTools
)
711 self
.toolsSizer
.Prepend(g
.tools
, 0, wx
.EXPAND
)
713 self
.toolsSizer
.Remove(g
.tools
)
714 self
.toolsSizer
.Layout()
716 def OnTest(self
, evt
):
717 if not tree
.selection
: return # key pressed event
718 tree
.ShowTestWindow(tree
.selection
)
720 def OnTestHide(self
, evt
):
721 tree
.CloseTestWindow()
723 # Find object by relative position
724 def FindObject(self
, item
, obj
):
725 # We simply perform depth-first traversal, sinse it's too much
726 # hassle to deal with all sizer/window combinations
727 w
= tree
.FindNodeObject(item
)
728 if w
== obj
or isinstance(w
, wx
.GBSizerItem
) and w
.GetWindow() == obj
:
730 if tree
.ItemHasChildren(item
):
731 child
= tree
.GetFirstChild(item
)[0]
733 found
= self
.FindObject(child
, obj
)
734 if found
: return found
735 child
= tree
.GetNextSibling(child
)
738 def OnTestWinLeftDown(self
, evt
):
739 pos
= evt
.GetPosition()
740 self
.SetHandler(g
.testWin
)
741 g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
)
742 item
= self
.FindObject(g
.testWin
.item
, evt
.GetEventObject())
744 tree
.EnsureVisible(item
)
745 tree
.SelectItem(item
)
746 self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, False)
748 self
.SetStatusText('Selected %s' % tree
.GetItemText(item
))
750 self
.SetStatusText('Locate failed!')
752 def SetHandler(self
, w
, h
=None):
755 w
.SetCursor(wx
.CROSS_CURSOR
)
758 w
.SetCursor(wx
.NullCursor
)
759 for ch
in w
.GetChildren():
760 self
.SetHandler(ch
, h
)
762 def OnLocate(self
, evt
):
764 if evt
.GetId() == self
.ID_LOCATE
or \
765 evt
.GetId() == self
.ID_TOOL_LOCATE
and evt
.IsChecked():
766 self
.SetHandler(g
.testWin
, g
.testWin
)
767 g
.testWin
.Connect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
, self
.OnTestWinLeftDown
)
768 if evt
.GetId() == self
.ID_LOCATE
:
769 self
.tb
.ToggleTool(self
.ID_TOOL_LOCATE
, True)
770 elif evt
.GetId() == self
.ID_TOOL_LOCATE
and not evt
.IsChecked():
771 self
.SetHandler(g
.testWin
, None)
772 g
.testWin
.Disconnect(wx
.ID_ANY
, wx
.ID_ANY
, wx
.wxEVT_LEFT_DOWN
)
773 self
.SetStatusText('Click somewhere in your test window now')
775 def OnRefresh(self
, evt
):
776 # If modified, apply first
777 selection
= tree
.selection
779 xxx
= tree
.GetPyData(selection
)
780 if xxx
and panel
.IsModified():
781 tree
.Apply(xxx
, selection
)
784 tree
.CreateTestWin(g
.testWin
.item
)
785 panel
.modified
= False
786 tree
.needUpdate
= False
788 def OnAutoRefresh(self
, evt
):
789 conf
.autoRefresh
= evt
.IsChecked()
790 self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
791 self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
793 def OnAbout(self
, evt
):
797 (c) Roman Rolinsky <rollrom@users.sourceforge.net>
798 Homepage: http://xrced.sourceforge.net\
800 dlg
= wx
.MessageDialog(self
, str, 'About XRCed', wx
.OK | wx
.CENTRE
)
804 def OnReadme(self
, evt
):
805 text
= open(os
.path
.join(basePath
, 'README.txt'), 'r').read()
806 dlg
= ScrolledMessageDialog(self
, text
, "XRCed README")
810 # Simple emulation of python command line
811 def OnDebugCMD(self
, evt
):
814 exec raw_input('C:\> ')
819 (etype
, value
, tb
) =sys
.exc_info()
820 tblist
=traceback
.extract_tb(tb
)[1:]
821 msg
=' '.join(traceback
.format_exception_only(etype
, value
)
822 +traceback
.format_list(tblist
))
825 def OnCreate(self
, evt
):
826 selected
= tree
.selection
827 if tree
.ctrl
: appendChild
= False
828 else: appendChild
= not tree
.NeedInsert(selected
)
829 xxx
= tree
.GetPyData(selected
)
833 # If has previous item, insert after it, else append to parent
835 parentLeaf
= tree
.GetItemParent(selected
)
837 # If has next item, insert, else append to parent
838 nextItem
= tree
.GetNextSibling(selected
)
839 parentLeaf
= tree
.GetItemParent(selected
)
840 # Expanded container (must have children)
841 elif tree
.shift
and tree
.IsExpanded(selected
) \
842 and tree
.GetChildrenCount(selected
, False):
843 nextItem
= tree
.GetFirstChild(selected
)[0]
844 parentLeaf
= selected
846 nextItem
= wx
.TreeItemId()
847 parentLeaf
= selected
848 parent
= tree
.GetPyData(parentLeaf
)
849 if parent
.hasChild
: parent
= parent
.child
852 if evt
.GetId() == ID_NEW
.REF
:
853 ref
= wx
.GetTextFromUser('Create reference to:', 'Create reference')
855 xxx
= MakeEmptyRefXXX(parent
, ref
)
857 # Create empty element
858 className
= pullDownMenu
.createMap
[evt
.GetId()]
859 xxx
= MakeEmptyXXX(parent
, className
)
861 # Set default name for top-level windows
862 if parent
.__class
__ == xxxMainNode
:
863 cl
= xxx
.treeObject().__class
__
864 frame
.maxIDs
[cl
] += 1
865 xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
]))
866 # And for some other standard controls
867 elif parent
.__class
__ == xxxStdDialogButtonSizer
:
868 xxx
.setTreeName(pullDownMenu
.stdButtonIDs
[evt
.GetId()][0])
869 # We can even set label
870 obj
= xxx
.treeObject()
871 elem
= g
.tree
.dom
.createElement('label')
872 elem
.appendChild(g
.tree
.dom
.createTextNode(pullDownMenu
.stdButtonIDs
[evt
.GetId()][1]))
873 obj
.params
['label'] = xxxParam(elem
)
874 xxx
.treeObject().element
.appendChild(elem
)
876 # Insert new node, register undo
878 newItem
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
)
879 undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
))
880 tree
.EnsureVisible(newItem
)
881 tree
.SelectItem(newItem
)
882 if not tree
.IsVisible(newItem
):
883 tree
.ScrollTo(newItem
)
886 if g
.testWin
and tree
.IsHighlatable(newItem
):
888 tree
.needUpdate
= True
889 tree
.pendingHighLight
= newItem
891 tree
.pendingHighLight
= None
895 # Replace one object with another
896 def OnReplace(self
, evt
):
897 selected
= tree
.selection
898 xxx
= tree
.GetPyData(selected
).treeObject()
900 parent
= elem
.parentNode
901 undoMan
.RegisterUndo(UndoReplace(selected
))
903 className
= pullDownMenu
.createMap
[evt
.GetId() - 1000]
904 # Create temporary empty node (with default values)
905 dummy
= MakeEmptyDOM(className
)
906 if className
== 'spacer' and xxx
.className
!= 'spacer':
908 elif xxx
.className
== 'spacer' and className
!= 'spacer':
911 klass
= xxxDict
[className
]
912 # Remove non-compatible children
913 if tree
.ItemHasChildren(selected
) and not klass
.hasChildren
:
914 tree
.DeleteChildren(selected
)
915 nodes
= elem
.childNodes
[:]
918 if node
.nodeType
!= minidom
.Node
.ELEMENT_NODE
: continue
922 if not klass
.hasChildren
: remove
= True
923 elif tag
not in klass
.allParams
and \
924 (not klass
.hasStyle
or tag
not in klass
.styles
):
929 elem
.removeChild(node
)
932 # Remove sizeritem child if spacer
933 if className
== 'spacer' and xxx
.className
!= 'spacer':
934 sizeritem
= elem
.parentNode
935 assert sizeritem
.getAttribute('class') == 'sizeritem'
936 sizeritem
.removeChild(elem
)
939 tree
.GetPyData(selected
).hasChild
= false
940 elif xxx
.className
== 'spacer' and className
!= 'spacer':
941 # Create sizeritem element
942 assert xxx
.parent
.isSizer
943 elem
.setAttribute('class', 'sizeritem')
944 node
= MakeEmptyDOM(className
)
945 elem
.appendChild(node
)
946 # Replace to point to new object
947 xxx
= xxxSizerItem(xxx
.parent
, elem
)
949 tree
.SetPyData(selected
, xxx
)
952 # Copy parameters present in dummy but not in elem
953 for node
in dummy
.childNodes
:
954 if node
.tagName
not in tags
: elem
.appendChild(node
.cloneNode(True))
958 elem
.setAttribute('class', className
)
959 if elem
.hasAttribute('subclass'):
960 elem
.removeAttribute('subclass') # clear subclassing
961 # Re-create xxx element
962 xxx
= MakeXXXFromDOM(xxx
.parent
, elem
)
963 # Update parent in child objects
964 if tree
.ItemHasChildren(selected
):
965 i
, cookie
= tree
.GetFirstChild(selected
)
967 x
= tree
.GetPyData(i
)
969 if x
.hasChild
: x
.child
.parent
= xxx
970 i
, cookie
= tree
.GetNextChild(selected
, cookie
)
973 if tree
.GetPyData(selected
).hasChild
: # child container
974 container
= tree
.GetPyData(selected
)
975 container
.child
= xxx
976 container
.hasChildren
= xxx
.hasChildren
977 container
.isSizer
= xxx
.isSizer
980 tree
.SetPyData(selected
, xxx
)
981 tree
.SetItemText(selected
, xxx
.treeName())
982 tree
.SetItemImage(selected
, xxx
.treeImage())
984 # Set default name for top-level windows
985 if parent
.__class
__ == xxxMainNode
:
986 cl
= xxx
.treeObject().__class
__
987 frame
.maxIDs
[cl
] += 1
988 xxx
.setTreeName('%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
]))
995 #undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
997 if g
.testWin
and tree
.IsHighlatable(selected
):
999 tree
.needUpdate
= True
1000 tree
.pendingHighLight
= selected
1002 tree
.pendingHighLight
= None
1006 # Expand/collapse subtree
1007 def OnExpand(self
, evt
):
1008 if tree
.selection
: tree
.ExpandAll(tree
.selection
)
1009 else: tree
.ExpandAll(tree
.root
)
1010 def OnCollapse(self
, evt
):
1011 if tree
.selection
: tree
.CollapseAll(tree
.selection
)
1012 else: tree
.CollapseAll(tree
.root
)
1014 def OnPullDownHighlight(self
, evt
):
1015 menuId
= evt
.GetMenuId()
1017 menu
= evt
.GetEventObject()
1018 help = menu
.GetHelpString(menuId
)
1019 self
.SetStatusText(help)
1021 self
.SetStatusText('')
1023 def OnUpdateUI(self
, evt
):
1024 if evt
.GetId() in [wx
.ID_CUT
, wx
.ID_COPY
, self
.ID_DELETE
]:
1025 evt
.Enable(tree
.selection
is not None and tree
.selection
!= tree
.root
)
1026 elif evt
.GetId() == wx
.ID_SAVE
:
1027 evt
.Enable(self
.modified
)
1028 elif evt
.GetId() in [wx
.ID_PASTE
, self
.ID_TOOL_PASTE
]:
1029 evt
.Enable(tree
.selection
is not None)
1030 elif evt
.GetId() == self
.ID_TEST
:
1031 evt
.Enable(tree
.selection
is not None and tree
.selection
!= tree
.root
)
1032 elif evt
.GetId() in [self
.ID_LOCATE
, self
.ID_TOOL_LOCATE
]:
1033 evt
.Enable(g
.testWin
is not None)
1034 elif evt
.GetId() == wx
.ID_UNDO
: evt
.Enable(undoMan
.CanUndo())
1035 elif evt
.GetId() == wx
.ID_REDO
: evt
.Enable(undoMan
.CanRedo())
1037 def OnIdle(self
, evt
):
1038 if self
.inIdle
: return # Recursive call protection
1042 if conf
.autoRefresh
:
1044 self
.SetStatusText('Refreshing test window...')
1046 tree
.CreateTestWin(g
.testWin
.item
)
1047 self
.SetStatusText('')
1048 tree
.needUpdate
= False
1049 elif tree
.pendingHighLight
:
1051 tree
.HighLight(tree
.pendingHighLight
)
1053 # Remove highlight if any problem
1054 if g
.testWin
.highLight
:
1055 g
.testWin
.highLight
.Remove()
1056 tree
.pendingHighLight
= None
1063 # We don't let close panel window
1064 def OnCloseMiniFrame(self
, evt
):
1067 def OnIconize(self
, evt
):
1068 conf
.x
, conf
.y
= self
.GetPosition()
1069 conf
.width
, conf
.height
= self
.GetSize()
1071 conf
.sashPos
= self
.splitter
.GetSashPosition()
1073 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
1074 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
1075 self
.miniFrame
.Iconize()
1078 def OnCloseWindow(self
, evt
):
1079 if not self
.AskSave(): return
1080 if g
.testWin
: g
.testWin
.Destroy()
1081 if not panel
.GetPageCount() == 2:
1082 panel
.page2
.Destroy()
1084 # If we don't do this, page does not get destroyed (a bug?)
1086 if not self
.IsIconized():
1087 conf
.x
, conf
.y
= self
.GetPosition()
1088 conf
.width
, conf
.height
= self
.GetSize()
1090 conf
.sashPos
= self
.splitter
.GetSashPosition()
1092 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
1093 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
1097 def CreateLocalConf(self
, path
):
1098 name
= os
.path
.splitext(path
)[0]
1100 return wx
.FileConfig(localFilename
=name
)
1105 conf
.localconf
= None
1107 self
.SetModified(False)
1113 # Numbers for new controls
1115 for cl
in [xxxPanel
, xxxDialog
, xxxFrame
,
1116 xxxMenuBar
, xxxMenu
, xxxToolBar
,
1117 xxxWizard
, xxxBitmap
, xxxIcon
]:
1120 def SetModified(self
, state
=True):
1121 self
.modified
= state
1122 name
= os
.path
.basename(self
.dataFile
)
1123 if not name
: name
= defaultName
1125 self
.SetTitle(progname
+ ': ' + name
+ ' *')
1127 self
.SetTitle(progname
+ ': ' + name
)
1129 def Open(self
, path
):
1130 if not os
.path
.exists(path
):
1131 wx
.LogError('File does not exists: %s' % path
)
1133 # Try to read the file
1137 dom
= minidom
.parse(f
)
1139 # Set encoding global variable and default encoding
1141 g
.currentEncoding
= dom
.encoding
1142 wx
.SetDefaultPyEncoding(g
.currentEncoding
.encode())
1144 g
.currentEncoding
= ''
1146 self
.dataFile
= path
= os
.path
.abspath(path
)
1147 dir = os
.path
.dirname(path
)
1148 if dir: os
.chdir(dir)
1150 self
.SetTitle(progname
+ ': ' + os
.path
.basename(path
))
1151 conf
.localconf
= self
.CreateLocalConf(self
.dataFile
)
1153 # Nice exception printing
1154 inf
= sys
.exc_info()
1155 wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
1156 wx
.LogError('Error reading file: %s' % path
)
1161 def Indent(self
, node
, indent
= 0):
1162 # Copy child list because it will change soon
1163 children
= node
.childNodes
[:]
1164 # Main node doesn't need to be indented
1166 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
1167 node
.parentNode
.insertBefore(text
, node
)
1169 # Append newline after last child, except for text nodes
1170 if children
[-1].nodeType
== minidom
.Node
.ELEMENT_NODE
:
1171 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
1172 node
.appendChild(text
)
1173 # Indent children which are elements
1175 if n
.nodeType
== minidom
.Node
.ELEMENT_NODE
:
1176 self
.Indent(n
, indent
+ 2)
1178 def Save(self
, path
):
1182 if tree
.selection
and panel
.IsModified():
1183 self
.OnRefresh(wx
.CommandEvent())
1184 if g
.currentEncoding
:
1185 f
= codecs
.open(path
, 'wt', g
.currentEncoding
)
1187 f
= codecs
.open(path
, 'wt')
1188 # Make temporary copy for formatting it
1189 # !!! We can't clone dom node, it works only once
1190 #self.domCopy = tree.dom.cloneNode(True)
1191 self
.domCopy
= MyDocument()
1192 mainNode
= self
.domCopy
.appendChild(tree
.mainNode
.cloneNode(True))
1193 # Remove first child (test element)
1194 testElem
= mainNode
.firstChild
1195 mainNode
.removeChild(testElem
)
1197 self
.Indent(mainNode
)
1198 self
.domCopy
.writexml(f
, encoding
= g
.currentEncoding
)
1200 self
.domCopy
.unlink()
1202 self
.SetModified(False)
1203 panel
.SetModified(False)
1204 conf
.localconf
.Flush()
1206 inf
= sys
.exc_info()
1207 wx
.LogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
1208 wx
.LogError('Error writing file: %s' % path
)
1212 if not (self
.modified
or panel
.IsModified()): return True
1213 flags
= wx
.ICON_EXCLAMATION | wx
.YES_NO | wx
.CANCEL | wx
.CENTRE
1214 dlg
= wx
.MessageDialog( self
, 'File is modified. Save before exit?',
1215 'Save before too late?', flags
)
1216 say
= dlg
.ShowModal()
1219 if say
== wx
.ID_YES
:
1220 self
.OnSaveOrSaveAs(wx
.CommandEvent(wx
.ID_SAVE
))
1221 # If save was successful, modified flag is unset
1222 if not self
.modified
: return True
1223 elif say
== wx
.ID_NO
:
1224 self
.SetModified(False)
1225 panel
.SetModified(False)
1232 ################################################################################
1234 class PythonOptions(wx
.Dialog
):
1236 def __init__(self
, parent
, cfg
, dataFile
):
1237 pre
= wx
.PreDialog()
1238 g
.frame
.res
.LoadOnDialog(pre
, parent
, "PYTHON_OPTIONS")
1239 self
.PostCreate(pre
)
1242 self
.dataFile
= dataFile
1244 self
.AutoGenerateCB
= xrc
.XRCCTRL(self
, "AutoGenerateCB")
1245 self
.EmbedCB
= xrc
.XRCCTRL(self
, "EmbedCB")
1246 self
.GettextCB
= xrc
.XRCCTRL(self
, "GettextCB")
1247 self
.MakeXRSFileCB
= xrc
.XRCCTRL(self
, "MakeXRSFileCB")
1248 self
.FileNameTC
= xrc
.XRCCTRL(self
, "FileNameTC")
1249 self
.BrowseBtn
= xrc
.XRCCTRL(self
, "BrowseBtn")
1250 self
.GenerateBtn
= xrc
.XRCCTRL(self
, "GenerateBtn")
1251 self
.SaveOptsBtn
= xrc
.XRCCTRL(self
, "SaveOptsBtn")
1253 self
.Bind(wx
.EVT_BUTTON
, self
.OnBrowse
, self
.BrowseBtn
)
1254 self
.Bind(wx
.EVT_BUTTON
, self
.OnGenerate
, self
.GenerateBtn
)
1255 self
.Bind(wx
.EVT_BUTTON
, self
.OnSaveOpts
, self
.SaveOptsBtn
)
1257 if self
.cfg
.Read("filename", "") != "":
1258 self
.FileNameTC
.SetValue(self
.cfg
.Read("filename"))
1260 name
= os
.path
.splitext(dataFile
)[0]
1262 self
.FileNameTC
.SetValue(name
)
1263 self
.AutoGenerateCB
.SetValue(self
.cfg
.ReadBool("autogenerate", False))
1264 self
.EmbedCB
.SetValue(self
.cfg
.ReadBool("embedResource", False))
1265 self
.MakeXRSFileCB
.SetValue(self
.cfg
.ReadBool("makeXRS", False))
1266 self
.GettextCB
.SetValue(self
.cfg
.ReadBool("genGettext", False))
1269 def OnBrowse(self
, evt
):
1270 path
= self
.FileNameTC
.GetValue()
1271 dirname
= os
.path
.abspath(os
.path
.dirname(path
))
1272 name
= os
.path
.split(path
)[1]
1273 dlg
= wx
.FileDialog(self
, 'Save As', dirname
, name
, '*.py',
1274 wx
.SAVE | wx
.OVERWRITE_PROMPT
)
1275 if dlg
.ShowModal() == wx
.ID_OK
:
1276 path
= dlg
.GetPath()
1277 self
.FileNameTC
.SetValue(path
)
1281 def OnGenerate(self
, evt
):
1282 pypath
= self
.FileNameTC
.GetValue()
1283 embed
= self
.EmbedCB
.GetValue()
1284 genGettext
= self
.GettextCB
.GetValue()
1285 frame
.GeneratePython(self
.dataFile
, pypath
, embed
, genGettext
)
1289 def OnSaveOpts(self
, evt
=None):
1290 self
.cfg
.Write("filename", self
.FileNameTC
.GetValue())
1291 self
.cfg
.WriteBool("autogenerate", self
.AutoGenerateCB
.GetValue())
1292 self
.cfg
.WriteBool("embedResource", self
.EmbedCB
.GetValue())
1293 self
.cfg
.WriteBool("makeXRS", self
.MakeXRSFileCB
.GetValue())
1294 self
.cfg
.WriteBool("genGettext", self
.GettextCB
.GetValue())
1296 self
.EndModal(wx
.ID_OK
)
1299 ################################################################################
1302 print >> sys
.stderr
, 'usage: xrced [-dhiv] [file]'
1307 if wx
.VERSION
[:3] < MinWxVersion
:
1309 This version of XRCed may not work correctly on your version of wxWidgets. \
1310 Please upgrade wxWidgets to %d.%d.%d or higher.''' % MinWxVersion
)
1312 # Process comand-line
1315 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'dhiv')
1323 print 'XRCed version', version
1326 except getopt
.GetoptError
:
1327 if wx
.Platform
!= '__WXMAC__': # macs have some extra parameters
1328 print >> sys
.stderr
, 'Unknown option'
1332 self
.SetAppName('xrced')
1335 conf
= g
.conf
= wx
.Config(style
= wx
.CONFIG_USE_LOCAL_FILE
)
1336 conf
.localconf
= None
1337 conf
.autoRefresh
= conf
.ReadInt('autorefresh', True)
1338 pos
= conf
.ReadInt('x', -1), conf
.ReadInt('y', -1)
1339 size
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600)
1340 conf
.embedPanel
= conf
.ReadInt('embedPanel', True)
1341 conf
.showTools
= conf
.ReadInt('showTools', True)
1342 conf
.sashPos
= conf
.ReadInt('sashPos', 200)
1343 # read recently used files
1344 recentfiles
=conf
.Read('recentFiles','')
1347 for fil
in recentfiles
.split('|'):
1348 conf
.recentfiles
[wx
.NewId()]=fil
1349 if not conf
.embedPanel
:
1350 conf
.panelX
= conf
.ReadInt('panelX', -1)
1351 conf
.panelY
= conf
.ReadInt('panelY', -1)
1353 conf
.panelX
= conf
.panelY
= -1
1354 conf
.panelWidth
= conf
.ReadInt('panelWidth', 200)
1355 conf
.panelHeight
= conf
.ReadInt('panelHeight', 200)
1356 conf
.panic
= not conf
.HasEntry('nopanic')
1358 wx
.FileSystem
.AddHandler(wx
.MemoryFSHandler())
1360 frame
= Frame(pos
, size
)
1363 # Load file after showing
1366 frame
.open = frame
.Open(args
[0])
1374 wc
.WriteInt('autorefresh', conf
.autoRefresh
)
1375 wc
.WriteInt('x', conf
.x
)
1376 wc
.WriteInt('y', conf
.y
)
1377 wc
.WriteInt('width', conf
.width
)
1378 wc
.WriteInt('height', conf
.height
)
1379 wc
.WriteInt('embedPanel', conf
.embedPanel
)
1380 wc
.WriteInt('showTools', conf
.showTools
)
1381 if not conf
.embedPanel
:
1382 wc
.WriteInt('panelX', conf
.panelX
)
1383 wc
.WriteInt('panelY', conf
.panelY
)
1384 wc
.WriteInt('sashPos', conf
.sashPos
)
1385 wc
.WriteInt('panelWidth', conf
.panelWidth
)
1386 wc
.WriteInt('panelHeight', conf
.panelHeight
)
1387 wc
.WriteInt('nopanic', True)
1388 wc
.Write('recentFiles', '|'.join(conf
.recentfiles
.values()[-5:]))
1392 app
= App(0, useBestVisual
=False)
1393 #app.SetAssertMode(wx.PYAPP_ASSERT_LOG)
1399 if __name__
== '__main__':