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