]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/tools/XRCed/xrced.py
4945d3dde8a2a24e9113d6ed898d10e7175d53f8
[wxWidgets.git] / wxPython / wx / tools / XRCed / xrced.py
1 # Name: xrced.py
2 # Purpose: XRC editor, main module
3 # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
4 # Created: 20.08.2001
5 # RCS-ID: $Id$
6
7 """
8
9 xrced -- Simple resource editor for XRC format used by wxWidgets/wxPython
10 GUI toolkit.
11
12 Usage:
13
14 xrced [ -h ] [ -v ] [ XRC-file ]
15
16 Options:
17
18 -h output short usage info and exit
19
20 -v output version info and exit
21 """
22
23 from globals import *
24 import os, sys, getopt, re, traceback, tempfile, shutil, cPickle
25 from xml.parsers import expat
26
27 # Local modules
28 from tree import * # imports xxx which imports params
29 from panel import *
30 from tools import *
31 from params import genericStyles
32 # Cleanup recursive import sideeffects, otherwise we can't create undoMan
33 import undo
34 undo.ParamPage = ParamPage
35 undoMan = g.undoMan = UndoManager()
36
37 # Set application path for loading resources
38 if __name__ == '__main__':
39 basePath = os.path.dirname(sys.argv[0])
40 else:
41 basePath = os.path.dirname(__file__)
42
43 # Remember system path
44 sys_path = sys.path
45
46 # 1 adds CMD command to Help menu
47 debug = 0
48
49 g.helpText = """\
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>
58 """
59
60 defaultIDs = {xxxPanel:'PANEL', xxxDialog:'DIALOG', xxxFrame:'FRAME',
61 xxxMenuBar:'MENUBAR', xxxMenu:'MENU', xxxToolBar:'TOOLBAR',
62 xxxWizard:'WIZARD', xxxBitmap:'BITMAP', xxxIcon:'ICON'}
63
64 defaultName = 'UNTITLED.xrc'
65
66 ################################################################################
67
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")
79 ok.SetDefault()
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)
85 self.Fit()
86 self.CenterOnScreen(wx.BOTH)
87
88 ################################################################################
89
90 # Event handler for using during location
91 class Locator(wx.EvtHandler):
92 def ProcessEvent(self, evt):
93 print evt
94
95 class TaskBarIcon(wx.TaskBarIcon):
96 def __init__(self, frame):
97 wx.TaskBarIcon.__init__(self)
98 self.frame = frame
99 # Set the image
100 self.SetIcon(images.getIconIcon(), "XRCed")
101
102 class Frame(wx.Frame):
103 def __init__(self, pos, size):
104 pre = wx.PreFrame()
105 # pre.SetExtraStyle(wx.FRAME_EX_METAL)
106 pre.Create(None, -1, '', pos, size)
107 self.PostCreate(pre)
108 #wx.Frame.__init__(self, None, -1, '', pos, size)
109 global frame
110 frame = g.frame = self
111 bar = self.CreateStatusBar(2)
112 bar.SetStatusWidths([-1, 40])
113 self.SetIcon(images.getIconIcon())
114 try:
115 self.tbicon = TaskBarIcon(self)
116 except:
117 self.tbicon = None
118
119 # Idle flag
120 self.inIdle = False
121
122 # Load our own resources
123 self.res = xrc.EmptyXmlResource()
124 # !!! Blocking of assert failure occurring in older unicode builds
125 try:
126 quietlog = wx.LogNull()
127 self.res.Load(os.path.join(basePath, 'xrced.xrc'))
128 except wx._core.PyAssertionError:
129 print 'PyAssertionError was ignored'
130
131 # Make menus
132 menuBar = wx.MenuBar()
133
134 menu = wx.Menu()
135 menu.Append(wx.ID_NEW, '&New\tCtrl-N', 'New file')
136 menu.AppendSeparator()
137 menu.Append(wx.ID_OPEN, '&Open...\tCtrl-O', 'Open XRC file')
138
139 self.recentMenu = wx.Menu()
140 g.fileHistory.UseMenu(self.recentMenu)
141 g.fileHistory.AddFilesToMenu()
142 self.Bind(wx.EVT_MENU, self.OnRecentFile, id=wx.ID_FILE1, id2=wx.ID_FILE9)
143 menu.AppendMenu(-1, 'Open &Recent', self.recentMenu, 'Open a recent file')
144
145 menu.AppendSeparator()
146 menu.Append(wx.ID_SAVE, '&Save\tCtrl-S', 'Save XRC file')
147 menu.Append(wx.ID_SAVEAS, 'Save &As...', 'Save XRC file under different name')
148 self.ID_GENERATE_PYTHON = wx.NewId()
149 menu.Append(self.ID_GENERATE_PYTHON, '&Generate Python...',
150 'Generate a Python module that uses this XRC')
151 menu.AppendSeparator()
152 self.ID_PREFS = wx.NewId()
153 menu.Append(self.ID_PREFS, 'Preferences...', 'Change XRCed settings')
154 menu.AppendSeparator()
155 menu.Append(wx.ID_EXIT, '&Quit\tCtrl-Q', 'Exit application')
156
157 menuBar.Append(menu, '&File')
158
159 menu = wx.Menu()
160 menu.Append(wx.ID_UNDO, '&Undo\tCtrl-Z', 'Undo')
161 menu.Append(wx.ID_REDO, '&Redo\tCtrl-Y', 'Redo')
162 menu.AppendSeparator()
163 menu.Append(wx.ID_CUT, 'Cut\tCtrl-X', 'Cut to the clipboard')
164 menu.Append(wx.ID_COPY, '&Copy\tCtrl-C', 'Copy to the clipboard')
165 menu.Append(wx.ID_PASTE, '&Paste\tCtrl-V', 'Paste from the clipboard')
166 self.ID_DELETE = wx.NewId()
167 menu.Append(self.ID_DELETE, '&Delete\tCtrl-D', 'Delete object')
168 menu.AppendSeparator()
169 self.ID_LOCATE = wx.NewId()
170 self.ID_TOOL_LOCATE = wx.NewId()
171 self.ID_TOOL_PASTE = wx.NewId()
172 menu.Append(self.ID_LOCATE, '&Locate\tCtrl-L', 'Locate control in test window and select it')
173 menuBar.Append(menu, '&Edit')
174 menu = wx.Menu()
175 self.ID_EMBED_PANEL = wx.NewId()
176 menu.Append(self.ID_EMBED_PANEL, '&Embed Panel',
177 'Toggle embedding properties panel in the main window', True)
178 menu.Check(self.ID_EMBED_PANEL, conf.embedPanel)
179 self.ID_SHOW_TOOLS = wx.NewId()
180 menu.Append(self.ID_SHOW_TOOLS, 'Show &Tools', 'Toggle tools', True)
181 menu.Check(self.ID_SHOW_TOOLS, conf.showTools)
182 menu.AppendSeparator()
183 self.ID_TEST = wx.NewId()
184 menu.Append(self.ID_TEST, '&Test\tF5', 'Show test window')
185 self.ID_REFRESH = wx.NewId()
186 menu.Append(self.ID_REFRESH, '&Refresh\tCtrl-R', 'Refresh test window')
187 self.ID_AUTO_REFRESH = wx.NewId()
188 menu.Append(self.ID_AUTO_REFRESH, '&Auto-refresh\tAlt-A',
189 'Toggle auto-refresh mode', True)
190 menu.Check(self.ID_AUTO_REFRESH, conf.autoRefresh)
191 self.ID_TEST_HIDE = wx.NewId()
192 menu.Append(self.ID_TEST_HIDE, '&Hide\tF6', 'Close test window')
193 menuBar.Append(menu, '&View')
194
195 menu = wx.Menu()
196 self.ID_MOVEUP = wx.NewId()
197 menu.Append(self.ID_MOVEUP, '&Up', 'Move before previous sibling')
198 self.ID_MOVEDOWN = wx.NewId()
199 menu.Append(self.ID_MOVEDOWN, '&Down', 'Move after next sibling')
200 self.ID_MOVELEFT = wx.NewId()
201 menu.Append(self.ID_MOVELEFT, '&Make sibling', 'Make sibling of parent')
202 self.ID_MOVERIGHT = wx.NewId()
203 menu.Append(self.ID_MOVERIGHT, '&Make child', 'Make child of previous sibling')
204 menuBar.Append(menu, '&Move')
205
206 menu = wx.Menu()
207 menu.Append(wx.ID_ABOUT, '&About...', 'About XCRed')
208 self.ID_README = wx.NewId()
209 menu.Append(self.ID_README, '&Readme...\tF1', 'View the README file')
210 if debug:
211 self.ID_DEBUG_CMD = wx.NewId()
212 menu.Append(self.ID_DEBUG_CMD, 'CMD', 'Python command line')
213 wx.EVT_MENU(self, self.ID_DEBUG_CMD, self.OnDebugCMD)
214 menuBar.Append(menu, '&Help')
215
216 self.menuBar = menuBar
217 self.SetMenuBar(menuBar)
218
219 # Create toolbar
220 tb = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT)
221 if wx.Platform != '__WXMAC__':
222 # Redefine AddSeparator on wxGTK and wxMSW to add vertical line
223 def _AddSeparator():
224 tb.AddControl(wx.StaticLine(tb, -1, size=(-1,23),
225 style=wx.LI_VERTICAL))
226 tb.AddSeparator = _AddSeparator
227
228 # Use tango icons and slightly wider bitmap size on Mac
229 if wx.Platform == '__WXMAC__':
230 tb.SetToolBitmapSize((26,26))
231 new_bmp = images.getNewBitmap()
232 open_bmp = images.getOpenBitmap()
233 save_bmp = images.getSaveBitmap()
234 undo_bmp = images.getUndoBitmap()
235 redo_bmp = images.getRedoBitmap()
236 cut_bmp = images.getCutBitmap()
237 copy_bmp = images.getCopyBitmap()
238 paste_bmp = images.getPasteBitmap()
239 else:
240 tb.SetToolBitmapSize((24,24))
241 new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_TOOLBAR)
242 open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR)
243 save_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR)
244 undo_bmp = wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_TOOLBAR)
245 redo_bmp = wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_TOOLBAR)
246 cut_bmp = wx.ArtProvider.GetBitmap(wx.ART_CUT, wx.ART_TOOLBAR)
247 copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR)
248 paste_bmp= wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR)
249 tb.AddSimpleTool(wx.ID_NEW, new_bmp, 'New', 'New file')
250 tb.AddSimpleTool(wx.ID_OPEN, open_bmp, 'Open', 'Open file')
251 tb.AddSimpleTool(wx.ID_SAVE, save_bmp, 'Save', 'Save file')
252 tb.AddSeparator()
253 tb.AddSimpleTool(wx.ID_UNDO, undo_bmp, 'Undo', 'Undo')
254 tb.AddSimpleTool(wx.ID_REDO, redo_bmp, 'Redo', 'Redo')
255 tb.AddSeparator()
256 tb.AddSimpleTool(wx.ID_CUT, cut_bmp, 'Cut', 'Cut')
257 tb.AddSimpleTool(wx.ID_COPY, copy_bmp, 'Copy', 'Copy')
258 tb.AddSimpleTool(self.ID_TOOL_PASTE, paste_bmp, 'Paste', 'Paste')
259 tb.AddSeparator()
260 tb.AddSimpleTool(self.ID_TOOL_LOCATE,
261 images.getLocateBitmap(), #images.getLocateArmedBitmap(),
262 'Locate', 'Locate control in test window and select it', True)
263 tb.AddSimpleTool(self.ID_TEST, images.getTestBitmap(), 'Test', 'Test window')
264 tb.AddSimpleTool(self.ID_REFRESH, images.getRefreshBitmap(),
265 'Refresh', 'Refresh view')
266 tb.AddSimpleTool(self.ID_AUTO_REFRESH, images.getAutoRefreshBitmap(),
267 'Auto-refresh', 'Toggle auto-refresh mode', True)
268 tb.AddSeparator()
269 tb.AddSimpleTool(self.ID_MOVEUP, images.getToolMoveUpBitmap(),
270 'Up', 'Move before previous sibling')
271 tb.AddSimpleTool(self.ID_MOVEDOWN, images.getToolMoveDownBitmap(),
272 'Down', 'Move after next sibling')
273 tb.AddSimpleTool(self.ID_MOVELEFT, images.getToolMoveLeftBitmap(),
274 'Make Sibling', 'Make sibling of parent')
275 tb.AddSimpleTool(self.ID_MOVERIGHT, images.getToolMoveRightBitmap(),
276 'Make Child', 'Make child of previous sibling')
277 tb.ToggleTool(self.ID_AUTO_REFRESH, conf.autoRefresh)
278 tb.Realize()
279
280 self.tb = tb
281 self.minWidth = tb.GetSize()[0] # minimal width is the size of toolbar
282
283 # File
284 wx.EVT_MENU(self, wx.ID_NEW, self.OnNew)
285 wx.EVT_MENU(self, wx.ID_OPEN, self.OnOpen)
286 wx.EVT_MENU(self, wx.ID_SAVE, self.OnSaveOrSaveAs)
287 wx.EVT_MENU(self, wx.ID_SAVEAS, self.OnSaveOrSaveAs)
288 wx.EVT_MENU(self, self.ID_GENERATE_PYTHON, self.OnGeneratePython)
289 wx.EVT_MENU(self, self.ID_PREFS, self.OnPrefs)
290 wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit)
291 # Edit
292 wx.EVT_MENU(self, wx.ID_UNDO, self.OnUndo)
293 wx.EVT_MENU(self, wx.ID_REDO, self.OnRedo)
294 wx.EVT_MENU(self, wx.ID_CUT, self.OnCutDelete)
295 wx.EVT_MENU(self, wx.ID_COPY, self.OnCopy)
296 wx.EVT_MENU(self, wx.ID_PASTE, self.OnPaste)
297 wx.EVT_MENU(self, self.ID_TOOL_PASTE, self.OnPaste)
298 wx.EVT_MENU(self, self.ID_DELETE, self.OnCutDelete)
299 wx.EVT_MENU(self, self.ID_LOCATE, self.OnLocate)
300 wx.EVT_MENU(self, self.ID_TOOL_LOCATE, self.OnLocate)
301 # View
302 wx.EVT_MENU(self, self.ID_EMBED_PANEL, self.OnEmbedPanel)
303 wx.EVT_MENU(self, self.ID_SHOW_TOOLS, self.OnShowTools)
304 wx.EVT_MENU(self, self.ID_TEST, self.OnTest)
305 wx.EVT_MENU(self, self.ID_REFRESH, self.OnRefresh)
306 wx.EVT_MENU(self, self.ID_AUTO_REFRESH, self.OnAutoRefresh)
307 wx.EVT_MENU(self, self.ID_TEST_HIDE, self.OnTestHide)
308 # Move
309 wx.EVT_MENU(self, self.ID_MOVEUP, self.OnMoveUp)
310 wx.EVT_MENU(self, self.ID_MOVEDOWN, self.OnMoveDown)
311 wx.EVT_MENU(self, self.ID_MOVELEFT, self.OnMoveLeft)
312 wx.EVT_MENU(self, self.ID_MOVERIGHT, self.OnMoveRight)
313 # Help
314 wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout)
315 wx.EVT_MENU(self, self.ID_README, self.OnReadme)
316
317 # Update events
318 wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.OnUpdateUI)
319 wx.EVT_UPDATE_UI(self, wx.ID_CUT, self.OnUpdateUI)
320 wx.EVT_UPDATE_UI(self, wx.ID_COPY, self.OnUpdateUI)
321 wx.EVT_UPDATE_UI(self, wx.ID_PASTE, self.OnUpdateUI)
322 wx.EVT_UPDATE_UI(self, self.ID_LOCATE, self.OnUpdateUI)
323 wx.EVT_UPDATE_UI(self, self.ID_TOOL_LOCATE, self.OnUpdateUI)
324 wx.EVT_UPDATE_UI(self, self.ID_TOOL_PASTE, self.OnUpdateUI)
325 wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.OnUpdateUI)
326 wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.OnUpdateUI)
327 wx.EVT_UPDATE_UI(self, self.ID_DELETE, self.OnUpdateUI)
328 wx.EVT_UPDATE_UI(self, self.ID_TEST, self.OnUpdateUI)
329 wx.EVT_UPDATE_UI(self, self.ID_REFRESH, self.OnUpdateUI)
330
331 # Build interface
332 sizer = wx.BoxSizer(wx.VERTICAL)
333 #sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)
334 # Horizontal sizer for toolbar and splitter
335 self.toolsSizer = sizer1 = wx.BoxSizer()
336 splitter = wx.SplitterWindow(self, -1, style=wx.SP_3DSASH)
337 self.splitter = splitter
338 splitter.SetMinimumPaneSize(100)
339 # Create tree
340 global tree
341 g.tree = tree = XML_Tree(splitter, -1)
342
343 # Init pull-down menu data
344 global pullDownMenu
345 g.pullDownMenu = pullDownMenu = PullDownMenu(self)
346
347 # Vertical toolbar for GUI buttons
348 g.tools = tools = Tools(self)
349 tools.Show(conf.showTools)
350 if conf.showTools: sizer1.Add(tools, 0, wx.EXPAND)
351
352 tree.RegisterKeyEvents()
353
354 # Miniframe for split mode
355 miniFrame = wx.MiniFrame(self, -1, 'Properties & Style',
356 (conf.panelX, conf.panelY),
357 (conf.panelWidth, conf.panelHeight))
358 self.miniFrame = miniFrame
359 sizer2 = wx.BoxSizer()
360 miniFrame.SetSizer(sizer2)
361 # Create panel for parameters
362 global panel
363 if conf.embedPanel:
364 panel = Panel(splitter)
365 # Set plitter windows
366 splitter.SplitVertically(tree, panel, conf.sashPos)
367 else:
368 panel = Panel(miniFrame)
369 sizer2.Add(panel, 1, wx.EXPAND)
370 miniFrame.Show(True)
371 splitter.Initialize(tree)
372 if wx.Platform == '__WXMAC__':
373 sizer1.Add(splitter, 1, wx.EXPAND|wx.RIGHT, 5)
374 else:
375 sizer1.Add(splitter, 1, wx.EXPAND)
376 sizer.Add(sizer1, 1, wx.EXPAND)
377 self.SetAutoLayout(True)
378 self.SetSizer(sizer)
379
380 # Other events
381 wx.EVT_IDLE(self, self.OnIdle)
382 wx.EVT_CLOSE(self, self.OnCloseWindow)
383 wx.EVT_KEY_DOWN(self, tools.OnKeyDown)
384 wx.EVT_KEY_UP(self, tools.OnKeyUp)
385 wx.EVT_ICONIZE(self, self.OnIconize)
386
387 def OnRecentFile(self,evt):
388 # open recently used file
389 if not self.AskSave(): return
390 wx.BeginBusyCursor()
391
392 # get the pathname based on the menu ID
393 fileNum = evt.GetId() - wx.ID_FILE1
394 path = g.fileHistory.GetHistoryFile(fileNum)
395
396 if self.Open(path):
397 self.SetStatusText('Data loaded')
398 # add it back to the history so it will be moved up the list
399 self.SaveRecent(path)
400 else:
401 self.SetStatusText('Failed')
402
403 wx.EndBusyCursor()
404
405 def OnNew(self, evt):
406 if not self.AskSave(): return
407 self.Clear()
408
409 def OnOpen(self, evt):
410 if not self.AskSave(): return
411 dlg = wx.FileDialog(self, 'Open', os.path.dirname(self.dataFile),
412 '', '*.xrc', wx.OPEN | wx.CHANGE_DIR)
413 if dlg.ShowModal() == wx.ID_OK:
414 path = dlg.GetPath()
415 self.SetStatusText('Loading...')
416 wx.BeginBusyCursor()
417 try:
418 if self.Open(path):
419 self.SetStatusText('Data loaded')
420 self.SaveRecent(path)
421 else:
422 self.SetStatusText('Failed')
423 finally:
424 wx.EndBusyCursor()
425 dlg.Destroy()
426
427 def OnSaveOrSaveAs(self, evt):
428 if evt.GetId() == wx.ID_SAVEAS or not self.dataFile:
429 if self.dataFile: name = ''
430 else: name = defaultName
431 dirname = os.path.abspath(os.path.dirname(self.dataFile))
432 dlg = wx.FileDialog(self, 'Save As', dirname, name, '*.xrc',
433 wx.SAVE | wx.OVERWRITE_PROMPT | wx.CHANGE_DIR)
434 if dlg.ShowModal() == wx.ID_OK:
435 path = dlg.GetPath()
436 if isinstance(path, unicode):
437 path = path.encode(sys.getfilesystemencoding())
438 dlg.Destroy()
439 else:
440 dlg.Destroy()
441 return
442
443 if conf.localconf:
444 # if we already have a localconf then it needs to be
445 # copied to a new config with the new name
446 lc = conf.localconf
447 nc = self.CreateLocalConf(path)
448 flag, key, idx = lc.GetFirstEntry()
449 while flag:
450 nc.Write(key, lc.Read(key))
451 flag, key, idx = lc.GetNextEntry(idx)
452 conf.localconf = nc
453 else:
454 # otherwise create a new one
455 conf.localconf = self.CreateLocalConf(path)
456 else:
457 path = self.dataFile
458 self.SetStatusText('Saving...')
459 wx.BeginBusyCursor()
460 try:
461 try:
462 tmpFile,tmpName = tempfile.mkstemp(prefix='xrced-')
463 os.close(tmpFile)
464 self.Save(tmpName) # save temporary file first
465 shutil.move(tmpName, path)
466 self.dataFile = path
467 self.SetModified(False)
468 if conf.localconf.ReadBool("autogenerate", False):
469 pypath = conf.localconf.Read("filename")
470 embed = conf.localconf.ReadBool("embedResource", False)
471 genGettext = conf.localconf.ReadBool("genGettext", False)
472 self.GeneratePython(self.dataFile, pypath, embed, genGettext)
473
474 self.SetStatusText('Data saved')
475 self.SaveRecent(path)
476 except IOError:
477 self.SetStatusText('Failed')
478 finally:
479 wx.EndBusyCursor()
480
481 def SaveRecent(self,path):
482 # append to recently used files
483 g.fileHistory.AddFileToHistory(path)
484
485 def GeneratePython(self, dataFile, pypath, embed, genGettext):
486 try:
487 import wx.tools.pywxrc
488 rescomp = wx.tools.pywxrc.XmlResourceCompiler()
489 rescomp.MakePythonModule([dataFile], pypath, embed, genGettext)
490 except:
491 inf = sys.exc_info()
492 wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1])
493 wx.LogError('Error generating python code : %s' % pypath)
494 raise
495
496
497 def OnGeneratePython(self, evt):
498 if self.modified or not conf.localconf:
499 wx.MessageBox("Save the XRC file first!", "Error")
500 return
501
502 dlg = PythonOptions(self, conf.localconf, self.dataFile)
503 dlg.ShowModal()
504 dlg.Destroy()
505
506 def OnPrefs(self, evt):
507 dlg = PrefsDialog(self)
508 if dlg.ShowModal() == wx.ID_OK:
509 # Fetch new preferences
510 for id,cdp in dlg.checkControls.items():
511 c,d,p = cdp
512 if dlg.FindWindowById(id).IsChecked():
513 d[p] = str(c.GetValue())
514 elif p in d: del d[p]
515 g.conf.allowExec = ('ask', 'yes', 'no')[dlg.radio_allow_exec.GetSelection()]
516 dlg.Destroy()
517
518 def OnExit(self, evt):
519 self.Close()
520
521 def OnUndo(self, evt):
522 # Extra check to not mess with idle updating
523 if undoMan.CanUndo():
524 undoMan.Undo()
525 g.panel.SetModified(False)
526 if not undoMan.CanUndo():
527 self.SetModified(False)
528
529 def OnRedo(self, evt):
530 if undoMan.CanRedo():
531 undoMan.Redo()
532 self.SetModified(True)
533
534 def OnCopy(self, evt):
535 selected = tree.selection
536 if not selected: return # key pressed event
537 xxx = tree.GetPyData(selected)
538 if wx.TheClipboard.Open():
539 if xxx.isElement:
540 data = wx.CustomDataObject('XRCED')
541 # Set encoding in header
542 # (False,True)
543 s = xxx.node.toxml(encoding=expat.native_encoding)
544 else:
545 data = wx.CustomDataObject('XRCED_node')
546 s = xxx.node.data
547 data.SetData(cPickle.dumps(s))
548 wx.TheClipboard.SetData(data)
549 wx.TheClipboard.Close()
550 self.SetStatusText('Copied')
551 else:
552 wx.MessageBox("Unable to open the clipboard", "Error")
553
554 def OnPaste(self, evt):
555 selected = tree.selection
556 if not selected: return # key pressed event
557 # For pasting with Ctrl pressed
558 appendChild = True
559 if evt.GetId() == pullDownMenu.ID_PASTE_SIBLING: appendChild = False
560 elif evt.GetId() == self.ID_TOOL_PASTE:
561 if g.tree.ctrl: appendChild = False
562 else: appendChild = not tree.NeedInsert(selected)
563 else: appendChild = not tree.NeedInsert(selected)
564 xxx = tree.GetPyData(selected)
565 if not appendChild:
566 # If has next item, insert, else append to parent
567 nextItem = tree.GetNextSibling(selected)
568 parentLeaf = tree.GetItemParent(selected)
569 # Expanded container (must have children)
570 elif tree.IsExpanded(selected) and tree.GetChildrenCount(selected, False):
571 # Insert as first child
572 nextItem = tree.GetFirstChild(selected)[0]
573 parentLeaf = selected
574 else:
575 # No children or unexpanded item - appendChild stays True
576 nextItem = wx.TreeItemId() # no next item
577 parentLeaf = selected
578 parent = tree.GetPyData(parentLeaf).treeObject()
579
580 # Create a copy of clipboard pickled element
581 success = success_node = False
582 if wx.TheClipboard.Open():
583 try:
584 data = wx.CustomDataObject('XRCED')
585 if wx.TheClipboard.IsSupported(data.GetFormat()):
586 try:
587 success = wx.TheClipboard.GetData(data)
588 except:
589 # there is a problem if XRCED_node is in clipboard
590 # but previous SetData was for XRCED
591 pass
592 if not success: # try other format
593 data = wx.CustomDataObject('XRCED_node')
594 if wx.TheClipboard.IsSupported(data.GetFormat()):
595 success_node = wx.TheClipboard.GetData(data)
596 finally:
597 wx.TheClipboard.Close()
598
599 if not success and not success_node:
600 wx.MessageBox(
601 "There is no data in the clipboard in the required format",
602 "Error")
603 return
604
605 xml = cPickle.loads(data.GetData()) # xml representation of element
606 if success:
607 elem = minidom.parseString(xml).childNodes[0]
608 else:
609 elem = g.tree.dom.createComment(xml)
610
611 # Tempopary xxx object to test things
612 xxx = MakeXXXFromDOM(parent, elem)
613
614 # Check compatibility
615 if not self.ItemsAreCompatible(parent, xxx.treeObject()): return
616
617 # Check parent and child relationships.
618 # If parent is sizer or notebook, child is of wrong class or
619 # parent is normal window, child is child container then detach child.
620 isChildContainer = isinstance(xxx, xxxChildContainer)
621 parentIsBook = parent.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook]
622 if isChildContainer and \
623 ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
624 (parentIsBook and not isinstance(xxx, xxxPage)) or \
625 not (parent.isSizer or parentIsBook)):
626 elem.removeChild(xxx.child.node) # detach child
627 elem.unlink() # delete child container
628 elem = xxx.child.node # replace
629 # This may help garbage collection
630 xxx.child.parent = None
631 isChildContainer = False
632 # Parent is sizer or notebook, child is not child container
633 if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer):
634 # Create sizer item element
635 sizerItemElem = MakeEmptyDOM(parent.itemTag)
636 sizerItemElem.appendChild(elem)
637 elem = sizerItemElem
638 elif isinstance(parent, xxxNotebook) and not isChildContainer:
639 pageElem = MakeEmptyDOM('notebookpage')
640 pageElem.appendChild(elem)
641 elem = pageElem
642 elif isinstance(parent, xxxChoicebook) and not isChildContainer:
643 pageElem = MakeEmptyDOM('choicebookpage')
644 pageElem.appendChild(elem)
645 elem = pageElem
646 elif isinstance(parent, xxxListbook) and not isChildContainer:
647 pageElem = MakeEmptyDOM('listbookpage')
648 pageElem.appendChild(elem)
649 elem = pageElem
650 # Insert new node, register undo
651 newItem = tree.InsertNode(parentLeaf, parent, elem, nextItem)
652 undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
653 # Scroll to show new item (!!! redundant?)
654 tree.EnsureVisible(newItem)
655 tree.SelectItem(newItem)
656 if not tree.IsVisible(newItem):
657 tree.ScrollTo(newItem)
658 tree.Refresh()
659 # Update view?
660 if g.testWin and tree.IsHighlatable(newItem):
661 if conf.autoRefresh:
662 tree.needUpdate = True
663 tree.pendingHighLight = newItem
664 else:
665 tree.pendingHighLight = None
666 self.SetModified()
667 self.SetStatusText('Pasted')
668
669
670 def ItemsAreCompatible(self, parent, child):
671 # Check compatibility
672 error = False
673 # Comments are always compatible
674 if child.__class__ == xxxComment:
675 return True
676 # Top-level
677 if child.__class__ in [xxxDialog, xxxFrame, xxxWizard]:
678 # Top-level classes
679 if parent.__class__ != xxxMainNode: error = True
680 elif child.__class__ == xxxMenuBar:
681 # Menubar can be put in frame or dialog
682 if parent.__class__ not in [xxxMainNode, xxxFrame, xxxDialog]: error = True
683 elif child.__class__ == xxxToolBar:
684 # Toolbar can be top-level of child of panel or frame
685 if parent.__class__ not in [xxxMainNode, xxxPanel, xxxFrame] and \
686 not parent.isSizer: error = True
687 elif child.__class__ == xxxPanel and parent.__class__ == xxxMainNode:
688 pass
689 elif child.__class__ == xxxSpacer:
690 if not parent.isSizer: error = True
691 elif child.__class__ == xxxSeparator:
692 if not parent.__class__ in [xxxMenu, xxxToolBar]: error = True
693 elif child.__class__ == xxxTool:
694 if parent.__class__ != xxxToolBar: error = True
695 elif child.__class__ == xxxMenu:
696 if not parent.__class__ in [xxxMainNode, xxxMenuBar, xxxMenu]: error = True
697 elif child.__class__ == xxxMenuItem:
698 if not parent.__class__ in [xxxMenuBar, xxxMenu]: error = True
699 elif child.isSizer and parent.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook]:
700 error = True
701 else: # normal controls can be almost anywhere
702 if parent.__class__ == xxxMainNode or \
703 parent.__class__ in [xxxMenuBar, xxxMenu]: error = True
704 if error:
705 if parent.__class__ == xxxMainNode: parentClass = 'root'
706 else: parentClass = parent.className
707 wx.LogError('Incompatible parent/child: parent is %s, child is %s!' %
708 (parentClass, child.className))
709 return False
710 return True
711
712 def OnMoveUp(self, evt):
713 selected = tree.selection
714 if not selected: return
715
716 index = tree.ItemIndex(selected)
717 if index == 0: return # No previous sibling found
718
719 # Remove highlight, update testWin
720 if g.testWin and g.testWin.highLight:
721 g.testWin.highLight.Remove()
722 tree.needUpdate = True
723
724 # Undo info
725 self.lastOp = 'MOVEUP'
726 status = 'Moved before previous sibling'
727
728 # Prepare undo data
729 panel.Apply()
730 tree.UnselectAll()
731
732 parent = tree.GetItemParent(selected)
733 elem = tree.RemoveLeaf(selected)
734 nextItem = tree.GetFirstChild(parent)[0]
735 for i in range(index - 1): nextItem = tree.GetNextSibling(nextItem)
736 selected = tree.InsertNode(parent, tree.GetPyData(parent).treeObject(), elem, nextItem)
737 newIndex = tree.ItemIndex(selected)
738 tree.SelectItem(selected)
739
740 undoMan.RegisterUndo(UndoMove(parent, index, parent, newIndex))
741
742 self.modified = True
743 self.SetStatusText(status)
744
745 return
746
747 def OnMoveDown(self, evt):
748 selected = tree.selection
749 if not selected: return
750
751 index = tree.ItemIndex(selected)
752 next = tree.GetNextSibling(selected)
753 if not next: return
754
755 # Remove highlight, update testWin
756 if g.testWin and g.testWin.highLight:
757 g.testWin.highLight.Remove()
758 tree.needUpdate = True
759
760 # Undo info
761 self.lastOp = 'MOVEDOWN'
762 status = 'Moved after next sibling'
763
764 # Prepare undo data
765 panel.Apply()
766 tree.UnselectAll()
767
768 parent = tree.GetItemParent(selected)
769 elem = tree.RemoveLeaf(selected)
770 nextItem = tree.GetFirstChild(parent)[0]
771 for i in range(index + 1): nextItem = tree.GetNextSibling(nextItem)
772 selected = tree.InsertNode(parent, tree.GetPyData(parent).treeObject(), elem, nextItem)
773 newIndex = tree.ItemIndex(selected)
774 tree.SelectItem(selected)
775
776 undoMan.RegisterUndo(UndoMove(parent, index, parent, newIndex))
777
778 self.modified = True
779 self.SetStatusText(status)
780
781 return
782
783 def OnMoveLeft(self, evt):
784 selected = tree.selection
785 if not selected: return
786
787 oldParent = tree.GetItemParent(selected)
788 if not oldParent: return
789 pparent = tree.GetItemParent(oldParent)
790 if not pparent: return
791
792 # Check compatibility
793 if not self.ItemsAreCompatible(tree.GetPyData(pparent).treeObject(), tree.GetPyData(selected).treeObject()): return
794
795 if g.testWin and g.testWin.highLight:
796 g.testWin.highLight.Remove()
797 tree.needUpdate = True
798
799 # Undo info
800 self.lastOp = 'MOVELEFT'
801 status = 'Made next sibling of parent'
802
803 oldIndex = tree.ItemIndex(selected)
804 elem = tree.RemoveLeaf(selected)
805 nextItem = tree.GetFirstChild(pparent)[0]
806 parentIndex = tree.ItemIndex(oldParent)
807 for i in range(parentIndex + 1): nextItem = tree.GetNextSibling(nextItem)
808
809 # Check parent and child relationships.
810 # If parent is sizer or notebook, child is of wrong class or
811 # parent is normal window, child is child container then detach child.
812 parent = tree.GetPyData(pparent).treeObject()
813 xxx = MakeXXXFromDOM(parent, elem)
814 isChildContainer = isinstance(xxx, xxxChildContainer)
815 if isChildContainer and \
816 ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
817 (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
818 not (parent.isSizer or isinstance(parent, xxxNotebook))):
819 elem.removeChild(xxx.child.node) # detach child
820 elem.unlink() # delete child container
821 elem = xxx.child.node # replace
822 # This may help garbage collection
823 xxx.child.parent = None
824 isChildContainer = False
825 # Parent is sizer or notebook, child is not child container
826 if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer):
827 # Create sizer item element
828 sizerItemElem = MakeEmptyDOM('sizeritem')
829 sizerItemElem.appendChild(elem)
830 elem = sizerItemElem
831 elif isinstance(parent, xxxNotebook) and not isChildContainer:
832 pageElem = MakeEmptyDOM('notebookpage')
833 pageElem.appendChild(elem)
834 elem = pageElem
835
836 selected = tree.InsertNode(pparent, tree.GetPyData(pparent).treeObject(), elem, nextItem)
837 newIndex = tree.ItemIndex(selected)
838 tree.SelectItem(selected)
839
840 undoMan.RegisterUndo(UndoMove(oldParent, oldIndex, pparent, newIndex))
841
842 self.modified = True
843 self.SetStatusText(status)
844
845 def OnMoveRight(self, evt):
846 selected = tree.selection
847 if not selected: return
848
849 oldParent = tree.GetItemParent(selected)
850 if not oldParent: return
851
852 newParent = tree.GetPrevSibling(selected)
853 if not newParent: return
854
855 parent = tree.GetPyData(newParent).treeObject()
856
857 # Check compatibility
858 if not self.ItemsAreCompatible(parent, tree.GetPyData(selected).treeObject()): return
859
860 # Remove highlight, update testWin
861 if g.testWin and g.testWin.highLight:
862 g.testWin.highLight.Remove()
863 tree.needUpdate = True
864
865 # Undo info
866 self.lastOp = 'MOVERIGHT'
867 status = 'Made last child of previous sibling'
868
869 oldIndex = tree.ItemIndex(selected)
870 elem = tree.RemoveLeaf(selected)
871
872 # Check parent and child relationships.
873 # If parent is sizer or notebook, child is of wrong class or
874 # parent is normal window, child is child container then detach child.
875 xxx = MakeXXXFromDOM(parent, elem)
876 isChildContainer = isinstance(xxx, xxxChildContainer)
877 if isChildContainer and \
878 ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
879 (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
880 not (parent.isSizer or isinstance(parent, xxxNotebook))):
881 elem.removeChild(xxx.child.node) # detach child
882 elem.unlink() # delete child container
883 elem = xxx.child.node # replace
884 # This may help garbage collection
885 xxx.child.parent = None
886 isChildContainer = False
887 # Parent is sizer or notebook, child is not child container
888 if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer):
889 # Create sizer item element
890 sizerItemElem = MakeEmptyDOM('sizeritem')
891 sizerItemElem.appendChild(elem)
892 elem = sizerItemElem
893 elif isinstance(parent, xxxNotebook) and not isChildContainer:
894 pageElem = MakeEmptyDOM('notebookpage')
895 pageElem.appendChild(elem)
896 elem = pageElem
897
898 selected = tree.InsertNode(newParent, tree.GetPyData(newParent).treeObject(), elem, wx.TreeItemId())
899
900 newIndex = tree.ItemIndex(selected)
901 tree.SelectItem(selected)
902
903 undoMan.RegisterUndo(UndoMove(oldParent, oldIndex, newParent, newIndex))
904
905 self.modified = True
906 self.SetStatusText(status)
907
908 def OnCutDelete(self, evt):
909 selected = tree.selection
910 if not selected: return # key pressed event
911 # Undo info
912 if evt.GetId() == wx.ID_CUT:
913 self.lastOp = 'CUT'
914 status = 'Removed to clipboard'
915 else:
916 self.lastOp = 'DELETE'
917 status = 'Deleted'
918 # Delete testWin?
919 if g.testWin:
920 # If deleting top-level item, delete testWin
921 if selected == g.testWin.item:
922 g.testWin.Destroy()
923 g.testWin = None
924 else:
925 # Remove highlight, update testWin
926 if g.testWin.highLight:
927 g.testWin.highLight.Remove()
928 tree.needUpdate = True
929 # Prepare undo data
930 panel.Apply()
931 index = tree.ItemFullIndex(selected)
932 xxx = tree.GetPyData(selected)
933 parent = tree.GetPyData(tree.GetItemParent(selected)).treeObject()
934 tree.UnselectAll()
935 elem = tree.RemoveLeaf(selected)
936 undoMan.RegisterUndo(UndoCutDelete(index, parent, elem))
937 if evt.GetId() == wx.ID_CUT:
938 if wx.TheClipboard.Open():
939 if xxx.isElement:
940 data = wx.CustomDataObject('XRCED')
941 # (False, True)
942 s = elem.toxml(encoding=expat.native_encoding)
943 else:
944 data = wx.CustomDataObject('XRCED_node')
945 s = xxx.node.data
946 data.SetData(cPickle.dumps(s))
947 wx.TheClipboard.SetData(data)
948 wx.TheClipboard.Close()
949 else:
950 wx.MessageBox("Unable to open the clipboard", "Error")
951 tree.pendingHighLight = None
952 # Update tools
953 panel.Clear()
954 self.SetModified()
955 self.SetStatusText(status)
956
957 def OnSubclass(self, evt):
958 selected = tree.selection
959 xxx = tree.GetPyData(selected).treeObject()
960 elem = xxx.node
961 subclass = xxx.subclass
962 dlg = wx.TextEntryDialog(self, 'Subclass:', defaultValue=subclass)
963 if dlg.ShowModal() == wx.ID_OK:
964 subclass = dlg.GetValue()
965 if subclass:
966 elem.setAttribute('subclass', subclass)
967 elif elem.hasAttribute('subclass'):
968 elem.removeAttribute('subclass')
969 self.SetModified()
970 xxx.subclass = elem.getAttribute('subclass')
971 tree.SetItemText(selected, xxx.treeName())
972 panel.pages[0].box.SetLabel(xxx.panelName())
973 dlg.Destroy()
974
975 def OnEmbedPanel(self, evt):
976 conf.embedPanel = evt.IsChecked()
977 if conf.embedPanel:
978 # Remember last dimentions
979 conf.panelX, conf.panelY = self.miniFrame.GetPosition()
980 conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize()
981 size = self.GetSize()
982 pos = self.GetPosition()
983 sizePanel = panel.GetSize()
984 panel.Reparent(self.splitter)
985 self.miniFrame.GetSizer().Remove(panel)
986 # Widen
987 self.SetDimensions(pos.x, pos.y, size.width + sizePanel.width, size.height)
988 self.splitter.SplitVertically(tree, panel, conf.sashPos)
989 self.miniFrame.Show(False)
990 else:
991 conf.sashPos = self.splitter.GetSashPosition()
992 pos = self.GetPosition()
993 size = self.GetSize()
994 sizePanel = panel.GetSize()
995 self.splitter.Unsplit(panel)
996 sizer = self.miniFrame.GetSizer()
997 panel.Reparent(self.miniFrame)
998 panel.Show(True)
999 sizer.Add(panel, 1, wx.EXPAND)
1000 self.miniFrame.Show(True)
1001 self.miniFrame.SetDimensions(conf.panelX, conf.panelY,
1002 conf.panelWidth, conf.panelHeight)
1003 self.miniFrame.Layout()
1004 # Reduce width
1005 self.SetDimensions(pos.x, pos.y,
1006 max(size.width - sizePanel.width, self.minWidth), size.height)
1007
1008 def OnShowTools(self, evt):
1009 conf.showTools = evt.IsChecked()
1010 g.tools.Show(conf.showTools)
1011 if conf.showTools:
1012 self.toolsSizer.Prepend(g.tools, 0, wx.EXPAND)
1013 else:
1014 self.toolsSizer.Remove(g.tools)
1015 self.toolsSizer.Layout()
1016
1017 def OnTest(self, evt):
1018 if not tree.selection: return # key pressed event
1019 tree.ShowTestWindow(tree.selection)
1020
1021 def OnTestHide(self, evt):
1022 tree.CloseTestWindow()
1023
1024 # Find object by relative position
1025 def FindObject(self, item, obj):
1026 # We simply perform depth-first traversal, sinse it's too much
1027 # hassle to deal with all sizer/window combinations
1028 w = tree.FindNodeObject(item)
1029 if w == obj or isinstance(w, wx.GBSizerItem) and w.GetWindow() == obj:
1030 return item
1031 if tree.ItemHasChildren(item):
1032 child = tree.GetFirstChild(item)[0]
1033 while child:
1034 found = self.FindObject(child, obj)
1035 if found: return found
1036 child = tree.GetNextSibling(child)
1037 return None
1038
1039 # Click event after locate activated
1040 def OnTestWinLeftDown(self, evt):
1041 # Restore normal event processing
1042 self.SetHandler(g.testWin)
1043 g.testWin.Disconnect(wx.ID_ANY, wx.ID_ANY, wx.wxEVT_LEFT_DOWN)
1044 item = self.FindObject(g.testWin.item, evt.GetEventObject())
1045 if item:
1046 tree.EnsureVisible(item)
1047 tree.SelectItem(item)
1048 self.tb.ToggleTool(self.ID_TOOL_LOCATE, False)
1049 if item:
1050 self.SetStatusText('Selected %s' % tree.GetItemText(item))
1051 else:
1052 self.SetStatusText('Locate failed!')
1053
1054 def SetHandler(self, w, h=None):
1055 if h:
1056 w.SetEventHandler(h)
1057 w.SetCursor(wx.CROSS_CURSOR)
1058 else:
1059 w.SetEventHandler(w)
1060 w.SetCursor(wx.NullCursor)
1061 for ch in w.GetChildren():
1062 self.SetHandler(ch, h)
1063
1064 def OnLocate(self, evt):
1065 if g.testWin:
1066 if evt.GetId() == self.ID_LOCATE or \
1067 evt.GetId() == self.ID_TOOL_LOCATE and evt.IsChecked():
1068 self.SetHandler(g.testWin, g.testWin)
1069 g.testWin.Connect(wx.ID_ANY, wx.ID_ANY, wx.wxEVT_LEFT_DOWN, self.OnTestWinLeftDown)
1070 if evt.GetId() == self.ID_LOCATE:
1071 self.tb.ToggleTool(self.ID_TOOL_LOCATE, True)
1072 elif evt.GetId() == self.ID_TOOL_LOCATE and not evt.IsChecked():
1073 self.SetHandler(g.testWin, None)
1074 g.testWin.Disconnect(wx.ID_ANY, wx.ID_ANY, wx.wxEVT_LEFT_DOWN)
1075 self.SetStatusText('Click somewhere in your test window now')
1076
1077 def OnRefresh(self, evt):
1078 # If modified, apply first
1079 selection = tree.selection
1080 if selection:
1081 xxx = tree.GetPyData(selection)
1082 if xxx and panel.IsModified():
1083 tree.Apply(xxx, selection)
1084 if g.testWin:
1085 # (re)create
1086 tree.CreateTestWin(g.testWin.item)
1087 panel.modified = False
1088 tree.needUpdate = False
1089
1090 def OnAutoRefresh(self, evt):
1091 conf.autoRefresh = evt.IsChecked()
1092 self.menuBar.Check(self.ID_AUTO_REFRESH, conf.autoRefresh)
1093 self.tb.ToggleTool(self.ID_AUTO_REFRESH, conf.autoRefresh)
1094
1095 def OnAbout(self, evt):
1096 str = '''\
1097 XRCed version %s
1098
1099 (c) Roman Rolinsky <rollrom@users.sourceforge.net>
1100 Homepage: http://xrced.sourceforge.net\
1101 ''' % version
1102 dlg = wx.MessageDialog(self, str, 'About XRCed', wx.OK | wx.CENTRE)
1103 dlg.ShowModal()
1104 dlg.Destroy()
1105
1106 def OnReadme(self, evt):
1107 text = open(os.path.join(basePath, 'README.txt'), 'r').read()
1108 dlg = ScrolledMessageDialog(self, text, "XRCed README")
1109 dlg.ShowModal()
1110 dlg.Destroy()
1111
1112 # Simple emulation of python command line
1113 def OnDebugCMD(self, evt):
1114 while 1:
1115 try:
1116 exec raw_input('C:\> ')
1117 except EOFError:
1118 print '^D'
1119 break
1120 except:
1121 (etype, value, tb) =sys.exc_info()
1122 tblist =traceback.extract_tb(tb)[1:]
1123 msg =' '.join(traceback.format_exception_only(etype, value)
1124 +traceback.format_list(tblist))
1125 print msg
1126
1127 def OnCreate(self, evt):
1128 # Ignore fake events generated while dragging
1129 if g.tools.drag:
1130 g.tools.drag = False
1131 return
1132 selected = tree.selection
1133 if tree.ctrl: appendChild = False
1134 else: appendChild = not tree.NeedInsert(selected)
1135 xxx = tree.GetPyData(selected)
1136 if not appendChild:
1137 # If insert before
1138 if tree.shift:
1139 # If has previous item, insert after it, else append to parent
1140 nextItem = selected
1141 parentLeaf = tree.GetItemParent(selected)
1142 else:
1143 # If has next item, insert, else append to parent
1144 nextItem = tree.GetNextSibling(selected)
1145 parentLeaf = tree.GetItemParent(selected)
1146 # Expanded container (must have children)
1147 elif tree.shift and tree.IsExpanded(selected) \
1148 and tree.GetChildrenCount(selected, False):
1149 nextItem = tree.GetFirstChild(selected)[0]
1150 parentLeaf = selected
1151 else:
1152 nextItem = wx.TreeItemId()
1153 parentLeaf = selected
1154 parent = tree.GetPyData(parentLeaf)
1155 if parent.hasChild: parent = parent.child
1156
1157 self.CreateXXX(parent, parentLeaf, nextItem, evt.GetId())
1158
1159 # Actual method to create object and add to XML and wx trees
1160 def CreateXXX(self, parent, parentLeaf, nextItem, id):
1161 selected = tree.selection
1162 # Create object_ref?
1163 if id == ID_NEW.REF:
1164 ref = wx.GetTextFromUser('Create reference to:', 'Create reference')
1165 if not ref: return
1166 xxx = MakeEmptyRefXXX(parent, ref)
1167 elif id == ID_NEW.COMMENT:
1168 xxx = MakeEmptyCommentXXX(parent)
1169 else:
1170 # Create empty element
1171 if id >= ID_NEW.CUSTOM:
1172 className = pullDownMenu.customMap[id]
1173 else:
1174 className = pullDownMenu.createMap[id]
1175 xxx = MakeEmptyXXX(parent, className)
1176
1177 # Insert new node, register undo
1178 if xxx.isElement: # true object
1179 # Set default name for top-level windows
1180 if parent.__class__ == xxxMainNode:
1181 cl = xxx.treeObject().__class__
1182 frame.maxIDs[cl] += 1
1183 xxx.setTreeName('%s%d' % (defaultIDs[cl], frame.maxIDs[cl]))
1184 # And for some other standard controls
1185 elif parent.__class__ == xxxStdDialogButtonSizer:
1186 # ... we can even set automatically tree name
1187 xxx.setTreeName(pullDownMenu.stdButtonIDs[id][0])
1188 obj = xxx.treeObject()
1189 # ... and label
1190 elem = g.tree.dom.createElement('label')
1191 elem.appendChild(g.tree.dom.createTextNode(pullDownMenu.stdButtonIDs[id][1]))
1192 obj.params['label'] = xxxParam(elem)
1193 xxx.treeObject().node.appendChild(elem)
1194 # Else, set label if exists to class name
1195 elif 'label' in xxx.treeObject().allParams:
1196 label = className
1197 if label[:2] == 'wx': label = label[2:]
1198 xxx.treeObject().set('label', label.upper())
1199 # For comment nodes, simply add node
1200 newItem = tree.InsertNode(parentLeaf, parent, xxx.node, nextItem)
1201 undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
1202 tree.EnsureVisible(newItem)
1203 tree.SelectItem(newItem)
1204 if not tree.IsVisible(newItem):
1205 tree.ScrollTo(newItem)
1206 tree.Refresh()
1207 # Update view?
1208 if xxx.isElement and g.testWin and tree.IsHighlatable(newItem):
1209 if conf.autoRefresh:
1210 tree.needUpdate = True
1211 tree.pendingHighLight = newItem
1212 else:
1213 tree.pendingHighLight = None
1214 tree.SetFocus()
1215 if not xxx.isElement:
1216 tree.EditLabel(newItem)
1217 self.SetModified()
1218 return xxx
1219
1220 # Replace one object with another
1221 def OnReplace(self, evt):
1222 selected = tree.selection
1223 xxx = tree.GetPyData(selected).treeObject()
1224 elem = xxx.node
1225 parent = elem.parentNode
1226 undoMan.RegisterUndo(UndoReplace(selected))
1227 # New class
1228 className = pullDownMenu.createMap[evt.GetId() - 1000]
1229
1230 # Create temporary empty node (with default values)
1231 dummy = MakeEmptyDOM(className)
1232 if className == 'spacer' and xxx.className != 'spacer':
1233 klass = xxxSpacer
1234 elif xxx.className == 'spacer' and className != 'spacer':
1235 klass = xxxSizerItem
1236 else:
1237 klass = xxxDict[className]
1238 # Remove non-compatible children
1239 if tree.ItemHasChildren(selected) and not klass.hasChildren:
1240 tree.DeleteChildren(selected)
1241 nodes = elem.childNodes[:]
1242 tags = []
1243 for node in nodes:
1244 if node.nodeType != minidom.Node.ELEMENT_NODE: continue
1245 remove = False
1246 tag = node.tagName
1247 if tag == 'object':
1248 if not klass.hasChildren: remove = True
1249 elif tag not in klass.allParams and \
1250 (not klass.hasStyle or tag not in klass.styles):
1251 remove = True
1252 else:
1253 tags.append(tag)
1254 if remove:
1255 elem.removeChild(node)
1256 node.unlink()
1257
1258 # Remove sizeritem child if spacer
1259 if className == 'spacer' and xxx.className != 'spacer':
1260 sizeritem = elem.parentNode
1261 assert sizeritem.getAttribute('class') == 'sizeritem'
1262 sizeritem.removeChild(elem)
1263 elem.unlink()
1264 elem = sizeritem
1265 tree.GetPyData(selected).hasChild = False
1266 elif xxx.className == 'spacer' and className != 'spacer':
1267 # Create sizeritem element
1268 assert xxx.parent.isSizer
1269 elem.setAttribute('class', 'sizeritem')
1270 node = MakeEmptyDOM(className)
1271 elem.appendChild(node)
1272 # Replace to point to new object
1273 xxx = xxxSizerItem(xxx.parent, elem)
1274 elem = node
1275 tree.SetPyData(selected, xxx)
1276 xxx = xxx.child
1277 else:
1278 # Copy parameters present in dummy but not in elem
1279 for node in dummy.childNodes:
1280 if node.tagName not in tags: elem.appendChild(node.cloneNode(True))
1281 dummy.unlink()
1282
1283 # Change class name
1284 elem.setAttribute('class', className)
1285 if elem.hasAttribute('subclass'):
1286 elem.removeAttribute('subclass') # clear subclassing
1287 # Re-create xxx element
1288 xxx = MakeXXXFromDOM(xxx.parent, elem)
1289 # Remove incompatible style flags
1290 if 'style' in xxx.params:
1291 styles = map(string.strip, xxx.params['style'].value().split('|'))
1292 newStyles = [s for s in styles if s in klass.winStyles or s in genericStyles]
1293 if newStyles != styles:
1294 if newStyles:
1295 value = reduce(lambda a,b: a+'|'+b, newStyles)
1296 else:
1297 value = ''
1298 xxx.params['style'].update(value)
1299
1300 # Update parent in child objects
1301 if tree.ItemHasChildren(selected):
1302 i, cookie = tree.GetFirstChild(selected)
1303 while i.IsOk():
1304 x = tree.GetPyData(i)
1305 x.parent = xxx
1306 if x.hasChild: x.child.parent = xxx
1307 i, cookie = tree.GetNextChild(selected, cookie)
1308
1309 # Update tree
1310 if tree.GetPyData(selected).hasChild: # child container
1311 container = tree.GetPyData(selected)
1312 container.resetChild(xxx)
1313 xxx = container
1314 else:
1315 tree.SetPyData(selected, xxx)
1316 tree.SetItemText(selected, xxx.treeName())
1317 tree.SetItemImage(selected, xxx.treeImage())
1318
1319 # Set default name for top-level windows
1320 if parent.__class__ == xxxMainNode:
1321 cl = xxx.treeObject().__class__
1322 frame.maxIDs[cl] += 1
1323 xxx.setTreeName('%s%d' % (defaultIDs[cl], frame.maxIDs[cl]))
1324
1325 # Update panel
1326 g.panel.SetData(xxx)
1327 # Update tools
1328 g.tools.UpdateUI()
1329
1330 #undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
1331 # Update view?
1332 if g.testWin and tree.IsHighlatable(selected):
1333 if conf.autoRefresh:
1334 tree.needUpdate = True
1335 tree.pendingHighLight = selected
1336 else:
1337 tree.pendingHighLight = None
1338 tree.SetFocus()
1339 self.SetModified()
1340
1341 # Expand/collapse subtree
1342 def OnExpand(self, evt):
1343 if tree.selection: tree.ExpandAll(tree.selection)
1344 else: tree.ExpandAll(tree.root)
1345 def OnCollapse(self, evt):
1346 if tree.selection: tree.CollapseAll(tree.selection)
1347 else: tree.CollapseAll(tree.root)
1348
1349 def OnPullDownHighlight(self, evt):
1350 menuId = evt.GetMenuId()
1351 if menuId != -1:
1352 menu = evt.GetEventObject()
1353 try:
1354 help = menu.GetHelpString(menuId)
1355 self.SetStatusText(help)
1356 except:
1357 self.SetStatusText('')
1358 else:
1359 self.SetStatusText('')
1360
1361 def OnUpdateUI(self, evt):
1362 if evt.GetId() in [wx.ID_CUT, wx.ID_COPY, self.ID_DELETE]:
1363 evt.Enable(tree.selection is not None and tree.selection != tree.root)
1364 elif evt.GetId() == wx.ID_SAVE:
1365 evt.Enable(self.modified)
1366 elif evt.GetId() in [wx.ID_PASTE, self.ID_TOOL_PASTE]:
1367 evt.Enable(tree.selection is not None)
1368 elif evt.GetId() == self.ID_TEST:
1369 evt.Enable(tree.selection is not None and tree.selection != tree.root)
1370 elif evt.GetId() in [self.ID_LOCATE, self.ID_TOOL_LOCATE]:
1371 evt.Enable(g.testWin is not None)
1372 elif evt.GetId() == wx.ID_UNDO: evt.Enable(undoMan.CanUndo())
1373 elif evt.GetId() == wx.ID_REDO: evt.Enable(undoMan.CanRedo())
1374
1375 def OnIdle(self, evt):
1376 if self.inIdle: return # Recursive call protection
1377 self.inIdle = True
1378 #print 'onidle',tree.needUpdate,tree.pendingHighLight
1379 try:
1380 if tree.needUpdate:
1381 if conf.autoRefresh:
1382 if g.testWin:
1383 #self.SetStatusText('Refreshing test window...')
1384 # (re)create
1385 tree.CreateTestWin(g.testWin.item)
1386 #self.SetStatusText('')
1387 tree.needUpdate = False
1388 elif tree.pendingHighLight:
1389 try:
1390 tree.HighLight(tree.pendingHighLight)
1391 except:
1392 # Remove highlight if any problem
1393 if g.testWin and g.testWin.highLight:
1394 g.testWin.highLight.Remove()
1395 tree.pendingHighLight = None
1396 raise
1397 else:
1398 evt.Skip()
1399 finally:
1400 self.inIdle = False
1401
1402 def OnIconize(self, evt):
1403 if evt.Iconized():
1404 conf.x, conf.y = self.GetPosition()
1405 conf.width, conf.height = self.GetSize()
1406 if conf.embedPanel:
1407 conf.sashPos = self.splitter.GetSashPosition()
1408 else:
1409 conf.panelX, conf.panelY = self.miniFrame.GetPosition()
1410 conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize()
1411 self.miniFrame.Show(False)
1412 else:
1413 if not conf.embedPanel:
1414 self.miniFrame.Show(True)
1415 evt.Skip()
1416
1417 def OnCloseWindow(self, evt):
1418 if not self.AskSave(): return
1419 if g.testWin: g.testWin.Destroy()
1420 if not panel.GetPageCount() == 2:
1421 panel.page2.Destroy()
1422 else:
1423 # If we don't do this, page does not get destroyed (a bug?)
1424 panel.RemovePage(1)
1425 if not self.IsIconized():
1426 conf.x, conf.y = self.GetPosition()
1427 if wx.Platform == '__WXMAC__':
1428 conf.width, conf.height = self.GetClientSize()
1429 else:
1430 conf.width, conf.height = self.GetSize()
1431 if conf.embedPanel:
1432 conf.sashPos = self.splitter.GetSashPosition()
1433 else:
1434 conf.panelX, conf.panelY = self.miniFrame.GetPosition()
1435 conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize()
1436 evt.Skip()
1437
1438 def CreateLocalConf(self, path):
1439 name = os.path.splitext(path)[0]
1440 name += '.xcfg'
1441 return wx.FileConfig(localFilename=name)
1442
1443 def Clear(self):
1444 self.dataFile = ''
1445 conf.localconf = None
1446 undoMan.Clear()
1447 self.SetModified(False)
1448 tree.Clear()
1449 panel.Clear()
1450 if g.testWin:
1451 g.testWin.Destroy()
1452 g.testWin = None
1453 # Numbers for new controls
1454 self.maxIDs = {}
1455 for cl in [xxxPanel, xxxDialog, xxxFrame,
1456 xxxMenuBar, xxxMenu, xxxToolBar,
1457 xxxWizard, xxxBitmap, xxxIcon]:
1458 self.maxIDs[cl] = 0
1459 # Restore handlers, menu, etc. to initial
1460 setHandlers(self.handlers[:])
1461 g.pullDownMenu.custom = self.custom[:]
1462 # Remove modules imported from comment directives
1463 map(sys.modules.pop, [m for m in sys.modules if m not in self.modules])
1464 xxxParamComment.locals = {} # clear local namespace
1465 xxxParamComment.allow = None # clear execution state
1466
1467 def SetModified(self, state=True):
1468 self.modified = state
1469 name = os.path.basename(self.dataFile)
1470 if not name: name = defaultName
1471 if state:
1472 self.SetTitle(progname + ': ' + name + ' *')
1473 else:
1474 self.SetTitle(progname + ': ' + name)
1475
1476 def Open(self, path):
1477 if not os.path.exists(path):
1478 wx.LogError('File does not exists: %s' % path)
1479 return False
1480 # Try to read the file
1481 try:
1482 f = open(path)
1483 self.Clear()
1484 dom = minidom.parse(f)
1485 f.close()
1486 # Set encoding global variable and default encoding
1487 if dom.encoding:
1488 g.currentEncoding = dom.encoding
1489 wx.SetDefaultPyEncoding(g.currentEncoding.encode())
1490 else:
1491 g.currentEncoding = ''
1492 # Change dir
1493 self.dataFile = path = os.path.abspath(path)
1494 dir = os.path.dirname(path)
1495 if dir: os.chdir(dir)
1496 # Allow importing modules from the same directory
1497 sys.path = sys_path + [dir]
1498 tree.SetData(dom)
1499 self.SetTitle(progname + ': ' + os.path.basename(path))
1500 conf.localconf = self.CreateLocalConf(self.dataFile)
1501 except:
1502 # Nice exception printing
1503 inf = sys.exc_info()
1504 wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1])
1505 wx.LogError('Error reading file: %s' % path)
1506 if debug: raise
1507 return False
1508 return True
1509
1510 def Indent(self, node, indent = 0):
1511 if node.nodeType == minidom.Node.COMMENT_NODE:
1512 text = self.domCopy.createTextNode('\n' + ' ' * indent)
1513 node.parentNode.insertBefore(text, node)
1514 return # no children
1515 # Copy child list because it will change soon
1516 children = node.childNodes[:]
1517 # Main node doesn't need to be indented
1518 if indent:
1519 text = self.domCopy.createTextNode('\n' + ' ' * indent)
1520 node.parentNode.insertBefore(text, node)
1521 if children:
1522 # Append newline after last child, except for text nodes
1523 if children[-1].nodeType == minidom.Node.ELEMENT_NODE:
1524 text = self.domCopy.createTextNode('\n' + ' ' * indent)
1525 node.appendChild(text)
1526 # Indent children which are elements
1527 for n in children:
1528 if n.nodeType == minidom.Node.ELEMENT_NODE or \
1529 n.nodeType == minidom.Node.COMMENT_NODE:
1530 self.Indent(n, indent + 2)
1531
1532 def Save(self, path):
1533 try:
1534 import codecs
1535 # Apply changes
1536 if tree.selection and panel.IsModified():
1537 self.OnRefresh(wx.CommandEvent())
1538 if g.currentEncoding:
1539 f = codecs.open(path, 'wt', g.currentEncoding)
1540 else:
1541 f = codecs.open(path, 'wt')
1542 # Make temporary copy for formatting it
1543 # !!! We can't clone dom node, it works only once
1544 #self.domCopy = tree.dom.cloneNode(True)
1545 self.domCopy = MyDocument()
1546 mainNode = self.domCopy.appendChild(tree.mainNode.cloneNode(True))
1547 # Remove first child (test element)
1548 testElem = mainNode.firstChild
1549 mainNode.removeChild(testElem)
1550 testElem.unlink()
1551 self.Indent(mainNode)
1552 self.domCopy.writexml(f, encoding = g.currentEncoding)
1553 f.close()
1554 self.domCopy.unlink()
1555 self.domCopy = None
1556 self.SetModified(False)
1557 panel.SetModified(False)
1558 conf.localconf.Flush()
1559 except:
1560 inf = sys.exc_info()
1561 wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1])
1562 wx.LogError('Error writing file: %s' % path)
1563 raise
1564
1565 def AskSave(self):
1566 if not (self.modified or panel.IsModified()): return True
1567 flags = wx.ICON_EXCLAMATION | wx.YES_NO | wx.CANCEL | wx.CENTRE
1568 dlg = wx.MessageDialog( self, 'File is modified. Save before exit?',
1569 'Save before too late?', flags )
1570 say = dlg.ShowModal()
1571 dlg.Destroy()
1572 wx.Yield()
1573 if say == wx.ID_YES:
1574 self.OnSaveOrSaveAs(wx.CommandEvent(wx.ID_SAVE))
1575 # If save was successful, modified flag is unset
1576 if not self.modified: return True
1577 elif say == wx.ID_NO:
1578 self.SetModified(False)
1579 panel.SetModified(False)
1580 return True
1581 return False
1582
1583 ################################################################################
1584
1585 class PythonOptions(wx.Dialog):
1586
1587 def __init__(self, parent, cfg, dataFile):
1588 pre = wx.PreDialog()
1589 g.frame.res.LoadOnDialog(pre, parent, "PYTHON_OPTIONS")
1590 self.PostCreate(pre)
1591
1592 self.cfg = cfg
1593 self.dataFile = dataFile
1594
1595 self.AutoGenerateCB = xrc.XRCCTRL(self, "AutoGenerateCB")
1596 self.EmbedCB = xrc.XRCCTRL(self, "EmbedCB")
1597 self.GettextCB = xrc.XRCCTRL(self, "GettextCB")
1598 self.MakeXRSFileCB = xrc.XRCCTRL(self, "MakeXRSFileCB")
1599 self.FileNameTC = xrc.XRCCTRL(self, "FileNameTC")
1600 self.BrowseBtn = xrc.XRCCTRL(self, "BrowseBtn")
1601 self.GenerateBtn = xrc.XRCCTRL(self, "GenerateBtn")
1602 self.SaveOptsBtn = xrc.XRCCTRL(self, "SaveOptsBtn")
1603
1604 self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.BrowseBtn)
1605 self.Bind(wx.EVT_BUTTON, self.OnGenerate, self.GenerateBtn)
1606 self.Bind(wx.EVT_BUTTON, self.OnSaveOpts, self.SaveOptsBtn)
1607
1608 if self.cfg.Read("filename", "") != "":
1609 self.FileNameTC.SetValue(self.cfg.Read("filename"))
1610 else:
1611 name = os.path.splitext(os.path.split(dataFile)[1])[0]
1612 name += '_xrc.py'
1613 self.FileNameTC.SetValue(name)
1614 self.AutoGenerateCB.SetValue(self.cfg.ReadBool("autogenerate", False))
1615 self.EmbedCB.SetValue(self.cfg.ReadBool("embedResource", False))
1616 self.MakeXRSFileCB.SetValue(self.cfg.ReadBool("makeXRS", False))
1617 self.GettextCB.SetValue(self.cfg.ReadBool("genGettext", False))
1618
1619
1620 def OnBrowse(self, evt):
1621 path = self.FileNameTC.GetValue()
1622 dirname = os.path.abspath(os.path.dirname(path))
1623 name = os.path.split(path)[1]
1624 dlg = wx.FileDialog(self, 'Save As', dirname, name, '*.py',
1625 wx.SAVE | wx.OVERWRITE_PROMPT)
1626 if dlg.ShowModal() == wx.ID_OK:
1627 path = dlg.GetPath()
1628 self.FileNameTC.SetValue(path)
1629 dlg.Destroy()
1630
1631
1632 def OnGenerate(self, evt):
1633 pypath = self.FileNameTC.GetValue()
1634 embed = self.EmbedCB.GetValue()
1635 genGettext = self.GettextCB.GetValue()
1636 frame.GeneratePython(self.dataFile, pypath, embed, genGettext)
1637 self.OnSaveOpts()
1638
1639
1640 def OnSaveOpts(self, evt=None):
1641 self.cfg.Write("filename", self.FileNameTC.GetValue())
1642 self.cfg.WriteBool("autogenerate", self.AutoGenerateCB.GetValue())
1643 self.cfg.WriteBool("embedResource", self.EmbedCB.GetValue())
1644 self.cfg.WriteBool("makeXRS", self.MakeXRSFileCB.GetValue())
1645 self.cfg.WriteBool("genGettext", self.GettextCB.GetValue())
1646
1647 self.EndModal(wx.ID_OK)
1648
1649 ################################################################################
1650
1651 class PrefsDialog(wx.Dialog):
1652
1653 def __init__(self, parent):
1654 pre = wx.PreDialog()
1655 g.frame.res.LoadOnDialog(pre, parent, "DIALOG_PREFS")
1656 self.PostCreate(pre)
1657 self.checkControls = {} # map of check IDs to (control,dict,param)
1658
1659 ##xxx = sys.modules['xxx']
1660 import xxx
1661 d = xxx.xxxSizerItem.defaults_panel
1662
1663 self.check_proportion_panel = xrc.XRCCTRL(self, 'check_proportion_panel')
1664 id = self.check_proportion_panel.GetId()
1665 wx.EVT_CHECKBOX(self, id, self.OnCheck)
1666 self.checkControls[id] = (xrc.XRCCTRL(self, 'spin_proportion_panel'),
1667 d, 'option')
1668
1669 self.check_flag_panel = xrc.XRCCTRL(self, 'check_flag_panel')
1670 id = self.check_flag_panel.GetId()
1671 wx.EVT_CHECKBOX(self, id, self.OnCheck)
1672 self.checkControls[id] = (xrc.XRCCTRL(self, 'text_flag_panel'),
1673 d, 'flag')
1674
1675 d = xxx.xxxSizerItem.defaults_control
1676
1677 self.check_proportion_panel = xrc.XRCCTRL(self, 'check_proportion_control')
1678 id = self.check_proportion_panel.GetId()
1679 wx.EVT_CHECKBOX(self, id, self.OnCheck)
1680 self.checkControls[id] = (xrc.XRCCTRL(self, 'spin_proportion_control'),
1681 d, 'option')
1682
1683 self.check_flag_panel = xrc.XRCCTRL(self, 'check_flag_control')
1684 id = self.check_flag_panel.GetId()
1685 wx.EVT_CHECKBOX(self, id, self.OnCheck)
1686 self.checkControls[id] = (xrc.XRCCTRL(self, 'text_flag_control'),
1687 d, 'flag')
1688
1689 for id,cdp in self.checkControls.items():
1690 c,d,p = cdp
1691 try:
1692 if isinstance(c, wx.SpinCtrl):
1693 c.SetValue(int(d[p]))
1694 else:
1695 c.SetValue(d[p])
1696 self.FindWindowById(id).SetValue(True)
1697 except KeyError:
1698 c.Enable(False)
1699
1700 self.radio_allow_exec = xrc.XRCCTRL(self, 'radio_allow_exec')
1701 try:
1702 radio = {'ask': 0, 'yes':1, 'no':2}[g.conf.allowExec]
1703 except KeyError:
1704 radio = 0
1705 self.radio_allow_exec.SetSelection(radio)
1706
1707 def OnCheck(self, evt):
1708 self.checkControls[evt.GetId()][0].Enable(evt.IsChecked())
1709 evt.Skip()
1710
1711 ################################################################################
1712
1713 # Parse string in form var1=val1[,var2=val2]* as dictionary
1714 def ReadDictFromString(s):
1715 d = {}
1716 for vv in s.split(','):
1717 var,val = vv.split(':')
1718 d[var.strip()] = val
1719 return d
1720
1721 # Transform dictionary with strings into one string
1722 def DictToString(d):
1723 return ','.join(map(':'.join, d.items()))
1724
1725 def usage():
1726 print >> sys.stderr, 'usage: xrced [-dhiv] [file]'
1727
1728 class App(wx.App):
1729 def OnInit(self):
1730 # Check version
1731 if wx.VERSION[:3] < MinWxVersion:
1732 wx.LogWarning('''\
1733 This version of XRCed may not work correctly on your version of wxWidgets. \
1734 Please upgrade wxWidgets to %d.%d.%d or higher.''' % MinWxVersion)
1735 global debug
1736 # Process comand-line
1737 opts = args = None
1738 try:
1739 opts, args = getopt.getopt(sys.argv[1:], 'dhiv')
1740 for o,a in opts:
1741 if o == '-h':
1742 usage()
1743 sys.exit(0)
1744 elif o == '-d':
1745 debug = True
1746 elif o == '-v':
1747 print 'XRCed version', version
1748 sys.exit(0)
1749
1750 except getopt.GetoptError:
1751 if wx.Platform != '__WXMAC__': # macs have some extra parameters
1752 print >> sys.stderr, 'Unknown option'
1753 usage()
1754 sys.exit(1)
1755
1756 self.SetAppName('xrced')
1757 # Settings
1758 global conf
1759 conf = g.conf = wx.Config(style = wx.CONFIG_USE_LOCAL_FILE)
1760 conf.localconf = None
1761 conf.autoRefresh = conf.ReadInt('autorefresh', True)
1762 pos = conf.ReadInt('x', -1), conf.ReadInt('y', -1)
1763 size = conf.ReadInt('width', 800), conf.ReadInt('height', 600)
1764 conf.embedPanel = conf.ReadInt('embedPanel', True)
1765 conf.showTools = conf.ReadInt('showTools', True)
1766 conf.sashPos = conf.ReadInt('sashPos', 200)
1767
1768 # read recently used files
1769 g.fileHistory = wx.FileHistory()
1770 g.fileHistory.Load(conf)
1771
1772 if not conf.embedPanel:
1773 conf.panelX = conf.ReadInt('panelX', -1)
1774 conf.panelY = conf.ReadInt('panelY', -1)
1775 else:
1776 conf.panelX = conf.panelY = -1
1777 conf.panelWidth = conf.ReadInt('panelWidth', 200)
1778 conf.panelHeight = conf.ReadInt('panelHeight', 200)
1779 conf.panic = not conf.HasEntry('nopanic')
1780 # Preferences
1781 conf.allowExec = conf.Read('Prefs/allowExec', 'ask')
1782 p = 'Prefs/sizeritem_defaults_panel'
1783 import xxx
1784 if conf.HasEntry(p):
1785 ##sys.modules['xxx'].xxxSizerItem.defaults_panel = ReadDictFromString(conf.Read(p))
1786 xxx.xxxSizerItem.defaults_panel = ReadDictFromString(conf.Read(p))
1787 p = 'Prefs/sizeritem_defaults_control'
1788 if conf.HasEntry(p):
1789 ##sys.modules['xxx'].xxxSizerItem.defaults_control = ReadDictFromString(conf.Read(p))
1790 xxx.xxxSizerItem.defaults_control = ReadDictFromString(conf.Read(p))
1791
1792 # Add handlers
1793 wx.FileSystem.AddHandler(wx.MemoryFSHandler())
1794 # Create main frame
1795 frame = Frame(pos, size)
1796 # Mac does not set the correct size
1797 if wx.Platform == '__WXMAC__':
1798 frame.SetClientSize(size)
1799 frame.Show(True)
1800
1801 # Load plugins
1802 plugins = os.getenv('XRCEDPATH')
1803 if plugins:
1804 cwd = os.getcwd()
1805 try:
1806 for dir in plugins.split(':'):
1807 if os.path.isdir(dir) and \
1808 os.path.isfile(os.path.join(dir, '__init__.py')):
1809 # Normalize
1810 dir = os.path.abspath(os.path.normpath(dir))
1811 sys.path = sys_path + [os.path.dirname(dir)]
1812 try:
1813 os.chdir(dir)
1814 __import__(os.path.basename(dir), globals(), locals(), ['*'])
1815 except:
1816 print traceback.print_exc()
1817 finally:
1818 os.chdir(cwd)
1819 # Store important data
1820 frame.handlers = getHandlers()[:]
1821 frame.custom = g.pullDownMenu.custom[:]
1822 frame.modules = sys.modules.copy()
1823
1824 # Initialize
1825 frame.Clear()
1826
1827 # Load file after showing
1828 if args:
1829 conf.panic = False
1830 frame.open = frame.Open(args[0])
1831
1832 return True
1833
1834 def OnExit(self):
1835 # Write config
1836 global conf
1837 wc = conf
1838 wc.WriteInt('autorefresh', conf.autoRefresh)
1839 wc.WriteInt('x', conf.x)
1840 wc.WriteInt('y', conf.y)
1841 wc.WriteInt('width', conf.width)
1842 wc.WriteInt('height', conf.height)
1843 wc.WriteInt('embedPanel', conf.embedPanel)
1844 wc.WriteInt('showTools', conf.showTools)
1845 if not conf.embedPanel:
1846 wc.WriteInt('panelX', conf.panelX)
1847 wc.WriteInt('panelY', conf.panelY)
1848 wc.WriteInt('sashPos', conf.sashPos)
1849 wc.WriteInt('panelWidth', conf.panelWidth)
1850 wc.WriteInt('panelHeight', conf.panelHeight)
1851 wc.WriteInt('nopanic', 1)
1852 g.fileHistory.Save(wc)
1853 # Preferences
1854 wc.DeleteGroup('Prefs')
1855 wc.Write('Prefs/allowExec', conf.allowExec)
1856 import xxx
1857 ##v = sys.modules['xxx'].xxxSizerItem.defaults_panel
1858 v = xxx.xxxSizerItem.defaults_panel
1859 if v: wc.Write('Prefs/sizeritem_defaults_panel', DictToString(v))
1860 ###v = sys.modules['xxx'].xxxSizerItem.defaults_control
1861 v = xxx.xxxSizerItem.defaults_control
1862 if v: wc.Write('Prefs/sizeritem_defaults_control', DictToString(v))
1863
1864 wc.Flush()
1865
1866 def main():
1867 app = App(0, useBestVisual=False)
1868 #app.SetAssertMode(wx.PYAPP_ASSERT_LOG)
1869 app.MainLoop()
1870 app.OnExit()
1871 global conf
1872 del conf
1873
1874 if __name__ == '__main__':
1875 main()