]>
Commit | Line | Data |
---|---|---|
d14a1e28 RD |
1 | # Name: tree.py |
2 | # Purpose: XRC editor, XML_tree class | |
3 | # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be> | |
4 | # Created: 02.12.2002 | |
5 | # RCS-ID: $Id$ | |
1fded56b | 6 | |
d14a1e28 | 7 | from xxx import * # xxx imports globals and params |
fdc1a8be | 8 | import types |
a4c013b2 | 9 | import traceback |
d14a1e28 RD |
10 | |
11 | # Constant to define standart window name | |
12 | STD_NAME = '_XRCED_T_W' | |
13 | ||
14 | # Icons | |
15 | import images | |
16 | ||
17 | class MemoryFile: | |
18 | def __init__(self, name): | |
19 | self.name = name | |
20 | self.buffer = '' | |
21 | def write(self, data): | |
7353d818 | 22 | self.buffer += data.encode(g.currentEncoding) |
d14a1e28 RD |
23 | def close(self): |
24 | wxMemoryFSHandler_AddFile(self.name, self.buffer) | |
25 | ||
26 | ################################################################################ | |
27 | ||
28 | # Redefine writing to include encoding | |
29 | class MyDocument(minidom.Document): | |
30 | def __init__(self): | |
31 | minidom.Document.__init__(self) | |
32 | self.encoding = '' | |
33 | def writexml(self, writer, indent="", addindent="", newl="", encoding=""): | |
34 | if encoding: encdstr = 'encoding="%s"' % encoding | |
35 | else: encdstr = '' | |
36 | writer.write('<?xml version="1.0" %s?>\n' % encdstr) | |
37 | for node in self.childNodes: | |
38 | node.writexml(writer, indent, addindent, newl) | |
39 | ||
40 | ################################################################################ | |
41 | ||
42 | # Ids for menu commands | |
43 | class ID_NEW: | |
44 | PANEL = wxNewId() | |
45 | DIALOG = wxNewId() | |
46 | FRAME = wxNewId() | |
47 | TOOL_BAR = wxNewId() | |
48 | TOOL = wxNewId() | |
49 | MENU_BAR = wxNewId() | |
50 | MENU = wxNewId() | |
51 | ||
52 | STATIC_TEXT = wxNewId() | |
53 | TEXT_CTRL = wxNewId() | |
54 | ||
55 | BUTTON = wxNewId() | |
56 | BITMAP_BUTTON = wxNewId() | |
57 | RADIO_BUTTON = wxNewId() | |
58 | SPIN_BUTTON = wxNewId() | |
3d49f2fb | 59 | TOGGLE_BUTTON = wxNewId() |
d14a1e28 RD |
60 | |
61 | STATIC_BOX = wxNewId() | |
62 | CHECK_BOX = wxNewId() | |
63 | RADIO_BOX = wxNewId() | |
64 | COMBO_BOX = wxNewId() | |
65 | LIST_BOX = wxNewId() | |
66 | ||
67 | STATIC_LINE = wxNewId() | |
68 | STATIC_BITMAP = wxNewId() | |
69 | CHOICE = wxNewId() | |
70 | SLIDER = wxNewId() | |
71 | GAUGE = wxNewId() | |
72 | SCROLL_BAR = wxNewId() | |
73 | TREE_CTRL = wxNewId() | |
74 | LIST_CTRL = wxNewId() | |
75 | CHECK_LIST = wxNewId() | |
76 | NOTEBOOK = wxNewId() | |
68ae5821 | 77 | SPLITTER_WINDOW = wxNewId() |
d14a1e28 RD |
78 | SCROLLED_WINDOW = wxNewId() |
79 | HTML_WINDOW = wxNewId() | |
80 | CALENDAR_CTRL = wxNewId() | |
81 | GENERIC_DIR_CTRL = wxNewId() | |
82 | SPIN_CTRL = wxNewId() | |
83 | UNKNOWN = wxNewId() | |
64bce500 RR |
84 | WIZARD = wxNewId() |
85 | WIZARD_PAGE = wxNewId() | |
86 | WIZARD_PAGE_SIMPLE = wxNewId() | |
87 | STATUS_BAR = wxNewId() | |
d14a1e28 RD |
88 | |
89 | BOX_SIZER = wxNewId() | |
90 | STATIC_BOX_SIZER = wxNewId() | |
91 | GRID_SIZER = wxNewId() | |
92 | FLEX_GRID_SIZER = wxNewId() | |
a4c013b2 | 93 | GRID_BAG_SIZER = wxNewId() |
64bce500 | 94 | STD_DIALOG_BUTTON_SIZER = wxNewId() |
d14a1e28 | 95 | SPACER = wxNewId() |
64bce500 | 96 | |
d14a1e28 RD |
97 | TOOL_BAR = wxNewId() |
98 | TOOL = wxNewId() | |
99 | MENU = wxNewId() | |
100 | MENU_ITEM = wxNewId() | |
101 | SEPARATOR = wxNewId() | |
102 | LAST = wxNewId() | |
103 | ||
104 | class PullDownMenu: | |
105 | ID_EXPAND = wxNewId() | |
106 | ID_COLLAPSE = wxNewId() | |
107 | ID_PASTE_SIBLING = wxNewId() | |
016f67ba | 108 | ID_TOOL_PASTE = wxNewId() |
2481bf3c | 109 | ID_SUBCLASS = wxNewId() |
d14a1e28 RD |
110 | |
111 | def __init__(self, parent): | |
112 | self.ID_DELETE = parent.ID_DELETE | |
113 | EVT_MENU_RANGE(parent, ID_NEW.PANEL, ID_NEW.LAST, parent.OnCreate) | |
114 | EVT_MENU_RANGE(parent, 1000 + ID_NEW.PANEL, 1000 + ID_NEW.LAST, parent.OnReplace) | |
115 | EVT_MENU(parent, self.ID_COLLAPSE, parent.OnCollapse) | |
116 | EVT_MENU(parent, self.ID_EXPAND, parent.OnExpand) | |
117 | EVT_MENU(parent, self.ID_PASTE_SIBLING, parent.OnPaste) | |
2481bf3c | 118 | EVT_MENU(parent, self.ID_SUBCLASS, parent.OnSubclass) |
d14a1e28 RD |
119 | # We connect to tree, but process in frame |
120 | EVT_MENU_HIGHLIGHT_ALL(g.tree, parent.OnPullDownHighlight) | |
121 | ||
122 | # Mapping from IDs to element names | |
123 | self.createMap = { | |
124 | ID_NEW.PANEL: 'wxPanel', | |
125 | ID_NEW.DIALOG: 'wxDialog', | |
126 | ID_NEW.FRAME: 'wxFrame', | |
64bce500 RR |
127 | ID_NEW.WIZARD: 'wxWizard', |
128 | ID_NEW.WIZARD_PAGE: 'wxWizardPage', | |
129 | ID_NEW.WIZARD_PAGE_SIMPLE: 'wxWizardPageSimple', | |
d14a1e28 RD |
130 | ID_NEW.TOOL_BAR: 'wxToolBar', |
131 | ID_NEW.TOOL: 'tool', | |
132 | ID_NEW.MENU_BAR: 'wxMenuBar', | |
133 | ID_NEW.MENU: 'wxMenu', | |
134 | ID_NEW.MENU_ITEM: 'wxMenuItem', | |
135 | ID_NEW.SEPARATOR: 'separator', | |
136 | ||
137 | ID_NEW.STATIC_TEXT: 'wxStaticText', | |
138 | ID_NEW.TEXT_CTRL: 'wxTextCtrl', | |
139 | ||
140 | ID_NEW.BUTTON: 'wxButton', | |
141 | ID_NEW.BITMAP_BUTTON: 'wxBitmapButton', | |
142 | ID_NEW.RADIO_BUTTON: 'wxRadioButton', | |
143 | ID_NEW.SPIN_BUTTON: 'wxSpinButton', | |
3d49f2fb | 144 | ID_NEW.TOGGLE_BUTTON: 'wxToggleButton', |
d14a1e28 RD |
145 | |
146 | ID_NEW.STATIC_BOX: 'wxStaticBox', | |
147 | ID_NEW.CHECK_BOX: 'wxCheckBox', | |
148 | ID_NEW.RADIO_BOX: 'wxRadioBox', | |
149 | ID_NEW.COMBO_BOX: 'wxComboBox', | |
150 | ID_NEW.LIST_BOX: 'wxListBox', | |
151 | ||
152 | ID_NEW.STATIC_LINE: 'wxStaticLine', | |
153 | ID_NEW.STATIC_BITMAP: 'wxStaticBitmap', | |
154 | ID_NEW.CHOICE: 'wxChoice', | |
155 | ID_NEW.SLIDER: 'wxSlider', | |
156 | ID_NEW.GAUGE: 'wxGauge', | |
157 | ID_NEW.SCROLL_BAR: 'wxScrollBar', | |
158 | ID_NEW.TREE_CTRL: 'wxTreeCtrl', | |
159 | ID_NEW.LIST_CTRL: 'wxListCtrl', | |
edfeb1b8 | 160 | ID_NEW.CHECK_LIST: 'wxCheckListBox', |
d14a1e28 | 161 | ID_NEW.NOTEBOOK: 'wxNotebook', |
68ae5821 | 162 | ID_NEW.SPLITTER_WINDOW: 'wxSplitterWindow', |
d14a1e28 RD |
163 | ID_NEW.SCROLLED_WINDOW: 'wxScrolledWindow', |
164 | ID_NEW.HTML_WINDOW: 'wxHtmlWindow', | |
165 | ID_NEW.CALENDAR_CTRL: 'wxCalendarCtrl', | |
166 | ID_NEW.GENERIC_DIR_CTRL: 'wxGenericDirCtrl', | |
167 | ID_NEW.SPIN_CTRL: 'wxSpinCtrl', | |
168 | ||
169 | ID_NEW.BOX_SIZER: 'wxBoxSizer', | |
170 | ID_NEW.STATIC_BOX_SIZER: 'wxStaticBoxSizer', | |
171 | ID_NEW.GRID_SIZER: 'wxGridSizer', | |
172 | ID_NEW.FLEX_GRID_SIZER: 'wxFlexGridSizer', | |
a4c013b2 | 173 | ID_NEW.GRID_BAG_SIZER: 'wxGridBagSizer', |
64bce500 | 174 | ID_NEW.STD_DIALOG_BUTTON_SIZER: 'wxStdDialogButtonSizer', |
d14a1e28 RD |
175 | ID_NEW.SPACER: 'spacer', |
176 | ID_NEW.UNKNOWN: 'unknown', | |
177 | } | |
178 | self.topLevel = [ | |
179 | (ID_NEW.PANEL, 'Panel', 'Create panel'), | |
180 | (ID_NEW.DIALOG, 'Dialog', 'Create dialog'), | |
181 | (ID_NEW.FRAME, 'Frame', 'Create frame'), | |
64bce500 | 182 | (ID_NEW.WIZARD, 'Wizard', 'Create wizard'), |
d14a1e28 RD |
183 | None, |
184 | (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'), | |
185 | (ID_NEW.MENU_BAR, 'MenuBar', 'Create menubar'), | |
186 | (ID_NEW.MENU, 'Menu', 'Create menu') | |
187 | ] | |
188 | self.containers = [ | |
189 | (ID_NEW.PANEL, 'Panel', 'Create panel'), | |
190 | (ID_NEW.NOTEBOOK, 'Notebook', 'Create notebook control'), | |
68ae5821 | 191 | (ID_NEW.SPLITTER_WINDOW, 'SplitterWindow', 'Create splitter window'), |
d14a1e28 | 192 | (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'), |
64bce500 RR |
193 | # (ID_NEW.WIZARD_PAGE, 'WizardPage', 'Create wizard page'), |
194 | (ID_NEW.WIZARD_PAGE_SIMPLE, 'WizardPageSimple', 'Create simple wizard page'), | |
d14a1e28 RD |
195 | ] |
196 | self.sizers = [ | |
197 | (ID_NEW.BOX_SIZER, 'BoxSizer', 'Create box sizer'), | |
198 | (ID_NEW.STATIC_BOX_SIZER, 'StaticBoxSizer', | |
199 | 'Create static box sizer'), | |
200 | (ID_NEW.GRID_SIZER, 'GridSizer', 'Create grid sizer'), | |
201 | (ID_NEW.FLEX_GRID_SIZER, 'FlexGridSizer', | |
202 | 'Create flexgrid sizer'), | |
a4c013b2 RR |
203 | (ID_NEW.GRID_BAG_SIZER, 'GridBagSizer', |
204 | 'Create gridbag sizer'), | |
64bce500 RR |
205 | # (ID_NEW.STD_DIALOG_BUTTON_SIZER, 'StdDialogButtonSizer', |
206 | # 'Create standard button sizer'), | |
d14a1e28 RD |
207 | (ID_NEW.SPACER, 'Spacer', 'Create spacer'), |
208 | ] | |
209 | self.controls = [ | |
210 | ['control', 'Various controls', | |
211 | (ID_NEW.STATIC_TEXT, 'Label', 'Create label'), | |
212 | (ID_NEW.STATIC_BITMAP, 'Bitmap', 'Create bitmap'), | |
213 | (ID_NEW.STATIC_LINE, 'Line', 'Create line'), | |
214 | (ID_NEW.TEXT_CTRL, 'TextBox', 'Create text box'), | |
215 | (ID_NEW.CHOICE, 'Choice', 'Create choice'), | |
216 | (ID_NEW.SLIDER, 'Slider', 'Create slider'), | |
217 | (ID_NEW.GAUGE, 'Gauge', 'Create gauge'), | |
218 | (ID_NEW.SPIN_CTRL, 'SpinCtrl', 'Create spin'), | |
219 | (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'), | |
220 | (ID_NEW.TREE_CTRL, 'TreeCtrl', 'Create tree'), | |
221 | (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list'), | |
222 | (ID_NEW.CHECK_LIST, 'CheckList', 'Create check list'), | |
223 | (ID_NEW.SCROLLED_WINDOW, 'ScrolledWindow', 'Create scrolled window'), | |
224 | (ID_NEW.HTML_WINDOW, 'HtmlWindow', 'Create HTML window'), | |
225 | (ID_NEW.CALENDAR_CTRL, 'CalendarCtrl', 'Create calendar control'), | |
226 | (ID_NEW.GENERIC_DIR_CTRL, 'GenericDirCtrl', 'Create generic dir control'), | |
227 | (ID_NEW.UNKNOWN, 'Unknown', 'Create custom control placeholder'), | |
228 | ], | |
229 | ['button', 'Buttons', | |
230 | (ID_NEW.BUTTON, 'Button', 'Create button'), | |
231 | (ID_NEW.BITMAP_BUTTON, 'BitmapButton', 'Create bitmap button'), | |
232 | (ID_NEW.RADIO_BUTTON, 'RadioButton', 'Create radio button'), | |
233 | (ID_NEW.SPIN_BUTTON, 'SpinButton', 'Create spin button'), | |
3d49f2fb | 234 | (ID_NEW.TOGGLE_BUTTON, 'ToggleButton', 'Create toggle button'), |
d14a1e28 RD |
235 | ], |
236 | ['box', 'Boxes', | |
237 | (ID_NEW.STATIC_BOX, 'StaticBox', 'Create static box'), | |
238 | (ID_NEW.CHECK_BOX, 'CheckBox', 'Create check box'), | |
239 | (ID_NEW.RADIO_BOX, 'RadioBox', 'Create radio box'), | |
240 | (ID_NEW.COMBO_BOX, 'ComboBox', 'Create combo box'), | |
241 | (ID_NEW.LIST_BOX, 'ListBox', 'Create list box'), | |
242 | ], | |
243 | ['container', 'Containers', | |
244 | (ID_NEW.PANEL, 'Panel', 'Create panel'), | |
245 | (ID_NEW.NOTEBOOK, 'Notebook', 'Create notebook control'), | |
68ae5821 | 246 | (ID_NEW.SPLITTER_WINDOW, 'SplitterWindow', 'Create splitter window'), |
d14a1e28 | 247 | (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'), |
64bce500 RR |
248 | # (ID_NEW.WIZARD_PAGE, 'Wizard Page', 'Create wizard page'), |
249 | (ID_NEW.WIZARD_PAGE_SIMPLE, 'WizardPageSimple', 'Create simple wizard page'), | |
d14a1e28 RD |
250 | ], |
251 | ['sizer', 'Sizers', | |
252 | (ID_NEW.BOX_SIZER, 'BoxSizer', 'Create box sizer'), | |
253 | (ID_NEW.STATIC_BOX_SIZER, 'StaticBoxSizer', | |
254 | 'Create static box sizer'), | |
255 | (ID_NEW.GRID_SIZER, 'GridSizer', 'Create grid sizer'), | |
256 | (ID_NEW.FLEX_GRID_SIZER, 'FlexGridSizer', | |
257 | 'Create flexgrid sizer'), | |
a4c013b2 RR |
258 | (ID_NEW.GRID_BAG_SIZER, 'GridBagSizer', |
259 | 'Create gridbag sizer'), | |
d14a1e28 | 260 | (ID_NEW.SPACER, 'Spacer', 'Create spacer'), |
64bce500 RR |
261 | (ID_NEW.STD_DIALOG_BUTTON_SIZER, 'StdDialogButtonSizer', |
262 | 'Create standard button sizer'), | |
d14a1e28 RD |
263 | ] |
264 | ] | |
265 | self.menuControls = [ | |
266 | (ID_NEW.MENU, 'Menu', 'Create menu'), | |
267 | (ID_NEW.MENU_ITEM, 'MenuItem', 'Create menu item'), | |
268 | (ID_NEW.SEPARATOR, 'Separator', 'Create separator'), | |
269 | ] | |
270 | self.toolBarControls = [ | |
271 | (ID_NEW.TOOL, 'Tool', 'Create tool'), | |
272 | (ID_NEW.SEPARATOR, 'Separator', 'Create separator'), | |
273 | ['control', 'Various controls', | |
274 | (ID_NEW.STATIC_TEXT, 'Label', 'Create label'), | |
275 | (ID_NEW.STATIC_BITMAP, 'Bitmap', 'Create bitmap'), | |
276 | (ID_NEW.STATIC_LINE, 'Line', 'Create line'), | |
277 | (ID_NEW.TEXT_CTRL, 'TextBox', 'Create text box'), | |
278 | (ID_NEW.CHOICE, 'Choice', 'Create choice'), | |
279 | (ID_NEW.SLIDER, 'Slider', 'Create slider'), | |
280 | (ID_NEW.GAUGE, 'Gauge', 'Create gauge'), | |
281 | (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'), | |
282 | (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list control'), | |
283 | (ID_NEW.CHECK_LIST, 'CheckList', 'Create check list'), | |
284 | ], | |
285 | ['button', 'Buttons', | |
286 | (ID_NEW.BUTTON, 'Button', 'Create button'), | |
287 | (ID_NEW.BITMAP_BUTTON, 'BitmapButton', 'Create bitmap button'), | |
288 | (ID_NEW.RADIO_BUTTON, 'RadioButton', 'Create radio button'), | |
289 | (ID_NEW.SPIN_BUTTON, 'SpinButton', 'Create spin button'), | |
290 | ], | |
291 | ['box', 'Boxes', | |
292 | (ID_NEW.STATIC_BOX, 'StaticBox', 'Create static box'), | |
293 | (ID_NEW.CHECK_BOX, 'CheckBox', 'Create check box'), | |
294 | (ID_NEW.RADIO_BOX, 'RadioBox', 'Create radio box'), | |
295 | (ID_NEW.COMBO_BOX, 'ComboBox', 'Create combo box'), | |
296 | (ID_NEW.LIST_BOX, 'ListBox', 'Create list box'), | |
297 | ], | |
298 | ] | |
299 | ||
300 | ################################################################################ | |
301 | ||
302 | # Set menu to list items. | |
303 | # Each menu command is a tuple (id, label, help) | |
304 | # submenus are lists [id, label, help, submenu] | |
305 | # and separators are any other type | |
306 | def SetMenu(m, list): | |
307 | for l in list: | |
308 | if type(l) == types.TupleType: | |
309 | apply(m.Append, l) | |
310 | elif type(l) == types.ListType: | |
311 | subMenu = wxMenu() | |
312 | SetMenu(subMenu, l[2:]) | |
313 | m.AppendMenu(wxNewId(), l[0], subMenu, l[1]) | |
314 | else: # separator | |
315 | m.AppendSeparator() | |
316 | # Same, but adds 1000 to all IDs | |
317 | def SetMenu2(m, list): | |
318 | for l in list: | |
319 | if type(l) == types.TupleType: | |
320 | # Shift ID | |
321 | l = (1000 + l[0],) + l[1:] | |
322 | apply(m.Append, l) | |
323 | elif type(l) == types.ListType: | |
324 | subMenu = wxMenu() | |
325 | SetMenu2(subMenu, l[2:]) | |
326 | m.AppendMenu(wxNewId(), l[0], subMenu, l[1]) | |
327 | else: # separator | |
328 | m.AppendSeparator() | |
329 | ||
330 | ################################################################################ | |
331 | ||
332 | class HighLightBox: | |
333 | def __init__(self, pos, size): | |
334 | if size.width == -1: size.width = 0 | |
335 | if size.height == -1: size.height = 0 | |
336 | w = g.testWin.panel | |
337 | l1 = wxWindow(w, -1, pos, wxSize(size.width, 2)) | |
338 | l1.SetBackgroundColour(wxRED) | |
339 | l2 = wxWindow(w, -1, pos, wxSize(2, size.height)) | |
340 | l2.SetBackgroundColour(wxRED) | |
341 | l3 = wxWindow(w, -1, wxPoint(pos.x + size.width - 2, pos.y), wxSize(2, size.height)) | |
342 | l3.SetBackgroundColour(wxRED) | |
343 | l4 = wxWindow(w, -1, wxPoint(pos.x, pos.y + size.height - 2), wxSize(size.width, 2)) | |
344 | l4.SetBackgroundColour(wxRED) | |
345 | self.lines = [l1, l2, l3, l4] | |
346 | # Move highlight to a new position | |
347 | def Replace(self, pos, size): | |
348 | if size.width == -1: size.width = 0 | |
349 | if size.height == -1: size.height = 0 | |
350 | self.lines[0].SetDimensions(pos.x, pos.y, size.width, 2) | |
351 | self.lines[1].SetDimensions(pos.x, pos.y, 2, size.height) | |
352 | self.lines[2].SetDimensions(pos.x + size.width - 2, pos.y, 2, size.height) | |
353 | self.lines[3].SetDimensions(pos.x, pos.y + size.height - 2, size.width, 2) | |
354 | # Remove it | |
355 | def Remove(self): | |
356 | map(wxWindow.Destroy, self.lines) | |
357 | g.testWin.highLight = None | |
358 | ||
359 | ################################################################################ | |
360 | ||
361 | class XML_Tree(wxTreeCtrl): | |
362 | def __init__(self, parent, id): | |
363 | wxTreeCtrl.__init__(self, parent, id, style = wxTR_HAS_BUTTONS) | |
364 | self.SetBackgroundColour(wxColour(224, 248, 224)) | |
365 | # Register events | |
366 | EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged) | |
367 | # One works on Linux, another on Windows | |
368 | if wxPlatform == '__WXGTK__': | |
369 | EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated) | |
370 | else: | |
371 | EVT_LEFT_DCLICK(self, self.OnDClick) | |
372 | EVT_RIGHT_DOWN(self, self.OnRightDown) | |
373 | EVT_TREE_ITEM_EXPANDED(self, self.GetId(), self.OnItemExpandedCollapsed) | |
374 | EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemExpandedCollapsed) | |
375 | ||
376 | self.selection = None | |
377 | self.needUpdate = False | |
378 | self.pendingHighLight = None | |
379 | self.ctrl = self.shift = False | |
380 | self.dom = None | |
381 | # Create image list | |
382 | il = wxImageList(16, 16, True) | |
383 | self.rootImage = il.Add(images.getTreeRootImage().Scale(16,16).ConvertToBitmap()) | |
384 | xxxObject.image = il.Add(images.getTreeDefaultImage().Scale(16,16).ConvertToBitmap()) | |
385 | xxxPanel.image = il.Add(images.getTreePanelImage().Scale(16,16).ConvertToBitmap()) | |
386 | xxxDialog.image = il.Add(images.getTreeDialogImage().Scale(16,16).ConvertToBitmap()) | |
387 | xxxFrame.image = il.Add(images.getTreeFrameImage().Scale(16,16).ConvertToBitmap()) | |
388 | xxxMenuBar.image = il.Add(images.getTreeMenuBarImage().Scale(16,16).ConvertToBitmap()) | |
389 | xxxMenu.image = il.Add(images.getTreeMenuImage().Scale(16,16).ConvertToBitmap()) | |
390 | xxxMenuItem.image = il.Add(images.getTreeMenuItemImage().Scale(16,16).ConvertToBitmap()) | |
391 | xxxToolBar.image = il.Add(images.getTreeToolBarImage().Scale(16,16).ConvertToBitmap()) | |
392 | xxxTool.image = il.Add(images.getTreeToolImage().Scale(16,16).ConvertToBitmap()) | |
393 | xxxSeparator.image = il.Add(images.getTreeSeparatorImage().Scale(16,16).ConvertToBitmap()) | |
394 | xxxSizer.imageH = il.Add(images.getTreeSizerHImage().Scale(16,16).ConvertToBitmap()) | |
395 | xxxSizer.imageV = il.Add(images.getTreeSizerVImage().Scale(16,16).ConvertToBitmap()) | |
396 | xxxStaticBoxSizer.imageH = il.Add(images.getTreeStaticBoxSizerHImage().Scale(16,16).ConvertToBitmap()) | |
397 | xxxStaticBoxSizer.imageV = il.Add(images.getTreeStaticBoxSizerVImage().Scale(16,16).ConvertToBitmap()) | |
398 | xxxGridSizer.image = il.Add(images.getTreeSizerGridImage().Scale(16,16).ConvertToBitmap()) | |
399 | xxxFlexGridSizer.image = il.Add(images.getTreeSizerFlexGridImage().Scale(16,16).ConvertToBitmap()) | |
400 | self.il = il | |
401 | self.SetImageList(il) | |
402 | ||
403 | def RegisterKeyEvents(self): | |
404 | EVT_KEY_DOWN(self, g.tools.OnKeyDown) | |
405 | EVT_KEY_UP(self, g.tools.OnKeyUp) | |
406 | EVT_ENTER_WINDOW(self, g.tools.OnMouse) | |
407 | EVT_LEAVE_WINDOW(self, g.tools.OnMouse) | |
408 | ||
409 | def Unselect(self): | |
410 | self.selection = None | |
411 | wxTreeCtrl.Unselect(self) | |
412 | g.tools.UpdateUI() | |
413 | ||
414 | def ExpandAll(self, item): | |
415 | if self.ItemHasChildren(item): | |
416 | self.Expand(item) | |
fdc1a8be | 417 | i, cookie = self.GetFirstChild(item) |
d14a1e28 RD |
418 | children = [] |
419 | while i.IsOk(): | |
420 | children.append(i) | |
421 | i, cookie = self.GetNextChild(item, cookie) | |
422 | for i in children: | |
423 | self.ExpandAll(i) | |
424 | def CollapseAll(self, item): | |
425 | if self.ItemHasChildren(item): | |
fdc1a8be | 426 | i, cookie = self.GetFirstChild(item) |
d14a1e28 RD |
427 | children = [] |
428 | while i.IsOk(): | |
429 | children.append(i) | |
430 | i, cookie = self.GetNextChild(item, cookie) | |
431 | for i in children: | |
432 | self.CollapseAll(i) | |
433 | self.Collapse(item) | |
434 | ||
435 | # Clear tree | |
436 | def Clear(self): | |
437 | self.DeleteAllItems() | |
438 | # Add minimal structure | |
439 | if self.dom: self.dom.unlink() | |
440 | self.dom = MyDocument() | |
441 | self.dummyNode = self.dom.createComment('dummy node') | |
442 | # Create main node | |
443 | self.mainNode = self.dom.createElement('resource') | |
444 | self.dom.appendChild(self.mainNode) | |
445 | self.rootObj = xxxMainNode(self.dom) | |
446 | self.root = self.AddRoot('XML tree', self.rootImage, | |
447 | data=wxTreeItemData(self.rootObj)) | |
448 | self.SetItemHasChildren(self.root) | |
d14a1e28 | 449 | self.Unselect() |
fdc1a8be | 450 | self.Expand(self.root) |
d14a1e28 RD |
451 | |
452 | # Clear old data and set new | |
453 | def SetData(self, dom): | |
454 | self.DeleteAllItems() | |
455 | # Add minimal structure | |
456 | if self.dom: self.dom.unlink() | |
457 | self.dom = dom | |
458 | self.dummyNode = self.dom.createComment('dummy node') | |
459 | # Find 'resource' child, add it's children | |
460 | self.mainNode = dom.documentElement | |
461 | self.rootObj = xxxMainNode(self.dom) | |
462 | self.root = self.AddRoot('XML tree', self.rootImage, | |
463 | data=wxTreeItemData(self.rootObj)) | |
464 | self.SetItemHasChildren(self.root) | |
465 | nodes = self.mainNode.childNodes[:] | |
466 | for node in nodes: | |
467 | if IsObject(node): | |
468 | self.AddNode(self.root, None, node) | |
469 | else: | |
470 | self.mainNode.removeChild(node) | |
471 | node.unlink() | |
472 | self.Expand(self.root) | |
473 | self.Unselect() | |
474 | ||
475 | # Add tree item for given parent item if node is DOM element node with | |
476 | # 'object' tag. xxxParent is parent xxx object | |
477 | def AddNode(self, itemParent, xxxParent, node): | |
478 | # Set item data to current node | |
479 | try: | |
480 | xxx = MakeXXXFromDOM(xxxParent, node) | |
481 | except: | |
482 | print 'ERROR: MakeXXXFromDom(%s, %s)' % (xxxParent, node) | |
483 | raise | |
484 | treeObj = xxx.treeObject() | |
485 | # Append tree item | |
486 | item = self.AppendItem(itemParent, treeObj.treeName(), | |
487 | image=treeObj.treeImage(), | |
488 | data=wxTreeItemData(xxx)) | |
489 | # Try to find children objects | |
490 | if treeObj.hasChildren: | |
491 | nodes = treeObj.element.childNodes[:] | |
492 | for n in nodes: | |
493 | if IsObject(n): | |
494 | self.AddNode(item, treeObj, n) | |
495 | elif n.nodeType != minidom.Node.ELEMENT_NODE: | |
496 | treeObj.element.removeChild(n) | |
497 | n.unlink() | |
498 | ||
499 | # Insert new item at specific position | |
500 | def InsertNode(self, itemParent, parent, elem, nextItem): | |
501 | # Insert in XML tree and wxWin | |
502 | xxx = MakeXXXFromDOM(parent, elem) | |
503 | # If nextItem is None, we append to parent, otherwise insert before it | |
504 | if nextItem.IsOk(): | |
505 | node = self.GetPyData(nextItem).element | |
506 | parent.element.insertBefore(elem, node) | |
507 | # Inserting before is difficult, se we insert after or first child | |
508 | index = self.ItemIndex(nextItem) | |
509 | newItem = self.InsertItemBefore(itemParent, index, | |
510 | xxx.treeName(), image=xxx.treeImage()) | |
511 | self.SetPyData(newItem, xxx) | |
512 | else: | |
513 | parent.element.appendChild(elem) | |
514 | newItem = self.AppendItem(itemParent, xxx.treeName(), image=xxx.treeImage(), | |
515 | data=wxTreeItemData(xxx)) | |
516 | # Add children items | |
517 | if xxx.hasChildren: | |
518 | treeObj = xxx.treeObject() | |
519 | for n in treeObj.element.childNodes: | |
520 | if IsObject(n): | |
521 | self.AddNode(newItem, treeObj, n) | |
522 | return newItem | |
523 | ||
524 | # Remove leaf of tree, return it's data object | |
525 | def RemoveLeaf(self, leaf): | |
526 | xxx = self.GetPyData(leaf) | |
527 | node = xxx.element | |
528 | parent = node.parentNode | |
529 | parent.removeChild(node) | |
530 | self.Delete(leaf) | |
531 | # Reset selection object | |
532 | self.selection = None | |
533 | return node | |
534 | # Find position relative to the top-level window | |
535 | def FindNodePos(self, item): | |
536 | # Root at (0,0) | |
537 | if item == g.testWin.item: return wxPoint(0, 0) | |
538 | itemParent = self.GetItemParent(item) | |
539 | # Select NB page | |
540 | obj = self.FindNodeObject(item) | |
541 | if self.GetPyData(itemParent).treeObject().__class__ == xxxNotebook: | |
542 | notebook = self.FindNodeObject(itemParent) | |
543 | # Find position | |
544 | for i in range(notebook.GetPageCount()): | |
545 | if notebook.GetPage(i) == obj: | |
fd919451 RR |
546 | if notebook.GetSelection() != i: |
547 | notebook.SetSelection(i) | |
548 | # Remove highlight - otherwise highlight window won't be visible | |
549 | if g.testWin.highLight: | |
550 | g.testWin.highLight.Remove() | |
d14a1e28 RD |
551 | break |
552 | # Find first ancestor which is a wxWindow (not a sizer) | |
553 | winParent = itemParent | |
554 | while self.GetPyData(winParent).isSizer: | |
555 | winParent = self.GetItemParent(winParent) | |
fd919451 RR |
556 | # Notebook children are layed out in a little strange way |
557 | if self.GetPyData(itemParent).treeObject().__class__ == xxxNotebook: | |
558 | parentPos = wxPoint(0,0) | |
559 | else: | |
560 | parentPos = self.FindNodePos(winParent) | |
d14a1e28 RD |
561 | # Position (-1,-1) is really (0,0) |
562 | pos = obj.GetPosition() | |
563 | if pos == (-1,-1): pos = (0,0) | |
564 | return parentPos + pos | |
565 | ||
566 | # Find window (or sizer) corresponding to a tree item. | |
567 | def FindNodeObject(self, item): | |
568 | testWin = g.testWin | |
569 | # If top-level, return testWin (or panel its panel) | |
570 | if item == testWin.item: return testWin.panel | |
571 | itemParent = self.GetItemParent(item) | |
572 | xxx = self.GetPyData(item).treeObject() | |
573 | parentWin = self.FindNodeObject(itemParent) | |
574 | # Top-level sizer? return window's sizer | |
575 | if xxx.isSizer and isinstance(parentWin, wxWindow): | |
576 | return parentWin.GetSizer() | |
577 | # Otherwise get parent's object and it's child | |
578 | child = parentWin.GetChildren()[self.ItemIndex(item)] | |
579 | # Return window or sizer for sizer items | |
580 | if child.GetClassName() == 'wxSizerItem': | |
581 | if child.IsWindow(): child = child.GetWindow() | |
582 | elif child.IsSizer(): | |
583 | child = child.GetSizer() | |
584 | # Test for notebook sizers | |
585 | if isinstance(child, wxNotebookSizer): | |
586 | child = child.GetNotebook() | |
587 | return child | |
588 | ||
589 | def OnSelChanged(self, evt): | |
fd919451 RR |
590 | self.ChangeSelection(evt.GetItem()) |
591 | ||
592 | def ChangeSelection(self, item): | |
d14a1e28 RD |
593 | # Apply changes |
594 | # !!! problem with wxGTK - GetOldItem is Ok if nothing selected | |
595 | #oldItem = evt.GetOldItem() | |
596 | status = '' | |
597 | oldItem = self.selection | |
598 | if oldItem: | |
599 | xxx = self.GetPyData(oldItem) | |
600 | # If some data was modified, apply changes | |
601 | if g.panel.IsModified(): | |
602 | self.Apply(xxx, oldItem) | |
603 | #if conf.autoRefresh: | |
604 | if g.testWin: | |
605 | if g.testWin.highLight: | |
606 | g.testWin.highLight.Remove() | |
607 | self.needUpdate = True | |
608 | status = 'Changes were applied' | |
609 | g.frame.SetStatusText(status) | |
610 | # Generate view | |
fd919451 | 611 | self.selection = item |
d14a1e28 RD |
612 | if not self.selection.IsOk(): |
613 | self.selection = None | |
614 | return | |
615 | xxx = self.GetPyData(self.selection) | |
616 | # Update panel | |
617 | g.panel.SetData(xxx) | |
618 | # Update tools | |
619 | g.tools.UpdateUI() | |
620 | # Hightlighting is done in OnIdle | |
621 | self.pendingHighLight = self.selection | |
622 | ||
623 | # Check if item is in testWin subtree | |
624 | def IsHighlatable(self, item): | |
625 | if item == g.testWin.item: return False | |
626 | while item != self.root: | |
627 | item = self.GetItemParent(item) | |
628 | if item == g.testWin.item: return True | |
629 | return False | |
630 | ||
631 | # Highlight selected item | |
632 | def HighLight(self, item): | |
633 | self.pendingHighLight = None | |
634 | # Can highlight only with some top-level windows | |
635 | if not g.testWin or self.GetPyData(g.testWin.item).treeObject().__class__ \ | |
636 | not in [xxxDialog, xxxPanel, xxxFrame]: | |
637 | return | |
638 | # If a control from another window is selected, remove highlight | |
639 | if not self.IsHighlatable(item): | |
640 | if g.testWin.highLight: g.testWin.highLight.Remove() | |
641 | return | |
642 | # Get window/sizer object | |
643 | obj, pos = self.FindNodeObject(item), self.FindNodePos(item) | |
644 | size = obj.GetSize() | |
645 | # Highlight | |
646 | # Nagative positions are not working wuite well | |
647 | if g.testWin.highLight: | |
648 | g.testWin.highLight.Replace(pos, size) | |
649 | else: | |
650 | g.testWin.highLight = HighLightBox(pos, size) | |
651 | g.testWin.highLight.item = item | |
652 | ||
653 | def ShowTestWindow(self, item): | |
654 | xxx = self.GetPyData(item) | |
655 | if g.panel.IsModified(): | |
656 | self.Apply(xxx, item) # apply changes | |
657 | treeObj = xxx.treeObject() | |
658 | if treeObj.className not in ['wxFrame', 'wxPanel', 'wxDialog', | |
64bce500 RR |
659 | 'wxMenuBar', 'wxToolBar', 'wxWizard', |
660 | 'wxWizardPageSimple']: | |
d14a1e28 RD |
661 | wxLogMessage('No view for this element (yet)') |
662 | return | |
663 | # Show item in bold | |
664 | if g.testWin: # Reset old | |
665 | self.SetItemBold(g.testWin.item, False) | |
666 | self.CreateTestWin(item) | |
667 | # Maybe an error occured, so we need to test | |
668 | if g.testWin: self.SetItemBold(g.testWin.item) | |
669 | ||
670 | # Double-click on Linux | |
671 | def OnItemActivated(self, evt): | |
672 | if evt.GetItem() != self.root: | |
673 | self.ShowTestWindow(evt.GetItem()) | |
674 | ||
675 | # Double-click on Windows | |
676 | def OnDClick(self, evt): | |
677 | item, flags = self.HitTest(evt.GetPosition()) | |
678 | if flags in [wxTREE_HITTEST_ONITEMBUTTON, wxTREE_HITTEST_ONITEMLABEL]: | |
679 | if item != self.root: self.ShowTestWindow(item) | |
680 | else: | |
681 | evt.Skip() | |
682 | ||
683 | def OnItemExpandedCollapsed(self, evt): | |
684 | # Update tool palette | |
685 | g.tools.UpdateUI() | |
686 | evt.Skip() | |
687 | ||
688 | # (re)create test window | |
689 | def CreateTestWin(self, item): | |
690 | testWin = g.testWin | |
691 | # Create a window with this resource | |
692 | xxx = self.GetPyData(item).treeObject() | |
693 | ||
694 | # If frame | |
695 | # if xxx.__class__ == xxxFrame: | |
696 | # Frame can't have many children, | |
697 | # but it's first child possibly can... | |
fdc1a8be | 698 | # child = self.GetFirstChild(item)[0] |
d14a1e28 RD |
699 | # if child.IsOk() and self.GetPyData(child).__class__ == xxxPanel: |
700 | # # Clean-up before recursive call or error | |
701 | # wxMemoryFSHandler_RemoveFile('xxx.xrc') | |
702 | # wxEndBusyCursor() | |
703 | # self.CreateTestWin(child) | |
704 | # return | |
705 | ||
706 | wxBeginBusyCursor() | |
707 | wxYield() | |
708 | # Close old window, remember where it was | |
709 | highLight = None | |
710 | if testWin: | |
711 | pos = testWin.GetPosition() | |
712 | if item == testWin.item: | |
713 | # Remember highlight if same top-level window | |
714 | if testWin.highLight: | |
715 | highLight = testWin.highLight.item | |
716 | if xxx.className == 'wxPanel': | |
717 | if testWin.highLight: | |
718 | testWin.pendingHighLight = highLight | |
719 | testWin.highLight.Remove() | |
720 | testWin.panel.Destroy() | |
721 | testWin.panel = None | |
722 | else: | |
723 | testWin.Destroy() | |
724 | testWin = g.testWin = None | |
725 | else: | |
726 | testWin.Destroy() | |
727 | testWin = g.testWin = None | |
728 | else: | |
729 | pos = g.testWinPos | |
730 | # Save in memory FS | |
731 | memFile = MemoryFile('xxx.xrc') | |
732 | # Create partial XML file - faster for big files | |
733 | ||
734 | dom = MyDocument() | |
735 | mainNode = dom.createElement('resource') | |
736 | dom.appendChild(mainNode) | |
737 | ||
738 | # Remove temporarily from old parent | |
739 | elem = xxx.element | |
740 | # Change window id to _XRCED_T_W. This gives some name for | |
741 | # unnamed windows, and for named gives the possibility to | |
742 | # write sawfish scripts. | |
743 | if not xxx.name: | |
744 | name = 'noname' | |
745 | else: | |
746 | name = xxx.name | |
747 | elem.setAttribute('name', STD_NAME) | |
64bce500 RR |
748 | # Replace wizard page class temporarily |
749 | if xxx.__class__ in [xxxWizardPage, xxxWizardPageSimple]: | |
750 | oldCl = elem.getAttribute('class') | |
751 | elem.setAttribute('class', 'wxPanel') | |
d14a1e28 RD |
752 | parent = elem.parentNode |
753 | next = elem.nextSibling | |
754 | parent.replaceChild(self.dummyNode, elem) | |
755 | # Append to new DOM, write it | |
756 | mainNode.appendChild(elem) | |
757 | dom.writexml(memFile, encoding=self.rootObj.params['encoding'].value()) | |
758 | # Put back in place | |
759 | mainNode.removeChild(elem) | |
760 | dom.unlink() | |
761 | parent.replaceChild(elem, self.dummyNode) | |
762 | # Remove temporary name or restore changed | |
763 | if not xxx.name: | |
764 | elem.removeAttribute('name') | |
765 | else: | |
766 | elem.setAttribute('name', xxx.name) | |
64bce500 RR |
767 | if xxx.__class__ in [xxxWizardPage, xxxWizardPageSimple]: |
768 | elem.setAttribute('class', oldCl) | |
d14a1e28 RD |
769 | memFile.close() # write to wxMemoryFS |
770 | xmlFlags = wxXRC_NO_SUBCLASSING | |
771 | # Use translations if encoding is not specified | |
772 | if g.currentEncoding == 'ascii': | |
773 | xmlFlags != wxXRC_USE_LOCALE | |
774 | res = wxXmlResource('', xmlFlags) | |
775 | res.Load('memory:xxx.xrc') | |
a4c013b2 RR |
776 | try: |
777 | if xxx.__class__ == xxxFrame: | |
778 | # Frame can't have many children, | |
779 | # but it's first child possibly can... | |
780 | # child = self.GetFirstChild(item)[0] | |
781 | # if child.IsOk() and self.GetPyData(child).__class__ == xxxPanel: | |
782 | # # Clean-up before recursive call or error | |
783 | # wxMemoryFSHandler_RemoveFile('xxx.xrc') | |
784 | # wxEndBusyCursor() | |
785 | # self.CreateTestWin(child) | |
786 | # return | |
787 | # This currently works under GTK, but not under MSW | |
788 | testWin = g.testWin = wxPreFrame() | |
789 | res.LoadOnFrame(testWin, g.frame, STD_NAME) | |
790 | # Create status bar | |
791 | testWin.panel = testWin | |
792 | testWin.CreateStatusBar() | |
793 | testWin.SetClientSize(testWin.GetBestSize()) | |
a4c013b2 RR |
794 | testWin.SetPosition(pos) |
795 | testWin.Show(True) | |
796 | elif xxx.__class__ == xxxPanel: | |
797 | # Create new frame | |
798 | if not testWin: | |
799 | testWin = g.testWin = wxFrame(g.frame, -1, 'Panel: ' + name, | |
800 | pos=pos, name=STD_NAME) | |
801 | testWin.panel = res.LoadPanel(testWin, STD_NAME) | |
802 | testWin.SetClientSize(testWin.GetBestSize()) | |
803 | testWin.Show(True) | |
804 | elif xxx.__class__ == xxxDialog: | |
805 | testWin = g.testWin = res.LoadDialog(None, STD_NAME) | |
806 | testWin.panel = testWin | |
807 | testWin.Layout() | |
808 | testWin.SetPosition(pos) | |
809 | testWin.Show(True) | |
810 | # Dialog's default code does not produce EVT_CLOSE | |
811 | EVT_BUTTON(testWin, wxID_OK, self.OnCloseTestWin) | |
812 | EVT_BUTTON(testWin, wxID_CANCEL, self.OnCloseTestWin) | |
64bce500 RR |
813 | elif xxx.__class__ == xxxWizard: |
814 | wiz = wxPreWizard() | |
815 | res.LoadOnObject(wiz, None, STD_NAME, 'wxWizard') | |
816 | # Find first page (don't know better way) | |
817 | firstPage = None | |
818 | for w in wiz.GetChildren(): | |
819 | if isinstance(w, wxWizardPage): | |
820 | firstPage = w | |
821 | break | |
822 | if not firstPage: | |
823 | wxLogError('Wizard is empty') | |
824 | else: | |
825 | # Wizard should be modal | |
826 | self.SetItemBold(item) | |
827 | wiz.RunWizard(w) | |
828 | self.SetItemBold(item, False) | |
829 | wiz.Destroy() | |
830 | elif xxx.__class__ in [xxxWizardPage, xxxWizardPageSimple]: | |
831 | # Create new frame | |
832 | if not testWin: | |
833 | testWin = g.testWin = wxFrame(g.frame, -1, 'Wizard page: ' + name, | |
834 | pos=pos, name=STD_NAME) | |
835 | testWin.panel = wxPrePanel() | |
836 | res.LoadOnObject(testWin.panel, testWin, STD_NAME, 'wxPanel') | |
837 | testWin.SetClientSize(testWin.GetBestSize()) | |
838 | testWin.Show(True) | |
a4c013b2 RR |
839 | elif xxx.__class__ == xxxMenuBar: |
840 | testWin = g.testWin = wxFrame(g.frame, -1, 'MenuBar: ' + name, | |
841 | pos=pos, name=STD_NAME) | |
842 | testWin.panel = None | |
843 | # Set status bar to display help | |
844 | testWin.CreateStatusBar() | |
845 | testWin.menuBar = res.LoadMenuBar(STD_NAME) | |
846 | testWin.SetMenuBar(testWin.menuBar) | |
847 | testWin.Show(True) | |
848 | elif xxx.__class__ == xxxToolBar: | |
849 | testWin = g.testWin = wxFrame(g.frame, -1, 'ToolBar: ' + name, | |
d14a1e28 | 850 | pos=pos, name=STD_NAME) |
a4c013b2 RR |
851 | testWin.panel = None |
852 | # Set status bar to display help | |
853 | testWin.CreateStatusBar() | |
854 | testWin.toolBar = res.LoadToolBar(testWin, STD_NAME) | |
855 | testWin.SetToolBar(testWin.toolBar) | |
856 | testWin.Show(True) | |
64bce500 RR |
857 | if testWin: |
858 | testWin.item = item | |
859 | EVT_CLOSE(testWin, self.OnCloseTestWin) | |
860 | testWin.highLight = None | |
861 | if highLight and not self.pendingHighLight: | |
862 | self.HighLight(highLight) | |
a4c013b2 RR |
863 | except: |
864 | if g.testWin: | |
865 | self.SetItemBold(item, False) | |
866 | g.testWinPos = g.testWin.GetPosition() | |
867 | g.testWin.Destroy() | |
868 | g.testWin = None | |
869 | inf = sys.exc_info() | |
870 | wxLogError(traceback.format_exception(inf[0], inf[1], None)[-1]) | |
871 | wxLogError('Error loading resource') | |
d14a1e28 | 872 | wxMemoryFSHandler_RemoveFile('xxx.xrc') |
d14a1e28 RD |
873 | wxEndBusyCursor() |
874 | ||
64bce500 RR |
875 | def CloseTestWindow(self): |
876 | if not g.testWin: return | |
d14a1e28 | 877 | self.SetItemBold(g.testWin.item, False) |
016f67ba | 878 | g.frame.tb.ToggleTool(g.frame.ID_TOOL_LOCATE, False) |
d14a1e28 RD |
879 | g.testWinPos = g.testWin.GetPosition() |
880 | g.testWin.Destroy() | |
881 | g.testWin = None | |
882 | ||
64bce500 RR |
883 | def OnCloseTestWin(self, evt): |
884 | self.CloseTestWindow() | |
885 | ||
d14a1e28 RD |
886 | # Return item index in parent |
887 | def ItemIndex(self, item): | |
888 | n = 0 # index of sibling | |
889 | prev = self.GetPrevSibling(item) | |
890 | while prev.IsOk(): | |
891 | prev = self.GetPrevSibling(prev) | |
892 | n += 1 | |
893 | return n | |
894 | ||
895 | # Full tree index of an item - list of positions | |
896 | def ItemFullIndex(self, item): | |
897 | if not item.IsOk(): return None | |
898 | l = [] | |
899 | while item != self.root: | |
900 | l.insert(0, self.ItemIndex(item)) | |
901 | item = self.GetItemParent(item) | |
902 | return l | |
903 | # Get item position from full index | |
904 | def ItemAtFullIndex(self, index): | |
905 | if index is None: return wxTreeItemId() | |
906 | item = self.root | |
907 | for i in index: | |
fdc1a8be | 908 | item = self.GetFirstChild(item)[0] |
d14a1e28 RD |
909 | for k in range(i): item = self.GetNextSibling(item) |
910 | return item | |
911 | ||
912 | # True if next item should be inserted after current (vs. appended to it) | |
913 | def NeedInsert(self, item): | |
914 | xxx = self.GetPyData(item) | |
915 | if item == self.root: return False # root item | |
916 | if xxx.hasChildren and not self.GetChildrenCount(item, False): | |
917 | return False | |
918 | return not (self.IsExpanded(item) and self.GetChildrenCount(item, False)) | |
919 | ||
920 | # Pull-down | |
921 | def OnRightDown(self, evt): | |
922 | pullDownMenu = g.pullDownMenu | |
923 | # select this item | |
924 | pt = evt.GetPosition(); | |
925 | item, flags = self.HitTest(pt) | |
926 | if item.Ok() and flags & wxTREE_HITTEST_ONITEM: | |
927 | self.SelectItem(item) | |
928 | ||
929 | # Setup menu | |
930 | menu = wxMenu() | |
931 | ||
932 | item = self.selection | |
933 | if not item: | |
934 | menu.Append(g.pullDownMenu.ID_EXPAND, 'Expand', 'Expand tree') | |
935 | menu.Append(g.pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse tree') | |
936 | else: | |
937 | # self.ctrl = evt.ControlDown() # save Ctrl state | |
938 | # self.shift = evt.ShiftDown() # and Shift too | |
939 | m = wxMenu() # create menu | |
940 | if self.ctrl: | |
941 | needInsert = True | |
942 | else: | |
943 | needInsert = self.NeedInsert(item) | |
944 | if item == self.root or needInsert and self.GetItemParent(item) == self.root: | |
945 | SetMenu(m, pullDownMenu.topLevel) | |
946 | else: | |
947 | xxx = self.GetPyData(item).treeObject() | |
948 | # Check parent for possible child nodes if inserting sibling | |
949 | if needInsert: xxx = xxx.parent | |
950 | if xxx.__class__ == xxxMenuBar: | |
951 | m.Append(ID_NEW.MENU, 'Menu', 'Create menu') | |
952 | elif xxx.__class__ in [xxxToolBar, xxxTool] or \ | |
953 | xxx.__class__ == xxxSeparator and xxx.parent.__class__ == xxxToolBar: | |
954 | SetMenu(m, pullDownMenu.toolBarControls) | |
955 | elif xxx.__class__ in [xxxMenu, xxxMenuItem]: | |
956 | SetMenu(m, pullDownMenu.menuControls) | |
957 | else: | |
958 | SetMenu(m, pullDownMenu.controls) | |
959 | if xxx.__class__ == xxxNotebook: | |
960 | m.Enable(m.FindItem('sizer'), False) | |
961 | elif not (xxx.isSizer or xxx.parent and xxx.parent.isSizer): | |
962 | m.Enable(ID_NEW.SPACER, False) | |
963 | # Select correct label for create menu | |
964 | if not needInsert: | |
965 | if self.shift: | |
966 | menu.AppendMenu(wxNewId(), 'Insert Child', m, | |
967 | 'Create child object as the first child') | |
968 | else: | |
969 | menu.AppendMenu(wxNewId(), 'Append Child', m, | |
970 | 'Create child object as the last child') | |
971 | else: | |
972 | if self.shift: | |
973 | menu.AppendMenu(wxNewId(), 'Create Sibling', m, | |
974 | 'Create sibling before selected object') | |
975 | else: | |
976 | menu.AppendMenu(wxNewId(), 'Create Sibling', m, | |
977 | 'Create sibling after selected object') | |
978 | # Build replace menu | |
979 | if item != self.root: | |
980 | xxx = self.GetPyData(item).treeObject() | |
981 | m = wxMenu() # create replace menu | |
982 | if xxx.__class__ == xxxMenuBar: | |
983 | m.Append(1000 + ID_NEW.MENU, 'Menu', 'Create menu') | |
984 | elif xxx.__class__ in [xxxMenu, xxxMenuItem]: | |
985 | SetMenu2(m, pullDownMenu.menuControls) | |
986 | elif xxx.__class__ == xxxToolBar and \ | |
987 | self.GetItemParent(item) == self.root: | |
988 | SetMenu2(m, []) | |
989 | elif xxx.__class__ in [xxxFrame, xxxDialog, xxxPanel]: | |
990 | SetMenu2(m, [ | |
991 | (ID_NEW.PANEL, 'Panel', 'Create panel'), | |
992 | (ID_NEW.DIALOG, 'Dialog', 'Create dialog'), | |
993 | (ID_NEW.FRAME, 'Frame', 'Create frame')]) | |
994 | elif xxx.isSizer: | |
995 | SetMenu2(m, pullDownMenu.sizers) | |
996 | else: | |
997 | SetMenu2(m, pullDownMenu.controls) | |
998 | id = wxNewId() | |
999 | menu.AppendMenu(id, 'Replace With', m) | |
1000 | if not m.GetMenuItemCount(): menu.Enable(id, False) | |
2481bf3c RR |
1001 | menu.Append(pullDownMenu.ID_SUBCLASS, 'Subclass...', |
1002 | 'Set subclass property') | |
d14a1e28 RD |
1003 | menu.AppendSeparator() |
1004 | # Not using standart IDs because we don't want to show shortcuts | |
1005 | menu.Append(wxID_CUT, 'Cut', 'Cut to the clipboard') | |
1006 | menu.Append(wxID_COPY, 'Copy', 'Copy to the clipboard') | |
1007 | if self.ctrl and item != self.root: | |
1008 | menu.Append(pullDownMenu.ID_PASTE_SIBLING, 'Paste Sibling', | |
1009 | 'Paste from the clipboard as a sibling') | |
1010 | else: | |
1011 | menu.Append(wxID_PASTE, 'Paste', 'Paste from the clipboard') | |
1012 | menu.Append(pullDownMenu.ID_DELETE, | |
1013 | 'Delete', 'Delete object') | |
1014 | if self.ItemHasChildren(item): | |
1015 | menu.AppendSeparator() | |
1016 | menu.Append(pullDownMenu.ID_EXPAND, 'Expand', 'Expand subtree') | |
1017 | menu.Append(pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse subtree') | |
1018 | self.PopupMenu(menu, evt.GetPosition()) | |
1019 | menu.Destroy() | |
1020 | ||
1021 | # Apply changes | |
1022 | def Apply(self, xxx, item): | |
1023 | g.panel.Apply() | |
1024 | # Update tree view | |
1025 | xxx = xxx.treeObject() | |
1026 | if xxx.hasName and self.GetItemText(item) != xxx.name: | |
1027 | self.SetItemText(item, xxx.treeName()) | |
1028 | # Item width may have changed | |
1029 | # !!! Tric to update tree width (wxGTK, ??) | |
1030 | self.SetIndent(self.GetIndent()) | |
1031 | # Change tree icon for sizers | |
1032 | if isinstance(xxx, xxxBoxSizer): | |
1033 | self.SetItemImage(item, xxx.treeImage()) | |
1034 | # Set global modified state | |
1035 | g.frame.modified = True | |
1fded56b | 1036 |