2 # Purpose: XRC editor, main module
3 # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
9 xrced -- Simple resource editor for XRC format used by wxWindows/wxPython
14 xrced [ -h ] [ -i ] [ -v ] [ XRC-file ]
18 -h output short usage info and exit
20 -i use international character set instead of translations
22 -v output version info and exit
27 import os
, sys
, getopt
, re
, traceback
30 from tree
import * # imports xxx which imports params
33 # Cleanup recursive import sideeffects, otherwise we can't create undoMan
35 undo
.ParamPage
= ParamPage
36 undoMan
= g
.undoMan
= UndoManager()
38 # Set application path for loading resources
39 if __name__
== '__main__':
40 basePath
= os
.path
.dirname(sys
.argv
[0])
42 basePath
= os
.path
.dirname(__file__
)
44 # 1 adds CMD command to Help menu
48 <HTML><H2>Welcome to XRC<font color="blue">ed</font></H2><H3><font color="green">DON'T PANIC :)</font></H3>
49 Read this note before clicking on anything!<P>
50 To start select tree root, then popup menu with your right mouse button,
51 select "Append Child", and then any command.<P>
52 Or just press one of the buttons on the tools palette.<P>
53 Enter XML ID, change properties, create children.<P>
54 To test your interface select Test command (View menu).<P>
55 Consult README file for the details.</HTML>
58 defaultIDs
= {xxxPanel
:'PANEL', xxxDialog
:'DIALOG', xxxFrame
:'FRAME',
59 xxxMenuBar
:'MENUBAR', xxxMenu
:'MENU', xxxToolBar
:'TOOLBAR'}
61 ################################################################################
63 # ScrolledMessageDialog - modified from wxPython lib to set fixed-width font
64 class ScrolledMessageDialog(wxDialog
):
65 def __init__(self
, parent
, msg
, caption
, pos
= wxDefaultPosition
, size
= (500,300)):
66 from wxPython
.lib
.layoutf
import Layoutf
67 wxDialog
.__init
__(self
, parent
, -1, caption
, pos
, size
)
68 text
= wxTextCtrl(self
, -1, msg
, wxDefaultPosition
,
69 wxDefaultSize
, wxTE_MULTILINE | wxTE_READONLY
)
70 text
.SetFont(modernFont
)
72 # !!! possible bug - GetTextExtent without font returns sysfont dims
73 w
, h
= dc
.GetFullTextExtent(' ', modernFont
)[:2]
74 ok
= wxButton(self
, wxID_OK
, "OK")
75 text
.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self
,ok
)))
76 text
.SetSize((w
* 80 + 30, h
* 40))
77 ok
.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self
,)))
78 self
.SetAutoLayout(True)
80 self
.CenterOnScreen(wxBOTH
)
82 ################################################################################
85 def __init__(self
, pos
, size
):
86 wxFrame
.__init
__(self
, None, -1, '', pos
, size
)
88 frame
= g
.frame
= self
89 bar
= self
.CreateStatusBar(2)
90 bar
.SetStatusWidths([-1, 40])
91 self
.SetIcon(images
.getIconIcon())
100 menu
.Append(wxID_NEW
, '&New\tCtrl-N', 'New file')
101 menu
.Append(wxID_OPEN
, '&Open...\tCtrl-O', 'Open XRC file')
102 menu
.Append(wxID_SAVE
, '&Save\tCtrl-S', 'Save XRC file')
103 menu
.Append(wxID_SAVEAS
, 'Save &As...', 'Save XRC file under different name')
104 menu
.AppendSeparator()
105 menu
.Append(wxID_EXIT
, '&Quit\tCtrl-Q', 'Exit application')
106 menuBar
.Append(menu
, '&File')
109 menu
.Append(wxID_UNDO
, '&Undo\tCtrl-Z', 'Undo')
110 menu
.Append(wxID_REDO
, '&Redo\tCtrl-Y', 'Redo')
111 menu
.AppendSeparator()
112 menu
.Append(wxID_CUT
, 'Cut\tCtrl-X', 'Cut to the clipboard')
113 menu
.Append(wxID_COPY
, '&Copy\tCtrl-C', 'Copy to the clipboard')
114 menu
.Append(wxID_PASTE
, '&Paste\tCtrl-V', 'Paste from the clipboard')
115 self
.ID_DELETE
= wxNewId()
116 menu
.Append(self
.ID_DELETE
, '&Delete\tCtrl-D', 'Delete object')
117 # menu.AppendSeparator()
118 ID_SELECT
= wxNewId()
119 # menu.Append(ID_SELECT, '&Select', 'Select object')
120 menuBar
.Append(menu
, '&Edit')
123 self
.ID_EMBED_PANEL
= wxNewId()
124 menu
.Append(self
.ID_EMBED_PANEL
, '&Embed Panel',
125 'Toggle embedding properties panel in the main window', True)
126 menu
.Check(self
.ID_EMBED_PANEL
, conf
.embedPanel
)
127 self
.ID_SHOW_TOOLS
= wxNewId()
128 menu
.Append(self
.ID_SHOW_TOOLS
, 'Show &Tools', 'Toggle tools', True)
129 menu
.Check(self
.ID_SHOW_TOOLS
, conf
.showTools
)
130 menu
.AppendSeparator()
131 self
.ID_TEST
= wxNewId()
132 menu
.Append(self
.ID_TEST
, '&Test\tF5', 'Test window')
133 self
.ID_REFRESH
= wxNewId()
134 menu
.Append(self
.ID_REFRESH
, '&Refresh\tCtrl-R', 'Refresh test window')
135 self
.ID_AUTO_REFRESH
= wxNewId()
136 menu
.Append(self
.ID_AUTO_REFRESH
, '&Auto-refresh\tCtrl-A',
137 'Toggle auto-refresh mode', True)
138 menu
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
139 menuBar
.Append(menu
, '&View')
142 menu
.Append(wxID_ABOUT
, '&About...', 'About XCRed')
143 self
.ID_README
= wxNewId()
144 menu
.Append(self
.ID_README
, '&Readme...', 'View the README file')
146 self
.ID_DEBUG_CMD
= wxNewId()
147 menu
.Append(self
.ID_DEBUG_CMD
, 'CMD', 'Python command line')
148 EVT_MENU(self
, self
.ID_DEBUG_CMD
, self
.OnDebugCMD
)
149 menuBar
.Append(menu
, '&Help')
151 self
.menuBar
= menuBar
152 self
.SetMenuBar(menuBar
)
155 tb
= self
.CreateToolBar(wxTB_HORIZONTAL | wxNO_BORDER | wxTB_FLAT
)
156 tb
.SetToolBitmapSize((24, 23))
157 tb
.AddSimpleTool(wxID_NEW
, images
.getNewBitmap(), 'New', 'New file')
158 tb
.AddSimpleTool(wxID_OPEN
, images
.getOpenBitmap(), 'Open', 'Open file')
159 tb
.AddSimpleTool(wxID_SAVE
, images
.getSaveBitmap(), 'Save', 'Save file')
160 tb
.AddControl(wxStaticLine(tb
, -1, size
=(-1,23), style
=wxLI_VERTICAL
))
161 tb
.AddSimpleTool(wxID_UNDO
, images
.getUndoBitmap(), 'Undo', 'Undo')
162 tb
.AddSimpleTool(wxID_REDO
, images
.getRedoBitmap(), 'Redo', 'Redo')
163 tb
.AddControl(wxStaticLine(tb
, -1, size
=(-1,23), style
=wxLI_VERTICAL
))
164 tb
.AddSimpleTool(wxID_CUT
, images
.getCutBitmap(), 'Cut', 'Cut')
165 tb
.AddSimpleTool(wxID_COPY
, images
.getCopyBitmap(), 'Copy', 'Copy')
166 tb
.AddSimpleTool(wxID_PASTE
, images
.getPasteBitmap(), 'Paste', 'Paste')
167 tb
.AddControl(wxStaticLine(tb
, -1, size
=(-1,23), style
=wxLI_VERTICAL
))
168 tb
.AddSimpleTool(self
.ID_TEST
, images
.getTestBitmap(), 'Test', 'Test window')
169 tb
.AddSimpleTool(self
.ID_REFRESH
, images
.getRefreshBitmap(),
170 'Refresh', 'Refresh view')
171 tb
.AddSimpleTool(self
.ID_AUTO_REFRESH
, images
.getAutoRefreshBitmap(),
172 'Auto-refresh', 'Toggle auto-refresh mode', True)
173 if wxPlatform
== '__WXGTK__':
174 tb
.AddSeparator() # otherwise auto-refresh sticks in status line
175 tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
178 self
.minWidth
= tb
.GetSize()[0] # minimal width is the size of toolbar
181 EVT_MENU(self
, wxID_NEW
, self
.OnNew
)
182 EVT_MENU(self
, wxID_OPEN
, self
.OnOpen
)
183 EVT_MENU(self
, wxID_SAVE
, self
.OnSaveOrSaveAs
)
184 EVT_MENU(self
, wxID_SAVEAS
, self
.OnSaveOrSaveAs
)
185 EVT_MENU(self
, wxID_EXIT
, self
.OnExit
)
187 EVT_MENU(self
, wxID_UNDO
, self
.OnUndo
)
188 EVT_MENU(self
, wxID_REDO
, self
.OnRedo
)
189 EVT_MENU(self
, wxID_CUT
, self
.OnCutDelete
)
190 EVT_MENU(self
, wxID_COPY
, self
.OnCopy
)
191 EVT_MENU(self
, wxID_PASTE
, self
.OnPaste
)
192 EVT_MENU(self
, self
.ID_DELETE
, self
.OnCutDelete
)
193 EVT_MENU(self
, ID_SELECT
, self
.OnSelect
)
195 EVT_MENU(self
, self
.ID_EMBED_PANEL
, self
.OnEmbedPanel
)
196 EVT_MENU(self
, self
.ID_SHOW_TOOLS
, self
.OnShowTools
)
197 EVT_MENU(self
, self
.ID_TEST
, self
.OnTest
)
198 EVT_MENU(self
, self
.ID_REFRESH
, self
.OnRefresh
)
199 EVT_MENU(self
, self
.ID_AUTO_REFRESH
, self
.OnAutoRefresh
)
201 EVT_MENU(self
, wxID_ABOUT
, self
.OnAbout
)
202 EVT_MENU(self
, self
.ID_README
, self
.OnReadme
)
205 EVT_UPDATE_UI(self
, wxID_CUT
, self
.OnUpdateUI
)
206 EVT_UPDATE_UI(self
, wxID_COPY
, self
.OnUpdateUI
)
207 EVT_UPDATE_UI(self
, wxID_PASTE
, self
.OnUpdateUI
)
208 EVT_UPDATE_UI(self
, wxID_UNDO
, self
.OnUpdateUI
)
209 EVT_UPDATE_UI(self
, wxID_REDO
, self
.OnUpdateUI
)
210 EVT_UPDATE_UI(self
, self
.ID_DELETE
, self
.OnUpdateUI
)
211 EVT_UPDATE_UI(self
, self
.ID_TEST
, self
.OnUpdateUI
)
212 EVT_UPDATE_UI(self
, self
.ID_REFRESH
, self
.OnUpdateUI
)
215 sizer
= wxBoxSizer(wxVERTICAL
)
216 sizer
.Add(wxStaticLine(self
, -1), 0, wxEXPAND
)
217 # Horizontal sizer for toolbar and splitter
218 self
.toolsSizer
= sizer1
= wxBoxSizer()
219 splitter
= wxSplitterWindow(self
, -1, style
=wxSP_3DSASH
)
220 self
.splitter
= splitter
221 splitter
.SetMinimumPaneSize(100)
224 g
.tree
= tree
= XML_Tree(splitter
, -1)
226 # Init pull-down menu data
228 g
.pullDownMenu
= pullDownMenu
= PullDownMenu(self
)
230 # Vertical toolbar for GUI buttons
231 g
.tools
= tools
= Tools(self
)
232 tools
.Show(conf
.showTools
)
233 if conf
.showTools
: sizer1
.Add(tools
, 0, wxEXPAND
)
235 tree
.RegisterKeyEvents()
237 # !!! frame styles are broken
238 # Miniframe for not embedded mode
239 miniFrame
= wxFrame(self
, -1, 'Properties Panel',
240 (conf
.panelX
, conf
.panelY
),
241 (conf
.panelWidth
, conf
.panelHeight
))
242 self
.miniFrame
= miniFrame
243 sizer2
= wxBoxSizer()
244 miniFrame
.SetAutoLayout(True)
245 miniFrame
.SetSizer(sizer2
)
246 EVT_CLOSE(self
.miniFrame
, self
.OnCloseMiniFrame
)
247 # Create panel for parameters
250 panel
= Panel(splitter
)
251 # Set plitter windows
252 splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
254 panel
= Panel(miniFrame
)
255 sizer2
.Add(panel
, 1, wxEXPAND
)
257 splitter
.Initialize(tree
)
258 sizer1
.Add(splitter
, 1, wxEXPAND
)
259 sizer
.Add(sizer1
, 1, wxEXPAND
)
260 self
.SetAutoLayout(True)
264 self
.clipboard
= None
268 EVT_IDLE(self
, self
.OnIdle
)
269 EVT_CLOSE(self
, self
.OnCloseWindow
)
270 EVT_LEFT_DOWN(self
, self
.OnLeftDown
)
271 EVT_KEY_DOWN(self
, tools
.OnKeyDown
)
272 EVT_KEY_UP(self
, tools
.OnKeyUp
)
274 def OnNew(self
, evt
):
277 def OnOpen(self
, evt
):
278 if not self
.AskSave(): return
279 dlg
= wxFileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
),
280 '', '*.xrc', wxOPEN | wxCHANGE_DIR
)
281 if dlg
.ShowModal() == wxID_OK
:
283 self
.SetStatusText('Loading...')
287 self
.SetStatusText('Data loaded')
289 self
.SetStatusText('Failed')
293 def OnSaveOrSaveAs(self
, evt
):
294 if evt
.GetId() == wxID_SAVEAS
or not self
.dataFile
:
295 if self
.dataFile
: defaultName
= ''
296 else: defaultName
= 'UNTITLED.xrc'
297 dlg
= wxFileDialog(self
, 'Save As', os
.path
.dirname(self
.dataFile
),
298 defaultName
, '*.xrc',
299 wxSAVE | wxOVERWRITE_PROMPT | wxCHANGE_DIR
)
300 if dlg
.ShowModal() == wxID_OK
:
308 self
.SetStatusText('Saving...')
314 self
.SetStatusText('Data saved')
316 self
.SetStatusText('Failed')
319 def OnExit(self
, evt
):
322 def OnUndo(self
, evt
):
323 # Extra check to not mess with idle updating
324 if undoMan
.CanUndo():
327 def OnRedo(self
, evt
):
328 if undoMan
.CanRedo():
331 def OnCopy(self
, evt
):
332 selected
= tree
.selection
333 if not selected
: return # key pressed event
334 xxx
= tree
.GetPyData(selected
)
335 self
.clipboard
= xxx
.element
.cloneNode(True)
336 self
.SetStatusText('Copied')
338 def OnPaste(self
, evt
):
339 selected
= tree
.selection
340 if not selected
: return # key pressed event
341 # For pasting with Ctrl pressed
342 if evt
.GetId() == pullDownMenu
.ID_PASTE_SIBLING
: appendChild
= False
343 else: appendChild
= not tree
.NeedInsert(selected
)
344 xxx
= tree
.GetPyData(selected
)
346 # If has next item, insert, else append to parent
347 nextItem
= tree
.GetNextSibling(selected
)
348 parentLeaf
= tree
.GetItemParent(selected
)
349 # Expanded container (must have children)
350 elif tree
.IsExpanded(selected
) and tree
.GetChildrenCount(selected
, False):
351 # Insert as first child
352 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
353 parentLeaf
= selected
355 # No children or unexpanded item - appendChild stays True
356 nextItem
= wxTreeItemId() # no next item
357 parentLeaf
= selected
358 parent
= tree
.GetPyData(parentLeaf
).treeObject()
360 # Create a copy of clipboard element
361 elem
= self
.clipboard
.cloneNode(True)
362 # Tempopary xxx object to test things
363 xxx
= MakeXXXFromDOM(parent
, elem
)
365 # Check compatibility
369 if x
.__class
__ in [xxxDialog
, xxxFrame
, xxxMenuBar
]:
371 if parent
.__class
__ != xxxMainNode
: error
= True
372 elif x
.__class
__ == xxxToolBar
:
373 # Toolbar can be top-level of child of panel or frame
374 if parent
.__class
__ not in [xxxMainNode
, xxxPanel
, xxxFrame
]: error
= True
375 elif x
.__class
__ == xxxPanel
and parent
.__class
__ == xxxMainNode
:
377 elif x
.__class
__ == xxxSpacer
:
378 if not parent
.isSizer
: error
= True
379 elif x
.__class
__ == xxxSeparator
:
380 if not parent
.__class
__ in [xxxMenu
, xxxToolBar
]: error
= True
381 elif x
.__class
__ == xxxTool
:
382 if parent
.__class
__ != xxxToolBar
: error
= True
383 elif x
.__class
__ == xxxMenu
:
384 if not parent
.__class
__ in [xxxMainNode
, xxxMenuBar
, xxxMenu
]: error
= True
385 elif x
.__class
__ == xxxMenuItem
:
386 if not parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= True
387 elif x
.isSizer
and parent
.__class
__ == xxxNotebook
: error
= True
388 else: # normal controls can be almost anywhere
389 if parent
.__class
__ == xxxMainNode
or \
390 parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= True
392 if parent
.__class
__ == xxxMainNode
: parentClass
= 'root'
393 else: parentClass
= parent
.className
394 wxLogError('Incompatible parent/child: parent is %s, child is %s!' %
395 (parentClass
, x
.className
))
398 # Check parent and child relationships.
399 # If parent is sizer or notebook, child is of wrong class or
400 # parent is normal window, child is child container then detach child.
401 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
402 if isChildContainer
and \
403 ((parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
404 (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
405 not (parent
.isSizer
or isinstance(parent
, xxxNotebook
))):
406 elem
.removeChild(xxx
.child
.element
) # detach child
407 elem
.unlink() # delete child container
408 elem
= xxx
.child
.element
# replace
409 # This may help garbage collection
410 xxx
.child
.parent
= None
411 isChildContainer
= False
412 # Parent is sizer or notebook, child is not child container
413 if parent
.isSizer
and not isChildContainer
and not isinstance(xxx
, xxxSpacer
):
414 # Create sizer item element
415 sizerItemElem
= MakeEmptyDOM('sizeritem')
416 sizerItemElem
.appendChild(elem
)
418 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
419 pageElem
= MakeEmptyDOM('notebookpage')
420 pageElem
.appendChild(elem
)
422 # Insert new node, register undo
423 newItem
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
)
424 undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
))
425 # Scroll to show new item (!!! redundant?)
426 tree
.EnsureVisible(newItem
)
427 tree
.SelectItem(newItem
)
428 if not tree
.IsVisible(newItem
):
429 tree
.ScrollTo(newItem
)
432 if g
.testWin
and tree
.IsHighlatable(newItem
):
434 tree
.needUpdate
= True
435 tree
.pendingHighLight
= newItem
437 tree
.pendingHighLight
= None
439 self
.SetStatusText('Pasted')
441 def OnCutDelete(self
, evt
):
442 selected
= tree
.selection
443 if not selected
: return # key pressed event
445 if evt
.GetId() == wxID_CUT
:
447 status
= 'Removed to clipboard'
449 self
.lastOp
= 'DELETE'
453 # If deleting top-level item, delete testWin
454 if selected
== g
.testWin
.item
:
458 # Remove highlight, update testWin
459 if g
.testWin
.highLight
:
460 g
.testWin
.highLight
.Remove()
461 tree
.needUpdate
= True
464 index
= tree
.ItemFullIndex(selected
)
465 parent
= tree
.GetPyData(tree
.GetItemParent(selected
)).treeObject()
466 elem
= tree
.RemoveLeaf(selected
)
467 undoMan
.RegisterUndo(UndoCutDelete(index
, parent
, elem
))
468 if evt
.GetId() == wxID_CUT
:
469 if self
.clipboard
: self
.clipboard
.unlink()
470 self
.clipboard
= elem
.cloneNode(True)
471 tree
.pendingHighLight
= None
475 self
.SetStatusText(status
)
477 def OnSelect(self
, evt
):
478 print >> sys
.stderr
, 'Xperimental function!'
480 self
.SetCursor(wxCROSS_CURSOR
)
483 def OnLeftDown(self
, evt
):
484 pos
= evt
.GetPosition()
485 self
.SetCursor(wxNullCursor
)
488 def OnEmbedPanel(self
, evt
):
489 conf
.embedPanel
= evt
.IsChecked()
491 # Remember last dimentions
492 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
493 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
494 size
= self
.GetSize()
495 pos
= self
.GetPosition()
496 sizePanel
= panel
.GetSize()
497 panel
.Reparent(self
.splitter
)
498 self
.miniFrame
.GetSizer().RemoveWindow(panel
)
501 self
.SetDimensions(pos
.x
, pos
.y
, size
.x
+ sizePanel
.x
, size
.y
)
502 self
.splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
503 self
.miniFrame
.Show(False)
505 conf
.sashPos
= self
.splitter
.GetSashPosition()
506 pos
= self
.GetPosition()
507 size
= self
.GetSize()
508 sizePanel
= panel
.GetSize()
509 self
.splitter
.Unsplit(panel
)
510 sizer
= self
.miniFrame
.GetSizer()
511 panel
.Reparent(self
.miniFrame
)
513 sizer
.Add(panel
, 1, wxEXPAND
)
514 self
.miniFrame
.Show(True)
515 self
.miniFrame
.SetDimensions(conf
.panelX
, conf
.panelY
,
516 conf
.panelWidth
, conf
.panelHeight
)
519 self
.SetDimensions(pos
.x
, pos
.y
,
520 max(size
.x
- sizePanel
.x
, self
.minWidth
), size
.y
)
522 def OnShowTools(self
, evt
):
523 conf
.showTools
= evt
.IsChecked()
524 g
.tools
.Show(conf
.showTools
)
526 self
.toolsSizer
.Prepend(g
.tools
, 0, wxEXPAND
)
528 self
.toolsSizer
.Remove(g
.tools
)
529 self
.toolsSizer
.Layout()
531 def OnTest(self
, evt
):
532 if not tree
.selection
: return # key pressed event
533 tree
.ShowTestWindow(tree
.selection
)
535 def OnRefresh(self
, evt
):
536 # If modified, apply first
537 selection
= tree
.selection
539 xxx
= tree
.GetPyData(selection
)
540 if xxx
and panel
.IsModified():
541 tree
.Apply(xxx
, selection
)
544 tree
.CreateTestWin(g
.testWin
.item
)
545 panel
.modified
= False
546 tree
.needUpdate
= False
548 def OnAutoRefresh(self
, evt
):
549 conf
.autoRefresh
= evt
.IsChecked()
550 self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
551 self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
553 def OnAbout(self
, evt
):
557 (c) Roman Rolinsky <rollrom@users.sourceforge.net>
558 Homepage: http://xrced.sourceforge.net\
560 dlg
= wxMessageDialog(self
, str, 'About XRCed', wxOK | wxCENTRE
)
564 def OnReadme(self
, evt
):
565 text
= open(os
.path
.join(basePath
, 'README.txt'), 'r').read()
566 dlg
= ScrolledMessageDialog(self
, text
, "XRCed README")
570 # Simple emulation of python command line
571 def OnDebugCMD(self
, evt
):
575 exec raw_input('C:\> ')
580 (etype
, value
, tb
) =sys
.exc_info()
581 tblist
=traceback
.extract_tb(tb
)[1:]
582 msg
=' '.join(traceback
.format_exception_only(etype
, value
)
583 +traceback
.format_list(tblist
))
586 def OnCreate(self
, evt
):
587 selected
= tree
.selection
588 if tree
.ctrl
: appendChild
= False
589 else: appendChild
= not tree
.NeedInsert(selected
)
590 xxx
= tree
.GetPyData(selected
)
594 # If has previous item, insert after it, else append to parent
596 parentLeaf
= tree
.GetItemParent(selected
)
598 # If has next item, insert, else append to parent
599 nextItem
= tree
.GetNextSibling(selected
)
600 parentLeaf
= tree
.GetItemParent(selected
)
601 # Expanded container (must have children)
602 elif tree
.shift
and tree
.IsExpanded(selected
) \
603 and tree
.GetChildrenCount(selected
, False):
604 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
605 parentLeaf
= selected
607 nextItem
= wxTreeItemId()
608 parentLeaf
= selected
609 parent
= tree
.GetPyData(parentLeaf
)
610 if parent
.hasChild
: parent
= parent
.child
613 className
= pullDownMenu
.createMap
[evt
.GetId()]
614 xxx
= MakeEmptyXXX(parent
, className
)
616 # Set default name for top-level windows
617 if parent
.__class
__ == xxxMainNode
:
618 cl
= xxx
.treeObject().__class
__
619 frame
.maxIDs
[cl
] += 1
620 xxx
.treeObject().name
= '%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
])
621 xxx
.treeObject().element
.setAttribute('name', xxx
.treeObject().name
)
623 # Insert new node, register undo
625 newItem
= tree
.InsertNode(parentLeaf
, parent
, elem
, nextItem
)
626 undoMan
.RegisterUndo(UndoPasteCreate(parentLeaf
, parent
, newItem
, selected
))
627 tree
.EnsureVisible(newItem
)
628 tree
.SelectItem(newItem
)
629 if not tree
.IsVisible(newItem
):
630 tree
.ScrollTo(newItem
)
633 if g
.testWin
and tree
.IsHighlatable(newItem
):
635 tree
.needUpdate
= True
636 tree
.pendingHighLight
= newItem
638 tree
.pendingHighLight
= None
641 # Expand/collapse subtree
642 def OnExpand(self
, evt
):
643 if tree
.selection
: tree
.ExpandAll(tree
.selection
)
644 else: tree
.ExpandAll(tree
.root
)
645 def OnCollapse(self
, evt
):
646 if tree
.selection
: tree
.CollapseAll(tree
.selection
)
647 else: tree
.CollapseAll(tree
.root
)
649 def OnPullDownHighlight(self
, evt
):
650 menuId
= evt
.GetMenuId()
652 menu
= evt
.GetEventObject()
653 help = menu
.GetHelpString(menuId
)
654 self
.SetStatusText(help)
656 self
.SetStatusText('')
658 def OnUpdateUI(self
, evt
):
659 if evt
.GetId() in [wxID_CUT
, wxID_COPY
, self
.ID_DELETE
]:
660 evt
.Enable(tree
.selection
is not None and tree
.selection
!= tree
.root
)
661 elif evt
.GetId() == wxID_PASTE
:
662 evt
.Enable((self
.clipboard
and tree
.selection
) != None)
663 elif evt
.GetId() == self
.ID_TEST
:
664 evt
.Enable(tree
.selection
is not None and tree
.selection
!= tree
.root
)
665 elif evt
.GetId() == wxID_UNDO
: evt
.Enable(undoMan
.CanUndo())
666 elif evt
.GetId() == wxID_REDO
: evt
.Enable(undoMan
.CanRedo())
668 def OnIdle(self
, evt
):
669 if self
.inIdle
: return # Recursive call protection
674 self
.SetStatusText('Refreshing test window...')
676 tree
.CreateTestWin(g
.testWin
.item
)
678 self
.SetStatusText('')
679 tree
.needUpdate
= False
680 elif tree
.pendingHighLight
:
681 tree
.HighLight(tree
.pendingHighLight
)
686 # We don't let close panel window
687 def OnCloseMiniFrame(self
, evt
):
690 def OnCloseWindow(self
, evt
):
691 if not self
.AskSave(): return
692 if g
.testWin
: g
.testWin
.Destroy()
693 # Destroy cached windows
694 panel
.cacheParent
.Destroy()
695 if not panel
.GetPageCount() == 2:
696 panel
.page2
.Destroy()
697 conf
.x
, conf
.y
= self
.GetPosition()
698 conf
.width
, conf
.height
= self
.GetSize()
700 conf
.sashPos
= self
.splitter
.GetSashPosition()
702 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
703 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
709 self
.clipboard
.unlink()
710 self
.clipboard
= None
712 self
.modified
= False
718 self
.SetTitle(progname
)
719 # Numbers for new controls
721 self
.maxIDs
[xxxPanel
] = self
.maxIDs
[xxxDialog
] = self
.maxIDs
[xxxFrame
] = \
722 self
.maxIDs
[xxxMenuBar
] = self
.maxIDs
[xxxMenu
] = self
.maxIDs
[xxxToolBar
] = 0
724 def Open(self
, path
):
725 if not os
.path
.exists(path
):
726 wxLogError('File does not exists: %s' % path
)
728 # Try to read the file
732 # Parse first line to get encoding (!! hack, I don't know a better way)
734 mo
= re
.match(r
'^<\?xml ([^<>]* )?encoding="(?P<encd>[^<>].*)"\?>', line
)
737 dom
= minidom
.parse(f
)
738 # Set encoding global variable and document encoding property
741 dom
.encoding
= xxx
.currentEncoding
= mo
.group('encd')
743 xxx
.currentEncoding
= 'iso-8859-1'
747 dir = os
.path
.dirname(path
)
748 if dir: os
.chdir(dir)
751 self
.SetTitle(progname
+ ': ' + os
.path
.basename(path
))
753 # Nice exception printing
755 wxLogError(traceback
.format_exception(inf
[0], inf
[1], None)[-1])
756 wxLogError('Error reading file: %s' % path
)
760 def Indent(self
, node
, indent
= 0):
761 # Copy child list because it will change soon
762 children
= node
.childNodes
[:]
763 # Main node doesn't need to be indented
765 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
766 node
.parentNode
.insertBefore(text
, node
)
768 # Append newline after last child, except for text nodes
769 if children
[-1].nodeType
== minidom
.Node
.ELEMENT_NODE
:
770 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
771 node
.appendChild(text
)
772 # Indent children which are elements
774 if n
.nodeType
== minidom
.Node
.ELEMENT_NODE
:
775 self
.Indent(n
, indent
+ 2)
777 def Save(self
, path
):
780 if tree
.selection
and panel
.IsModified():
781 self
.OnRefresh(wxCommandEvent())
783 # Make temporary copy for formatting it
784 # !!! We can't clone dom node, it works only once
785 #self.domCopy = tree.dom.cloneNode(True)
786 self
.domCopy
= MyDocument()
787 mainNode
= self
.domCopy
.appendChild(tree
.mainNode
.cloneNode(True))
788 self
.Indent(mainNode
)
789 self
.domCopy
.writexml(f
, encoding
=tree
.rootObj
.params
['encoding'].value())
791 self
.domCopy
.unlink()
793 self
.modified
= False
794 panel
.SetModified(False)
796 wxLogError('Error writing file: %s' % path
)
800 if not (self
.modified
or panel
.IsModified()): return True
801 flags
= wxICON_EXCLAMATION | wxYES_NO | wxCANCEL | wxCENTRE
802 dlg
= wxMessageDialog( self
, 'File is modified. Save before exit?',
803 'Save before too late?', flags
)
804 say
= dlg
.ShowModal()
807 self
.OnSaveOrSaveAs(wxCommandEvent(wxID_SAVE
))
808 # If save was successful, modified flag is unset
809 if not self
.modified
: return True
811 self
.modified
= False
812 panel
.SetModified(False)
819 ################################################################################
822 print >> sys
.stderr
, 'usage: xrced [-dhlv] [file]'
827 # Process comand-line
829 opts
= args
= [] #give empty values in case of exception
830 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'dhiv')
831 except getopt
.GetoptError
:
832 if wxPlatform
!= '__WXMAC__': # macs have some extra parameters
833 print >> sys
.stderr
, 'Unknown option'
843 g
.xmlFlags
&= ~wxXRC_USE_LOCALE
845 print 'XRCed version', version
848 self
.SetAppName('xrced')
851 conf
= g
.conf
= wxConfig(style
= wxCONFIG_USE_LOCAL_FILE
)
852 conf
.autoRefresh
= conf
.ReadInt('autorefresh', True)
853 pos
= conf
.ReadInt('x', -1), conf
.ReadInt('y', -1)
854 size
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600)
855 conf
.embedPanel
= conf
.ReadInt('embedPanel', True)
856 conf
.showTools
= conf
.ReadInt('showTools', True)
857 conf
.sashPos
= conf
.ReadInt('sashPos', 200)
858 if not conf
.embedPanel
:
859 conf
.panelX
= conf
.ReadInt('panelX', -1)
860 conf
.panelY
= conf
.ReadInt('panelY', -1)
862 conf
.panelX
= conf
.panelY
= -1
863 conf
.panelWidth
= conf
.ReadInt('panelWidth', 200)
864 conf
.panelHeight
= conf
.ReadInt('panelHeight', 200)
865 conf
.panic
= not conf
.HasEntry('nopanic')
867 wxFileSystem_AddHandler(wxMemoryFSHandler())
868 wxInitAllImageHandlers()
870 frame
= Frame(pos
, size
)
872 # Load resources from XRC file (!!! should be transformed to .py later?)
873 frame
.res
= wxXmlResource('')
874 frame
.res
.Load(os
.path
.join(basePath
, 'xrced.xrc'))
876 # Load file after showing
879 frame
.open = frame
.Open(args
[0])
886 wc
= wxConfigBase_Get()
887 wc
.WriteInt('autorefresh', conf
.autoRefresh
)
888 wc
.WriteInt('x', conf
.x
)
889 wc
.WriteInt('y', conf
.y
)
890 wc
.WriteInt('width', conf
.width
)
891 wc
.WriteInt('height', conf
.height
)
892 wc
.WriteInt('embedPanel', conf
.embedPanel
)
893 wc
.WriteInt('showTools', conf
.showTools
)
894 if not conf
.embedPanel
:
895 wc
.WriteInt('panelX', conf
.panelX
)
896 wc
.WriteInt('panelY', conf
.panelY
)
897 wc
.WriteInt('sashPos', conf
.sashPos
)
898 wc
.WriteInt('panelWidth', conf
.panelWidth
)
899 wc
.WriteInt('panelHeight', conf
.panelHeight
)
900 wc
.WriteInt('nopanic', True)
904 app
= App(0, useBestVisual
=False)
910 if __name__
== '__main__':