]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/tools/XRCed/xrced.py
Add some tips on fault navigation after input from Phlip
[wxWidgets.git] / wxPython / wx / tools / XRCed / xrced.py
CommitLineData
d14a1e28
RD
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$
1fded56b 6
d14a1e28 7"""
1fded56b 8
d14a1e28
RD
9xrced -- Simple resource editor for XRC format used by wxWindows/wxPython
10 GUI toolkit.
11
12Usage:
13
14 xrced [ -h ] [ -v ] [ XRC-file ]
15
16Options:
17
18 -h output short usage info and exit
19
20 -v output version info and exit
21"""
22
23
24from globals import *
25import os, sys, getopt, re, traceback
26
27# Local modules
28from tree import * # imports xxx which imports params
29from panel import *
30from tools import *
31# Cleanup recursive import sideeffects, otherwise we can't create undoMan
32import undo
33undo.ParamPage = ParamPage
34undoMan = g.undoMan = UndoManager()
35
36# Set application path for loading resources
37if __name__ == '__main__':
38 basePath = os.path.dirname(sys.argv[0])
39else:
40 basePath = os.path.dirname(__file__)
41
42# 1 adds CMD command to Help menu
43debug = 0
44
45g.helpText = """\
46<HTML><H2>Welcome to XRC<font color="blue">ed</font></H2><H3><font color="green">DON'T PANIC :)</font></H3>
47Read this note before clicking on anything!<P>
48To start select tree root, then popup menu with your right mouse button,
49select "Append Child", and then any command.<P>
50Or just press one of the buttons on the tools palette.<P>
51Enter XML ID, change properties, create children.<P>
52To test your interface select Test command (View menu).<P>
53Consult README file for the details.</HTML>
54"""
55
56defaultIDs = {xxxPanel:'PANEL', xxxDialog:'DIALOG', xxxFrame:'FRAME',
64bce500
RR
57 xxxMenuBar:'MENUBAR', xxxMenu:'MENU', xxxToolBar:'TOOLBAR',
58 xxxWizard:'WIZARD'}
d14a1e28
RD
59
60################################################################################
61
62# ScrolledMessageDialog - modified from wxPython lib to set fixed-width font
63class ScrolledMessageDialog(wxDialog):
64 def __init__(self, parent, msg, caption, pos = wxDefaultPosition, size = (500,300)):
65 from wxPython.lib.layoutf import Layoutf
66 wxDialog.__init__(self, parent, -1, caption, pos, size)
67 text = wxTextCtrl(self, -1, msg, wxDefaultPosition,
68 wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY)
289128a4 69 text.SetFont(g.modernFont())
d14a1e28
RD
70 dc = wxWindowDC(text)
71 # !!! possible bug - GetTextExtent without font returns sysfont dims
289128a4 72 w, h = dc.GetFullTextExtent(' ', g.modernFont())[:2]
d14a1e28
RD
73 ok = wxButton(self, wxID_OK, "OK")
74 text.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok)))
75 text.SetSize((w * 80 + 30, h * 40))
364a2be0 76 text.ShowPosition(1)
d14a1e28
RD
77 ok.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self,)))
78 self.SetAutoLayout(True)
79 self.Fit()
80 self.CenterOnScreen(wxBOTH)
81
82################################################################################
83
fd919451
RR
84# Event handler for using during location
85class Locator(wxEvtHandler):
86 def ProcessEvent(self, evt):
87 print evt
88
d14a1e28
RD
89class Frame(wxFrame):
90 def __init__(self, pos, size):
91 wxFrame.__init__(self, None, -1, '', pos, size)
92 global frame
93 frame = g.frame = self
94 bar = self.CreateStatusBar(2)
95 bar.SetStatusWidths([-1, 40])
96 self.SetIcon(images.getIconIcon())
97
98 # Idle flag
99 self.inIdle = False
100
64bce500
RR
101 # Load our own resources
102 self.res = wxXmlResource('')
103 # !!! Blocking of assert failure occuring in older unicode builds
104 try:
105 self.res.Load(os.path.join(basePath, 'xrced.xrc'))
106 except wx._core.PyAssertionError:
107 print 'PyAssertionError was ignored'
108
d14a1e28
RD
109 # Make menus
110 menuBar = wxMenuBar()
111
112 menu = wxMenu()
113 menu.Append(wxID_NEW, '&New\tCtrl-N', 'New file')
80389ff7 114 menu.AppendSeparator()
d14a1e28 115 menu.Append(wxID_OPEN, '&Open...\tCtrl-O', 'Open XRC file')
80389ff7
RR
116 self.recentMenu = wxMenu()
117 self.AppendRecent(self.recentMenu)
118 menu.AppendMenu(-1, 'Open Recent', self.recentMenu, 'Open a recent file')
119 menu.AppendSeparator()
d14a1e28
RD
120 menu.Append(wxID_SAVE, '&Save\tCtrl-S', 'Save XRC file')
121 menu.Append(wxID_SAVEAS, 'Save &As...', 'Save XRC file under different name')
122 menu.AppendSeparator()
123 menu.Append(wxID_EXIT, '&Quit\tCtrl-Q', 'Exit application')
80389ff7 124
d14a1e28
RD
125 menuBar.Append(menu, '&File')
126
127 menu = wxMenu()
128 menu.Append(wxID_UNDO, '&Undo\tCtrl-Z', 'Undo')
129 menu.Append(wxID_REDO, '&Redo\tCtrl-Y', 'Redo')
130 menu.AppendSeparator()
131 menu.Append(wxID_CUT, 'Cut\tCtrl-X', 'Cut to the clipboard')
132 menu.Append(wxID_COPY, '&Copy\tCtrl-C', 'Copy to the clipboard')
133 menu.Append(wxID_PASTE, '&Paste\tCtrl-V', 'Paste from the clipboard')
134 self.ID_DELETE = wxNewId()
135 menu.Append(self.ID_DELETE, '&Delete\tCtrl-D', 'Delete object')
64bce500 136 menu.AppendSeparator()
fd919451 137 self.ID_LOCATE = wxNewId()
64bce500 138 self.ID_LOCATE_TOOL = wxNewId()
fd919451 139 menu.Append(self.ID_LOCATE, '&Locate\tCtrl-L', 'Locate control in test window and select it')
d14a1e28
RD
140 menuBar.Append(menu, '&Edit')
141
142 menu = wxMenu()
143 self.ID_EMBED_PANEL = wxNewId()
144 menu.Append(self.ID_EMBED_PANEL, '&Embed Panel',
145 'Toggle embedding properties panel in the main window', True)
146 menu.Check(self.ID_EMBED_PANEL, conf.embedPanel)
147 self.ID_SHOW_TOOLS = wxNewId()
148 menu.Append(self.ID_SHOW_TOOLS, 'Show &Tools', 'Toggle tools', True)
149 menu.Check(self.ID_SHOW_TOOLS, conf.showTools)
150 menu.AppendSeparator()
151 self.ID_TEST = wxNewId()
fd919451 152 menu.Append(self.ID_TEST, '&Test\tF5', 'Show test window')
d14a1e28
RD
153 self.ID_REFRESH = wxNewId()
154 menu.Append(self.ID_REFRESH, '&Refresh\tCtrl-R', 'Refresh test window')
155 self.ID_AUTO_REFRESH = wxNewId()
156 menu.Append(self.ID_AUTO_REFRESH, '&Auto-refresh\tCtrl-A',
157 'Toggle auto-refresh mode', True)
158 menu.Check(self.ID_AUTO_REFRESH, conf.autoRefresh)
64bce500
RR
159 self.ID_TEST_HIDE = wxNewId()
160 menu.Append(self.ID_TEST_HIDE, '&Hide\tCtrl-H', 'Close test window')
d14a1e28
RD
161 menuBar.Append(menu, '&View')
162
163 menu = wxMenu()
164 menu.Append(wxID_ABOUT, '&About...', 'About XCRed')
165 self.ID_README = wxNewId()
166 menu.Append(self.ID_README, '&Readme...', 'View the README file')
167 if debug:
168 self.ID_DEBUG_CMD = wxNewId()
169 menu.Append(self.ID_DEBUG_CMD, 'CMD', 'Python command line')
170 EVT_MENU(self, self.ID_DEBUG_CMD, self.OnDebugCMD)
171 menuBar.Append(menu, '&Help')
172
173 self.menuBar = menuBar
174 self.SetMenuBar(menuBar)
175
176 # Create toolbar
177 tb = self.CreateToolBar(wxTB_HORIZONTAL | wxNO_BORDER | wxTB_FLAT)
178 tb.SetToolBitmapSize((24, 23))
179 tb.AddSimpleTool(wxID_NEW, images.getNewBitmap(), 'New', 'New file')
180 tb.AddSimpleTool(wxID_OPEN, images.getOpenBitmap(), 'Open', 'Open file')
181 tb.AddSimpleTool(wxID_SAVE, images.getSaveBitmap(), 'Save', 'Save file')
182 tb.AddControl(wxStaticLine(tb, -1, size=(-1,23), style=wxLI_VERTICAL))
183 tb.AddSimpleTool(wxID_UNDO, images.getUndoBitmap(), 'Undo', 'Undo')
184 tb.AddSimpleTool(wxID_REDO, images.getRedoBitmap(), 'Redo', 'Redo')
185 tb.AddControl(wxStaticLine(tb, -1, size=(-1,23), style=wxLI_VERTICAL))
186 tb.AddSimpleTool(wxID_CUT, images.getCutBitmap(), 'Cut', 'Cut')
187 tb.AddSimpleTool(wxID_COPY, images.getCopyBitmap(), 'Copy', 'Copy')
188 tb.AddSimpleTool(wxID_PASTE, images.getPasteBitmap(), 'Paste', 'Paste')
189 tb.AddControl(wxStaticLine(tb, -1, size=(-1,23), style=wxLI_VERTICAL))
64bce500
RR
190 tb.AddCheckTool(self.ID_LOCATE_TOOL,
191 images.getLocateBitmap(), images.getLocateArmedBitmap(),
192 'Locate', 'Locate control in test window and select it')
193 tb.AddControl(wxStaticLine(tb, -1, size=(-1,23), style=wxLI_VERTICAL))
d14a1e28
RD
194 tb.AddSimpleTool(self.ID_TEST, images.getTestBitmap(), 'Test', 'Test window')
195 tb.AddSimpleTool(self.ID_REFRESH, images.getRefreshBitmap(),
196 'Refresh', 'Refresh view')
197 tb.AddSimpleTool(self.ID_AUTO_REFRESH, images.getAutoRefreshBitmap(),
198 'Auto-refresh', 'Toggle auto-refresh mode', True)
199 if wxPlatform == '__WXGTK__':
200 tb.AddSeparator() # otherwise auto-refresh sticks in status line
201 tb.ToggleTool(self.ID_AUTO_REFRESH, conf.autoRefresh)
202 tb.Realize()
64bce500 203
d14a1e28
RD
204 self.tb = tb
205 self.minWidth = tb.GetSize()[0] # minimal width is the size of toolbar
206
207 # File
208 EVT_MENU(self, wxID_NEW, self.OnNew)
209 EVT_MENU(self, wxID_OPEN, self.OnOpen)
210 EVT_MENU(self, wxID_SAVE, self.OnSaveOrSaveAs)
211 EVT_MENU(self, wxID_SAVEAS, self.OnSaveOrSaveAs)
212 EVT_MENU(self, wxID_EXIT, self.OnExit)
213 # Edit
214 EVT_MENU(self, wxID_UNDO, self.OnUndo)
215 EVT_MENU(self, wxID_REDO, self.OnRedo)
216 EVT_MENU(self, wxID_CUT, self.OnCutDelete)
217 EVT_MENU(self, wxID_COPY, self.OnCopy)
218 EVT_MENU(self, wxID_PASTE, self.OnPaste)
219 EVT_MENU(self, self.ID_DELETE, self.OnCutDelete)
fd919451 220 EVT_MENU(self, self.ID_LOCATE, self.OnLocate)
64bce500 221 EVT_MENU(self, self.ID_LOCATE_TOOL, self.OnLocate)
d14a1e28
RD
222 # View
223 EVT_MENU(self, self.ID_EMBED_PANEL, self.OnEmbedPanel)
224 EVT_MENU(self, self.ID_SHOW_TOOLS, self.OnShowTools)
225 EVT_MENU(self, self.ID_TEST, self.OnTest)
226 EVT_MENU(self, self.ID_REFRESH, self.OnRefresh)
227 EVT_MENU(self, self.ID_AUTO_REFRESH, self.OnAutoRefresh)
64bce500 228 EVT_MENU(self, self.ID_TEST_HIDE, self.OnTestHide)
d14a1e28
RD
229 # Help
230 EVT_MENU(self, wxID_ABOUT, self.OnAbout)
231 EVT_MENU(self, self.ID_README, self.OnReadme)
232
233 # Update events
234 EVT_UPDATE_UI(self, wxID_CUT, self.OnUpdateUI)
235 EVT_UPDATE_UI(self, wxID_COPY, self.OnUpdateUI)
236 EVT_UPDATE_UI(self, wxID_PASTE, self.OnUpdateUI)
64bce500
RR
237 EVT_UPDATE_UI(self, self.ID_LOCATE, self.OnUpdateUI)
238 EVT_UPDATE_UI(self, self.ID_LOCATE_TOOL, self.OnUpdateUI)
d14a1e28
RD
239 EVT_UPDATE_UI(self, wxID_UNDO, self.OnUpdateUI)
240 EVT_UPDATE_UI(self, wxID_REDO, self.OnUpdateUI)
241 EVT_UPDATE_UI(self, self.ID_DELETE, self.OnUpdateUI)
242 EVT_UPDATE_UI(self, self.ID_TEST, self.OnUpdateUI)
243 EVT_UPDATE_UI(self, self.ID_REFRESH, self.OnUpdateUI)
244
245 # Build interface
246 sizer = wxBoxSizer(wxVERTICAL)
247 sizer.Add(wxStaticLine(self, -1), 0, wxEXPAND)
248 # Horizontal sizer for toolbar and splitter
249 self.toolsSizer = sizer1 = wxBoxSizer()
250 splitter = wxSplitterWindow(self, -1, style=wxSP_3DSASH)
251 self.splitter = splitter
252 splitter.SetMinimumPaneSize(100)
253 # Create tree
254 global tree
255 g.tree = tree = XML_Tree(splitter, -1)
256
257 # Init pull-down menu data
258 global pullDownMenu
259 g.pullDownMenu = pullDownMenu = PullDownMenu(self)
260
261 # Vertical toolbar for GUI buttons
262 g.tools = tools = Tools(self)
263 tools.Show(conf.showTools)
264 if conf.showTools: sizer1.Add(tools, 0, wxEXPAND)
265
266 tree.RegisterKeyEvents()
267
268 # !!! frame styles are broken
269 # Miniframe for not embedded mode
270 miniFrame = wxFrame(self, -1, 'Properties Panel',
271 (conf.panelX, conf.panelY),
272 (conf.panelWidth, conf.panelHeight))
273 self.miniFrame = miniFrame
274 sizer2 = wxBoxSizer()
275 miniFrame.SetAutoLayout(True)
276 miniFrame.SetSizer(sizer2)
277 EVT_CLOSE(self.miniFrame, self.OnCloseMiniFrame)
278 # Create panel for parameters
279 global panel
280 if conf.embedPanel:
281 panel = Panel(splitter)
282 # Set plitter windows
283 splitter.SplitVertically(tree, panel, conf.sashPos)
284 else:
285 panel = Panel(miniFrame)
286 sizer2.Add(panel, 1, wxEXPAND)
287 miniFrame.Show(True)
288 splitter.Initialize(tree)
289 sizer1.Add(splitter, 1, wxEXPAND)
290 sizer.Add(sizer1, 1, wxEXPAND)
291 self.SetAutoLayout(True)
292 self.SetSizer(sizer)
293
294 # Initialize
295 self.clipboard = None
296 self.Clear()
297
298 # Other events
299 EVT_IDLE(self, self.OnIdle)
300 EVT_CLOSE(self, self.OnCloseWindow)
d14a1e28
RD
301 EVT_KEY_DOWN(self, tools.OnKeyDown)
302 EVT_KEY_UP(self, tools.OnKeyUp)
80389ff7
RR
303
304 def AppendRecent(self, menu):
305 # add recently used files to the menu
306 for id,name in conf.recentfiles.iteritems():
307 menu.Append(id,name)
308 EVT_MENU(self,id,self.OnRecentFile)
309 return
310
311 def OnRecentFile(self,evt):
312 # open recently used file
313 if not self.AskSave(): return
314 wxBeginBusyCursor()
315 try:
316 path=conf.recentfiles[evt.GetId()]
317 if self.Open(path):
318 self.SetStatusText('Data loaded')
319 else:
320 self.SetStatusText('Failed')
321 except KeyError:
322 self.SetStatusText('No such file')
323 wxEndBusyCursor()
d14a1e28
RD
324
325 def OnNew(self, evt):
326 if not self.AskSave(): return
327 self.Clear()
328
329 def OnOpen(self, evt):
330 if not self.AskSave(): return
331 dlg = wxFileDialog(self, 'Open', os.path.dirname(self.dataFile),
332 '', '*.xrc', wxOPEN | wxCHANGE_DIR)
333 if dlg.ShowModal() == wxID_OK:
334 path = dlg.GetPath()
335 self.SetStatusText('Loading...')
336 wxYield()
337 wxBeginBusyCursor()
338 if self.Open(path):
339 self.SetStatusText('Data loaded')
340 else:
341 self.SetStatusText('Failed')
80389ff7 342 self.SaveRecent(path)
d14a1e28
RD
343 wxEndBusyCursor()
344 dlg.Destroy()
345
346 def OnSaveOrSaveAs(self, evt):
347 if evt.GetId() == wxID_SAVEAS or not self.dataFile:
348 if self.dataFile: defaultName = ''
349 else: defaultName = 'UNTITLED.xrc'
fd919451
RR
350 dirname = os.path.dirname(self.dataFile)
351 dlg = wxFileDialog(self, 'Save As', dirname, defaultName, '*.xrc',
d14a1e28
RD
352 wxSAVE | wxOVERWRITE_PROMPT | wxCHANGE_DIR)
353 if dlg.ShowModal() == wxID_OK:
354 path = dlg.GetPath()
355 dlg.Destroy()
356 else:
357 dlg.Destroy()
358 return
359 else:
360 path = self.dataFile
361 self.SetStatusText('Saving...')
362 wxYield()
363 wxBeginBusyCursor()
364 try:
365 self.Save(path)
366 self.dataFile = path
367 self.SetStatusText('Data saved')
80389ff7 368 self.SaveRecent(path)
d14a1e28
RD
369 except IOError:
370 self.SetStatusText('Failed')
80389ff7
RR
371 wxEndBusyCursor()
372
373 def SaveRecent(self,path):
374 # append to recently used files
375 if path not in conf.recentfiles.values():
376 newid = wxNewId()
377 self.recentMenu.Append(newid, path)
378 EVT_MENU(self, newid, self.OnRecentFile)
379 conf.recentfiles[newid] = path
d14a1e28
RD
380
381 def OnExit(self, evt):
382 self.Close()
383
384 def OnUndo(self, evt):
385 # Extra check to not mess with idle updating
386 if undoMan.CanUndo():
387 undoMan.Undo()
388
389 def OnRedo(self, evt):
390 if undoMan.CanRedo():
391 undoMan.Redo()
392
393 def OnCopy(self, evt):
394 selected = tree.selection
395 if not selected: return # key pressed event
396 xxx = tree.GetPyData(selected)
397 self.clipboard = xxx.element.cloneNode(True)
398 self.SetStatusText('Copied')
399
400 def OnPaste(self, evt):
401 selected = tree.selection
402 if not selected: return # key pressed event
403 # For pasting with Ctrl pressed
404 if evt.GetId() == pullDownMenu.ID_PASTE_SIBLING: appendChild = False
405 else: appendChild = not tree.NeedInsert(selected)
406 xxx = tree.GetPyData(selected)
407 if not appendChild:
408 # If has next item, insert, else append to parent
409 nextItem = tree.GetNextSibling(selected)
410 parentLeaf = tree.GetItemParent(selected)
411 # Expanded container (must have children)
412 elif tree.IsExpanded(selected) and tree.GetChildrenCount(selected, False):
413 # Insert as first child
a4c013b2 414 nextItem = tree.GetFirstChild(selected)[0]
d14a1e28
RD
415 parentLeaf = selected
416 else:
417 # No children or unexpanded item - appendChild stays True
418 nextItem = wxTreeItemId() # no next item
419 parentLeaf = selected
420 parent = tree.GetPyData(parentLeaf).treeObject()
421
422 # Create a copy of clipboard element
423 elem = self.clipboard.cloneNode(True)
424 # Tempopary xxx object to test things
425 xxx = MakeXXXFromDOM(parent, elem)
426
427 # Check compatibility
428 error = False
429 # Top-level
430 x = xxx.treeObject()
64bce500 431 if x.__class__ in [xxxDialog, xxxFrame, xxxMenuBar, xxxWizard]:
d14a1e28
RD
432 # Top-level classes
433 if parent.__class__ != xxxMainNode: error = True
434 elif x.__class__ == xxxToolBar:
435 # Toolbar can be top-level of child of panel or frame
436 if parent.__class__ not in [xxxMainNode, xxxPanel, xxxFrame]: error = True
437 elif x.__class__ == xxxPanel and parent.__class__ == xxxMainNode:
438 pass
439 elif x.__class__ == xxxSpacer:
440 if not parent.isSizer: error = True
441 elif x.__class__ == xxxSeparator:
442 if not parent.__class__ in [xxxMenu, xxxToolBar]: error = True
443 elif x.__class__ == xxxTool:
444 if parent.__class__ != xxxToolBar: error = True
445 elif x.__class__ == xxxMenu:
446 if not parent.__class__ in [xxxMainNode, xxxMenuBar, xxxMenu]: error = True
447 elif x.__class__ == xxxMenuItem:
448 if not parent.__class__ in [xxxMenuBar, xxxMenu]: error = True
449 elif x.isSizer and parent.__class__ == xxxNotebook: error = True
450 else: # normal controls can be almost anywhere
451 if parent.__class__ == xxxMainNode or \
452 parent.__class__ in [xxxMenuBar, xxxMenu]: error = True
453 if error:
454 if parent.__class__ == xxxMainNode: parentClass = 'root'
455 else: parentClass = parent.className
456 wxLogError('Incompatible parent/child: parent is %s, child is %s!' %
457 (parentClass, x.className))
458 return
459
460 # Check parent and child relationships.
461 # If parent is sizer or notebook, child is of wrong class or
462 # parent is normal window, child is child container then detach child.
463 isChildContainer = isinstance(xxx, xxxChildContainer)
464 if isChildContainer and \
465 ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
466 (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
467 not (parent.isSizer or isinstance(parent, xxxNotebook))):
468 elem.removeChild(xxx.child.element) # detach child
469 elem.unlink() # delete child container
470 elem = xxx.child.element # replace
471 # This may help garbage collection
472 xxx.child.parent = None
473 isChildContainer = False
474 # Parent is sizer or notebook, child is not child container
475 if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer):
476 # Create sizer item element
477 sizerItemElem = MakeEmptyDOM('sizeritem')
478 sizerItemElem.appendChild(elem)
479 elem = sizerItemElem
480 elif isinstance(parent, xxxNotebook) and not isChildContainer:
481 pageElem = MakeEmptyDOM('notebookpage')
482 pageElem.appendChild(elem)
483 elem = pageElem
484 # Insert new node, register undo
485 newItem = tree.InsertNode(parentLeaf, parent, elem, nextItem)
486 undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
487 # Scroll to show new item (!!! redundant?)
488 tree.EnsureVisible(newItem)
489 tree.SelectItem(newItem)
490 if not tree.IsVisible(newItem):
491 tree.ScrollTo(newItem)
492 tree.Refresh()
493 # Update view?
494 if g.testWin and tree.IsHighlatable(newItem):
495 if conf.autoRefresh:
496 tree.needUpdate = True
497 tree.pendingHighLight = newItem
498 else:
499 tree.pendingHighLight = None
500 self.modified = True
501 self.SetStatusText('Pasted')
502
503 def OnCutDelete(self, evt):
504 selected = tree.selection
505 if not selected: return # key pressed event
506 # Undo info
507 if evt.GetId() == wxID_CUT:
508 self.lastOp = 'CUT'
509 status = 'Removed to clipboard'
510 else:
511 self.lastOp = 'DELETE'
512 status = 'Deleted'
513 # Delete testWin?
514 if g.testWin:
515 # If deleting top-level item, delete testWin
516 if selected == g.testWin.item:
517 g.testWin.Destroy()
518 g.testWin = None
519 else:
520 # Remove highlight, update testWin
521 if g.testWin.highLight:
522 g.testWin.highLight.Remove()
523 tree.needUpdate = True
524 # Prepare undo data
525 panel.Apply()
526 index = tree.ItemFullIndex(selected)
527 parent = tree.GetPyData(tree.GetItemParent(selected)).treeObject()
528 elem = tree.RemoveLeaf(selected)
529 undoMan.RegisterUndo(UndoCutDelete(index, parent, elem))
530 if evt.GetId() == wxID_CUT:
531 if self.clipboard: self.clipboard.unlink()
532 self.clipboard = elem.cloneNode(True)
533 tree.pendingHighLight = None
534 tree.Unselect()
535 panel.Clear()
536 self.modified = True
537 self.SetStatusText(status)
538
2481bf3c
RR
539 def OnSubclass(self, evt):
540 selected = tree.selection
541 xxx = tree.GetPyData(selected).treeObject()
542 elem = xxx.element
543 subclass = xxx.subclass
544 dlg = wxTextEntryDialog(self, 'Subclass:', defaultValue=subclass)
545 if dlg.ShowModal() == wxID_OK:
546 subclass = dlg.GetValue()
547 if subclass:
548 elem.setAttribute('subclass', subclass)
549 self.modified = True
550 elif elem.hasAttribute('subclass'):
551 elem.removeAttribute('subclass')
552 self.modified = True
553 xxx.subclass = elem.getAttribute('subclass')
554 tree.SetItemText(selected, xxx.treeName())
555 panel.pages[0].box.SetLabel(xxx.panelName())
556 dlg.Destroy()
557
d14a1e28
RD
558 def OnEmbedPanel(self, evt):
559 conf.embedPanel = evt.IsChecked()
560 if conf.embedPanel:
561 # Remember last dimentions
562 conf.panelX, conf.panelY = self.miniFrame.GetPosition()
563 conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize()
564 size = self.GetSize()
565 pos = self.GetPosition()
566 sizePanel = panel.GetSize()
567 panel.Reparent(self.splitter)
80389ff7 568 self.miniFrame.GetSizer().Remove(panel)
d14a1e28
RD
569 wxYield()
570 # Widen
571 self.SetDimensions(pos.x, pos.y, size.width + sizePanel.width, size.height)
572 self.splitter.SplitVertically(tree, panel, conf.sashPos)
573 self.miniFrame.Show(False)
574 else:
575 conf.sashPos = self.splitter.GetSashPosition()
576 pos = self.GetPosition()
577 size = self.GetSize()
578 sizePanel = panel.GetSize()
579 self.splitter.Unsplit(panel)
580 sizer = self.miniFrame.GetSizer()
581 panel.Reparent(self.miniFrame)
582 panel.Show(True)
583 sizer.Add(panel, 1, wxEXPAND)
584 self.miniFrame.Show(True)
585 self.miniFrame.SetDimensions(conf.panelX, conf.panelY,
586 conf.panelWidth, conf.panelHeight)
587 wxYield()
588 # Reduce width
589 self.SetDimensions(pos.x, pos.y,
590 max(size.width - sizePanel.width, self.minWidth), size.height)
591
592 def OnShowTools(self, evt):
593 conf.showTools = evt.IsChecked()
594 g.tools.Show(conf.showTools)
595 if conf.showTools:
596 self.toolsSizer.Prepend(g.tools, 0, wxEXPAND)
597 else:
598 self.toolsSizer.Remove(g.tools)
599 self.toolsSizer.Layout()
600
601 def OnTest(self, evt):
602 if not tree.selection: return # key pressed event
603 tree.ShowTestWindow(tree.selection)
604
64bce500
RR
605 def OnTestHide(self, evt):
606 tree.CloseTestWindow()
607
fd919451
RR
608 # Find object by relative position
609 def FindObject(self, item, obj):
610 # We simply perform depth-first traversal, sinse it's too much
611 # hassle to deal with all sizer/window combinations
612 w = tree.FindNodeObject(item)
613 if w == obj:
614 return item
615 if tree.ItemHasChildren(item):
616 child = tree.GetFirstChild(item)[0]
617 while child:
618 found = self.FindObject(child, obj)
619 if found: return found
620 child = tree.GetNextSibling(child)
621 return None
622
623 def OnTestWinLeftDown(self, evt):
624 pos = evt.GetPosition()
625 self.SetHandler(g.testWin)
626 g.testWin.Disconnect(wxID_ANY, wxID_ANY, wxEVT_LEFT_DOWN)
627 item = self.FindObject(g.testWin.item, evt.GetEventObject())
628 if item:
629 tree.SelectItem(item)
64bce500
RR
630 self.tb.ToggleTool(self.ID_LOCATE_TOOL, False)
631 if item:
632 self.SetStatusText('Selected %s' % tree.GetItemText(item))
633 else:
634 self.SetStatusText('Locate failed!')
fd919451
RR
635
636 def SetHandler(self, w, h=None):
637 if h:
638 w.SetEventHandler(h)
639 w.SetCursor(wxCROSS_CURSOR)
640 else:
641 w.SetEventHandler(w)
642 w.SetCursor(wxNullCursor)
643 for ch in w.GetChildren():
644 self.SetHandler(ch, h)
645
646 def OnLocate(self, evt):
647 if g.testWin:
64bce500
RR
648 if evt.GetId() == self.ID_LOCATE or \
649 evt.GetId() == self.ID_LOCATE_TOOL and evt.IsChecked():
650 self.SetHandler(g.testWin, g.testWin)
651 g.testWin.Connect(wxID_ANY, wxID_ANY, wxEVT_LEFT_DOWN, self.OnTestWinLeftDown)
652 if evt.GetId() == self.ID_LOCATE:
653 self.tb.ToggleTool(self.ID_LOCATE_TOOL, True)
654 elif evt.GetId() == self.ID_LOCATE_TOOL and not evt.IsChecked():
655 self.SetHandler(g.testWin, None)
656 g.testWin.Disconnect(wxID_ANY, wxID_ANY, wxEVT_LEFT_DOWN)
657 self.SetStatusText('Click somewhere in your test window now')
fd919451 658
d14a1e28
RD
659 def OnRefresh(self, evt):
660 # If modified, apply first
661 selection = tree.selection
662 if selection:
663 xxx = tree.GetPyData(selection)
664 if xxx and panel.IsModified():
665 tree.Apply(xxx, selection)
666 if g.testWin:
667 # (re)create
668 tree.CreateTestWin(g.testWin.item)
669 panel.modified = False
670 tree.needUpdate = False
671
672 def OnAutoRefresh(self, evt):
673 conf.autoRefresh = evt.IsChecked()
674 self.menuBar.Check(self.ID_AUTO_REFRESH, conf.autoRefresh)
675 self.tb.ToggleTool(self.ID_AUTO_REFRESH, conf.autoRefresh)
676
677 def OnAbout(self, evt):
678 str = '''\
679XRCed version %s
680
681(c) Roman Rolinsky <rollrom@users.sourceforge.net>
682Homepage: http://xrced.sourceforge.net\
683''' % version
684 dlg = wxMessageDialog(self, str, 'About XRCed', wxOK | wxCENTRE)
685 dlg.ShowModal()
686 dlg.Destroy()
687
688 def OnReadme(self, evt):
689 text = open(os.path.join(basePath, 'README.txt'), 'r').read()
690 dlg = ScrolledMessageDialog(self, text, "XRCed README")
691 dlg.ShowModal()
692 dlg.Destroy()
693
694 # Simple emulation of python command line
695 def OnDebugCMD(self, evt):
696 import traceback
697 while 1:
698 try:
699 exec raw_input('C:\> ')
700 except EOFError:
701 print '^D'
702 break
703 except:
704 (etype, value, tb) =sys.exc_info()
705 tblist =traceback.extract_tb(tb)[1:]
706 msg =' '.join(traceback.format_exception_only(etype, value)
707 +traceback.format_list(tblist))
708 print msg
709
710 def OnCreate(self, evt):
711 selected = tree.selection
712 if tree.ctrl: appendChild = False
713 else: appendChild = not tree.NeedInsert(selected)
714 xxx = tree.GetPyData(selected)
715 if not appendChild:
716 # If insert before
717 if tree.shift:
718 # If has previous item, insert after it, else append to parent
719 nextItem = selected
720 parentLeaf = tree.GetItemParent(selected)
721 else:
722 # If has next item, insert, else append to parent
723 nextItem = tree.GetNextSibling(selected)
724 parentLeaf = tree.GetItemParent(selected)
725 # Expanded container (must have children)
726 elif tree.shift and tree.IsExpanded(selected) \
727 and tree.GetChildrenCount(selected, False):
a4c013b2 728 nextItem = tree.GetFirstChild(selected)[0]
d14a1e28
RD
729 parentLeaf = selected
730 else:
731 nextItem = wxTreeItemId()
732 parentLeaf = selected
733 parent = tree.GetPyData(parentLeaf)
734 if parent.hasChild: parent = parent.child
735
736 # Create element
737 className = pullDownMenu.createMap[evt.GetId()]
738 xxx = MakeEmptyXXX(parent, className)
739
740 # Set default name for top-level windows
741 if parent.__class__ == xxxMainNode:
742 cl = xxx.treeObject().__class__
743 frame.maxIDs[cl] += 1
744 xxx.treeObject().name = '%s%d' % (defaultIDs[cl], frame.maxIDs[cl])
745 xxx.treeObject().element.setAttribute('name', xxx.treeObject().name)
746
747 # Insert new node, register undo
748 elem = xxx.element
749 newItem = tree.InsertNode(parentLeaf, parent, elem, nextItem)
750 undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
751 tree.EnsureVisible(newItem)
752 tree.SelectItem(newItem)
753 if not tree.IsVisible(newItem):
754 tree.ScrollTo(newItem)
755 tree.Refresh()
756 # Update view?
757 if g.testWin and tree.IsHighlatable(newItem):
758 if conf.autoRefresh:
759 tree.needUpdate = True
760 tree.pendingHighLight = newItem
761 else:
762 tree.pendingHighLight = None
763 tree.SetFocus()
764 self.modified = True
765
766 # Replace one object with another
767 def OnReplace(self, evt):
768 selected = tree.selection
769 xxx = tree.GetPyData(selected).treeObject()
770 elem = xxx.element
771 parent = elem.parentNode
772 parentXXX = xxx.parent
773 # New class
774 className = pullDownMenu.createMap[evt.GetId() - 1000]
775 # Create temporary empty node (with default values)
776 dummy = MakeEmptyDOM(className)
777 xxxClass = xxxDict[className]
778 # Remove non-compatible children
779 if tree.ItemHasChildren(selected) and not xxxClass.hasChildren:
780 tree.DeleteChildren(selected)
781 nodes = elem.childNodes[:]
782 tags = []
783 for node in nodes:
64bce500 784 if node.nodeType != minidom.Node.ELEMENT_NODE: continue
d14a1e28
RD
785 remove = False
786 tag = node.tagName
787 if tag == 'object':
788 if not xxxClass.hasChildren:
789 remove = True
790 elif tag not in xxxClass.allParams and \
791 (not xxxClass.hasStyle or tag not in xxxClass.styles):
792 remove = True
793 else:
794 tags.append(tag)
795 if remove:
796 elem.removeChild(node)
797 node.unlink()
798
799 # Copy parameters present in dummy but not in elem
800 for node in dummy.childNodes:
801 tag = node.tagName
802 if tag not in tags:
803 elem.appendChild(node.cloneNode(True))
804 dummy.unlink()
805 # Change class name
806 elem.setAttribute('class', className)
64bce500
RR
807 if elem.hasAttribute('subclass'):
808 elem.removeAttribute('subclass') # clear subclassing
d14a1e28
RD
809 # Re-create xxx element
810 xxx = MakeXXXFromDOM(parentXXX, elem)
811 # Update parent in child objects
812 if tree.ItemHasChildren(selected):
a4c013b2 813 i, cookie = tree.GetFirstChild(selected)
d14a1e28
RD
814 while i.IsOk():
815 x = tree.GetPyData(i)
816 x.parent = xxx
817 if x.hasChild: x.child.parent = xxx
818 i, cookie = tree.GetNextChild(selected, cookie)
819
820 # Update tree
821 if tree.GetPyData(selected).hasChild: # child container
822 container = tree.GetPyData(selected)
823 container.child = xxx
824 container.hasChildren = xxx.hasChildren
825 container.isSizer = xxx.isSizer
826 else:
827 tree.SetPyData(selected, xxx)
828 tree.SetItemText(selected, xxx.treeName())
829 tree.SetItemImage(selected, xxx.treeImage())
830
831 # Set default name for top-level windows
832 if parent.__class__ == xxxMainNode:
833 cl = xxx.treeObject().__class__
834 frame.maxIDs[cl] += 1
835 xxx.treeObject().name = '%s%d' % (defaultIDs[cl], frame.maxIDs[cl])
836 xxx.treeObject().element.setAttribute('name', xxx.treeObject().name)
837
838 # Update panel
839 g.panel.SetData(xxx)
840 # Update tools
841 g.tools.UpdateUI()
842
843 #undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
844 # Update view?
845 if g.testWin and tree.IsHighlatable(selected):
846 if conf.autoRefresh:
847 tree.needUpdate = True
848 tree.pendingHighLight = selected
849 else:
850 tree.pendingHighLight = None
851 tree.SetFocus()
852 self.modified = True
853
854 # Expand/collapse subtree
855 def OnExpand(self, evt):
856 if tree.selection: tree.ExpandAll(tree.selection)
857 else: tree.ExpandAll(tree.root)
858 def OnCollapse(self, evt):
859 if tree.selection: tree.CollapseAll(tree.selection)
860 else: tree.CollapseAll(tree.root)
861
862 def OnPullDownHighlight(self, evt):
863 menuId = evt.GetMenuId()
864 if menuId != -1:
865 menu = evt.GetEventObject()
866 help = menu.GetHelpString(menuId)
867 self.SetStatusText(help)
868 else:
869 self.SetStatusText('')
870
871 def OnUpdateUI(self, evt):
872 if evt.GetId() in [wxID_CUT, wxID_COPY, self.ID_DELETE]:
873 evt.Enable(tree.selection is not None and tree.selection != tree.root)
874 elif evt.GetId() == wxID_PASTE:
875 evt.Enable((self.clipboard and tree.selection) != None)
876 elif evt.GetId() == self.ID_TEST:
877 evt.Enable(tree.selection is not None and tree.selection != tree.root)
64bce500
RR
878 elif evt.GetId() in [self.ID_LOCATE, self.ID_LOCATE_TOOL]:
879 evt.Enable(g.testWin is not None)
d14a1e28
RD
880 elif evt.GetId() == wxID_UNDO: evt.Enable(undoMan.CanUndo())
881 elif evt.GetId() == wxID_REDO: evt.Enable(undoMan.CanRedo())
882
883 def OnIdle(self, evt):
884 if self.inIdle: return # Recursive call protection
885 self.inIdle = True
886 if tree.needUpdate:
887 if conf.autoRefresh:
888 if g.testWin:
889 self.SetStatusText('Refreshing test window...')
890 # (re)create
891 tree.CreateTestWin(g.testWin.item)
892 wxYield()
893 self.SetStatusText('')
894 tree.needUpdate = False
895 elif tree.pendingHighLight:
896 tree.HighLight(tree.pendingHighLight)
897 else:
898 evt.Skip()
899 self.inIdle = False
900
901 # We don't let close panel window
902 def OnCloseMiniFrame(self, evt):
903 return
904
905 def OnCloseWindow(self, evt):
906 if not self.AskSave(): return
907 if g.testWin: g.testWin.Destroy()
d14a1e28
RD
908 if not panel.GetPageCount() == 2:
909 panel.page2.Destroy()
80389ff7
RR
910 else:
911 # If we don't do this, page does not get destroyed (a bug?)
912 panel.RemovePage(1)
3429f8d0
RD
913 if not self.IsIconized():
914 conf.x, conf.y = self.GetPosition()
915 conf.width, conf.height = self.GetSize()
916 if conf.embedPanel:
917 conf.sashPos = self.splitter.GetSashPosition()
918 else:
919 conf.panelX, conf.panelY = self.miniFrame.GetPosition()
920 conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize()
d14a1e28
RD
921 evt.Skip()
922
923 def Clear(self):
924 self.dataFile = ''
925 if self.clipboard:
926 self.clipboard.unlink()
927 self.clipboard = None
928 undoMan.Clear()
929 self.modified = False
930 tree.Clear()
931 panel.Clear()
932 if g.testWin:
933 g.testWin.Destroy()
934 g.testWin = None
935 self.SetTitle(progname)
936 # Numbers for new controls
937 self.maxIDs = {}
938 self.maxIDs[xxxPanel] = self.maxIDs[xxxDialog] = self.maxIDs[xxxFrame] = \
64bce500
RR
939 self.maxIDs[xxxMenuBar] = self.maxIDs[xxxMenu] = self.maxIDs[xxxToolBar] = \
940 self.maxIDs[xxxWizard] = 0
d14a1e28
RD
941
942 def Open(self, path):
943 if not os.path.exists(path):
944 wxLogError('File does not exists: %s' % path)
945 return False
946 # Try to read the file
947 try:
948 f = open(path)
949 self.Clear()
d14a1e28 950 dom = minidom.parse(f)
d14a1e28 951 f.close()
7353d818 952 # Set encoding global variable
759c619e 953 if dom.encoding: g.currentEncoding = dom.encoding
d14a1e28 954 # Change dir
fd919451 955 self.dataFile = path = os.path.abspath(path)
d14a1e28
RD
956 dir = os.path.dirname(path)
957 if dir: os.chdir(dir)
958 tree.SetData(dom)
d14a1e28
RD
959 self.SetTitle(progname + ': ' + os.path.basename(path))
960 except:
961 # Nice exception printing
962 inf = sys.exc_info()
963 wxLogError(traceback.format_exception(inf[0], inf[1], None)[-1])
964 wxLogError('Error reading file: %s' % path)
965 return False
966 return True
967
968 def Indent(self, node, indent = 0):
969 # Copy child list because it will change soon
970 children = node.childNodes[:]
971 # Main node doesn't need to be indented
972 if indent:
973 text = self.domCopy.createTextNode('\n' + ' ' * indent)
974 node.parentNode.insertBefore(text, node)
975 if children:
976 # Append newline after last child, except for text nodes
977 if children[-1].nodeType == minidom.Node.ELEMENT_NODE:
978 text = self.domCopy.createTextNode('\n' + ' ' * indent)
979 node.appendChild(text)
980 # Indent children which are elements
981 for n in children:
982 if n.nodeType == minidom.Node.ELEMENT_NODE:
983 self.Indent(n, indent + 2)
984
985 def Save(self, path):
986 try:
7353d818 987 import codecs
d14a1e28
RD
988 # Apply changes
989 if tree.selection and panel.IsModified():
990 self.OnRefresh(wxCommandEvent())
7353d818 991 f = codecs.open(path, 'w', g.currentEncoding)
d14a1e28
RD
992 # Make temporary copy for formatting it
993 # !!! We can't clone dom node, it works only once
994 #self.domCopy = tree.dom.cloneNode(True)
995 self.domCopy = MyDocument()
996 mainNode = self.domCopy.appendChild(tree.mainNode.cloneNode(True))
997 self.Indent(mainNode)
7353d818 998 self.domCopy.writexml(f, encoding = g.currentEncoding)
d14a1e28
RD
999 f.close()
1000 self.domCopy.unlink()
1001 self.domCopy = None
1002 self.modified = False
1003 panel.SetModified(False)
1004 except:
1005 wxLogError('Error writing file: %s' % path)
1006 raise
1007
1008 def AskSave(self):
1009 if not (self.modified or panel.IsModified()): return True
1010 flags = wxICON_EXCLAMATION | wxYES_NO | wxCANCEL | wxCENTRE
1011 dlg = wxMessageDialog( self, 'File is modified. Save before exit?',
1012 'Save before too late?', flags )
1013 say = dlg.ShowModal()
1014 dlg.Destroy()
1015 if say == wxID_YES:
1016 self.OnSaveOrSaveAs(wxCommandEvent(wxID_SAVE))
1017 # If save was successful, modified flag is unset
1018 if not self.modified: return True
1019 elif say == wxID_NO:
1020 self.modified = False
1021 panel.SetModified(False)
1022 return True
1023 return False
1024
1025 def SaveUndo(self):
1026 pass # !!!
1027
1028################################################################################
1029
1030def usage():
1031 print >> sys.stderr, 'usage: xrced [-dhiv] [file]'
1032
1033class App(wxApp):
1034 def OnInit(self):
1035 global debug
1036 # Process comand-line
364a2be0 1037 opts = args = None
d14a1e28
RD
1038 try:
1039 opts, args = getopt.getopt(sys.argv[1:], 'dhiv')
1c01bc8e
RD
1040 for o,a in opts:
1041 if o == '-h':
1042 usage()
1043 sys.exit(0)
1044 elif o == '-d':
1045 debug = True
1046 elif o == '-v':
1047 print 'XRCed version', version
1048 sys.exit(0)
1049
d14a1e28
RD
1050 except getopt.GetoptError:
1051 if wxPlatform != '__WXMAC__': # macs have some extra parameters
1052 print >> sys.stderr, 'Unknown option'
1053 usage()
1054 sys.exit(1)
d14a1e28
RD
1055
1056 self.SetAppName('xrced')
1057 # Settings
1058 global conf
1059 conf = g.conf = wxConfig(style = wxCONFIG_USE_LOCAL_FILE)
1060 conf.autoRefresh = conf.ReadInt('autorefresh', True)
1061 pos = conf.ReadInt('x', -1), conf.ReadInt('y', -1)
1062 size = conf.ReadInt('width', 800), conf.ReadInt('height', 600)
1063 conf.embedPanel = conf.ReadInt('embedPanel', True)
1064 conf.showTools = conf.ReadInt('showTools', True)
1065 conf.sashPos = conf.ReadInt('sashPos', 200)
80389ff7
RR
1066 # read recently used files
1067 recentfiles=conf.Read('recentFiles','')
1068 conf.recentfiles={}
1069 if recentfiles:
1070 for fil in recentfiles.split('|'):
1071 conf.recentfiles[wxNewId()]=fil
d14a1e28
RD
1072 if not conf.embedPanel:
1073 conf.panelX = conf.ReadInt('panelX', -1)
1074 conf.panelY = conf.ReadInt('panelY', -1)
1075 else:
1076 conf.panelX = conf.panelY = -1
1077 conf.panelWidth = conf.ReadInt('panelWidth', 200)
1078 conf.panelHeight = conf.ReadInt('panelHeight', 200)
1079 conf.panic = not conf.HasEntry('nopanic')
1080 # Add handlers
1081 wxFileSystem_AddHandler(wxMemoryFSHandler())
1082 wxInitAllImageHandlers()
1083 # Create main frame
1084 frame = Frame(pos, size)
1085 frame.Show(True)
d14a1e28
RD
1086
1087 # Load file after showing
1088 if args:
1089 conf.panic = False
1090 frame.open = frame.Open(args[0])
1091
1092 return True
1093
1094 def OnExit(self):
1095 # Write config
1096 global conf
1097 wc = wxConfigBase_Get()
1098 wc.WriteInt('autorefresh', conf.autoRefresh)
1099 wc.WriteInt('x', conf.x)
1100 wc.WriteInt('y', conf.y)
1101 wc.WriteInt('width', conf.width)
1102 wc.WriteInt('height', conf.height)
1103 wc.WriteInt('embedPanel', conf.embedPanel)
1104 wc.WriteInt('showTools', conf.showTools)
1105 if not conf.embedPanel:
1106 wc.WriteInt('panelX', conf.panelX)
1107 wc.WriteInt('panelY', conf.panelY)
1108 wc.WriteInt('sashPos', conf.sashPos)
1109 wc.WriteInt('panelWidth', conf.panelWidth)
1110 wc.WriteInt('panelHeight', conf.panelHeight)
1111 wc.WriteInt('nopanic', True)
80389ff7 1112 wc.Write('recentFiles', '|'.join(conf.recentfiles.values()[-5:]))
d14a1e28
RD
1113 wc.Flush()
1114
1115def main():
1116 app = App(0, useBestVisual=False)
a4c013b2 1117 #app.SetAssertMode(wxPYAPP_ASSERT_LOG)
d14a1e28
RD
1118 app.MainLoop()
1119 app.OnExit()
1120 global conf
1121 del conf
1122
1123if __name__ == '__main__':
1124 main()