]>
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 | ||
e5b889c9 RR |
14 | COLOUR_COMMENT = 'Blue' |
15 | COLOUR_REF = 'DarkGreen' | |
16 | COLOUR_HIDDEN = 'Grey' | |
17 | COLOUR_HL = 'Red' | |
18 | COLOUR_DT = 'Green' | |
19 | ||
d14a1e28 RD |
20 | # Icons |
21 | import images | |
22 | ||
23 | class MemoryFile: | |
24 | def __init__(self, name): | |
25 | self.name = name | |
26 | self.buffer = '' | |
27 | def write(self, data): | |
9a69d0aa | 28 | if g.currentEncoding: |
4eb5bfc6 | 29 | encoding = g.currentEncoding |
9a69d0aa | 30 | else: |
29a41103 | 31 | encoding = wx.GetDefaultPyEncoding() |
4eb5bfc6 RD |
32 | try: |
33 | self.buffer += data.encode(encoding) | |
34 | except UnicodeEncodeError: | |
35 | self.buffer += data.encode(encoding, 'xmlcharrefreplace') | |
36 | ||
d14a1e28 | 37 | def close(self): |
29a41103 | 38 | wx.MemoryFSHandler.AddFile(self.name, self.buffer) |
d14a1e28 RD |
39 | |
40 | ################################################################################ | |
41 | ||
42 | # Redefine writing to include encoding | |
43 | class MyDocument(minidom.Document): | |
44 | def __init__(self): | |
45 | minidom.Document.__init__(self) | |
46 | self.encoding = '' | |
47 | def writexml(self, writer, indent="", addindent="", newl="", encoding=""): | |
48 | if encoding: encdstr = 'encoding="%s"' % encoding | |
49 | else: encdstr = '' | |
50 | writer.write('<?xml version="1.0" %s?>\n' % encdstr) | |
51 | for node in self.childNodes: | |
52 | node.writexml(writer, indent, addindent, newl) | |
53 | ||
54 | ################################################################################ | |
55 | ||
56 | # Ids for menu commands | |
57 | class ID_NEW: | |
29a41103 RD |
58 | PANEL = wx.NewId() |
59 | DIALOG = wx.NewId() | |
60 | FRAME = wx.NewId() | |
61 | TOOL_BAR = wx.NewId() | |
62 | TOOL = wx.NewId() | |
63 | MENU_BAR = wx.NewId() | |
64 | MENU = wx.NewId() | |
65 | STATUS_BAR = wx.NewId() | |
d14a1e28 | 66 | |
29a41103 RD |
67 | STATIC_TEXT = wx.NewId() |
68 | TEXT_CTRL = wx.NewId() | |
d14a1e28 | 69 | |
29a41103 RD |
70 | BUTTON = wx.NewId() |
71 | BITMAP_BUTTON = wx.NewId() | |
72 | RADIO_BUTTON = wx.NewId() | |
73 | SPIN_BUTTON = wx.NewId() | |
74 | TOGGLE_BUTTON = wx.NewId() | |
d14a1e28 | 75 | |
29a41103 RD |
76 | STATIC_BOX = wx.NewId() |
77 | CHECK_BOX = wx.NewId() | |
78 | RADIO_BOX = wx.NewId() | |
79 | COMBO_BOX = wx.NewId() | |
80 | LIST_BOX = wx.NewId() | |
d14a1e28 | 81 | |
29a41103 RD |
82 | STATIC_LINE = wx.NewId() |
83 | STATIC_BITMAP = wx.NewId() | |
84 | CHOICE = wx.NewId() | |
85 | SLIDER = wx.NewId() | |
86 | GAUGE = wx.NewId() | |
87 | SCROLL_BAR = wx.NewId() | |
88 | TREE_CTRL = wx.NewId() | |
89 | LIST_CTRL = wx.NewId() | |
90 | CHECK_LIST = wx.NewId() | |
91 | NOTEBOOK = wx.NewId() | |
92 | CHOICEBOOK = wx.NewId() | |
93 | LISTBOOK = wx.NewId() | |
94 | SPLITTER_WINDOW = wx.NewId() | |
b372319f | 95 | GRID = wx.NewId() |
29a41103 RD |
96 | SCROLLED_WINDOW = wx.NewId() |
97 | HTML_WINDOW = wx.NewId() | |
98 | CALENDAR_CTRL = wx.NewId() | |
99 | DATE_CTRL = wx.NewId() | |
b372319f | 100 | FILE_PICKER_CTRL = wx.NewId() |
29a41103 RD |
101 | GENERIC_DIR_CTRL = wx.NewId() |
102 | SPIN_CTRL = wx.NewId() | |
103 | UNKNOWN = wx.NewId() | |
104 | WIZARD = wx.NewId() | |
105 | WIZARD_PAGE = wx.NewId() | |
106 | WIZARD_PAGE_SIMPLE = wx.NewId() | |
107 | BITMAP = wx.NewId() | |
108 | ICON = wx.NewId() | |
109 | STATUS_BAR = wx.NewId() | |
d14a1e28 | 110 | |
29a41103 RD |
111 | BOX_SIZER = wx.NewId() |
112 | STATIC_BOX_SIZER = wx.NewId() | |
113 | GRID_SIZER = wx.NewId() | |
114 | FLEX_GRID_SIZER = wx.NewId() | |
115 | GRID_BAG_SIZER = wx.NewId() | |
116 | STD_DIALOG_BUTTON_SIZER = wx.NewId() | |
117 | SPACER = wx.NewId() | |
64bce500 | 118 | |
29a41103 RD |
119 | TOOL_BAR = wx.NewId() |
120 | TOOL = wx.NewId() | |
121 | MENU = wx.NewId() | |
122 | MENU_ITEM = wx.NewId() | |
123 | SEPARATOR = wx.NewId() | |
64b9ac75 | 124 | |
29a41103 RD |
125 | OK_BUTTON = wx.NewId() |
126 | YES_BUTTON = wx.NewId() | |
127 | SAVE_BUTTON = wx.NewId() | |
128 | APPLY_BUTTON = wx.NewId() | |
129 | NO_BUTTON = wx.NewId() | |
130 | CANCEL_BUTTON = wx.NewId() | |
131 | HELP_BUTTON = wx.NewId() | |
132 | CONTEXT_HELP_BUTTON = wx.NewId() | |
64b9ac75 | 133 | |
29a41103 | 134 | REF = wx.NewId() |
b372319f | 135 | COMMENT = wx.NewId() |
03319b65 | 136 | |
c0d5ae74 RR |
137 | CUSTOM = wx.NewId() |
138 | for i in range(99): wx.NewId() # reserve IDs for custom controls | |
139 | ||
29a41103 | 140 | LAST = wx.NewId() |
d14a1e28 | 141 | |
64b9ac75 RR |
142 | |
143 | ||
d14a1e28 | 144 | class PullDownMenu: |
29a41103 RD |
145 | ID_EXPAND = wx.NewId() |
146 | ID_COLLAPSE = wx.NewId() | |
147 | ID_PASTE_SIBLING = wx.NewId() | |
148 | ID_TOOL_PASTE = wx.NewId() | |
149 | ID_SUBCLASS = wx.NewId() | |
d14a1e28 RD |
150 | |
151 | def __init__(self, parent): | |
152 | self.ID_DELETE = parent.ID_DELETE | |
29a41103 RD |
153 | wx.EVT_MENU_RANGE(parent, ID_NEW.PANEL, ID_NEW.LAST, parent.OnCreate) |
154 | wx.EVT_MENU_RANGE(parent, 1000 + ID_NEW.PANEL, 1000 + ID_NEW.LAST, parent.OnReplace) | |
155 | wx.EVT_MENU(parent, self.ID_COLLAPSE, parent.OnCollapse) | |
156 | wx.EVT_MENU(parent, self.ID_EXPAND, parent.OnExpand) | |
157 | wx.EVT_MENU(parent, self.ID_PASTE_SIBLING, parent.OnPaste) | |
158 | wx.EVT_MENU(parent, self.ID_SUBCLASS, parent.OnSubclass) | |
d14a1e28 | 159 | # We connect to tree, but process in frame |
29a41103 | 160 | wx.EVT_MENU_HIGHLIGHT_ALL(g.tree, parent.OnPullDownHighlight) |
d14a1e28 RD |
161 | |
162 | # Mapping from IDs to element names | |
163 | self.createMap = { | |
164 | ID_NEW.PANEL: 'wxPanel', | |
165 | ID_NEW.DIALOG: 'wxDialog', | |
166 | ID_NEW.FRAME: 'wxFrame', | |
64bce500 RR |
167 | ID_NEW.WIZARD: 'wxWizard', |
168 | ID_NEW.WIZARD_PAGE: 'wxWizardPage', | |
169 | ID_NEW.WIZARD_PAGE_SIMPLE: 'wxWizardPageSimple', | |
d14a1e28 RD |
170 | ID_NEW.TOOL_BAR: 'wxToolBar', |
171 | ID_NEW.TOOL: 'tool', | |
306b6fe9 | 172 | ID_NEW.STATUS_BAR: 'wxStatusBar', |
d14a1e28 RD |
173 | ID_NEW.MENU_BAR: 'wxMenuBar', |
174 | ID_NEW.MENU: 'wxMenu', | |
175 | ID_NEW.MENU_ITEM: 'wxMenuItem', | |
306b6fe9 RR |
176 | ID_NEW.BITMAP: 'wxBitmap', |
177 | ID_NEW.ICON: 'wxIcon', | |
d14a1e28 RD |
178 | ID_NEW.SEPARATOR: 'separator', |
179 | ||
180 | ID_NEW.STATIC_TEXT: 'wxStaticText', | |
181 | ID_NEW.TEXT_CTRL: 'wxTextCtrl', | |
182 | ||
183 | ID_NEW.BUTTON: 'wxButton', | |
184 | ID_NEW.BITMAP_BUTTON: 'wxBitmapButton', | |
185 | ID_NEW.RADIO_BUTTON: 'wxRadioButton', | |
186 | ID_NEW.SPIN_BUTTON: 'wxSpinButton', | |
3d49f2fb | 187 | ID_NEW.TOGGLE_BUTTON: 'wxToggleButton', |
d14a1e28 RD |
188 | |
189 | ID_NEW.STATIC_BOX: 'wxStaticBox', | |
190 | ID_NEW.CHECK_BOX: 'wxCheckBox', | |
191 | ID_NEW.RADIO_BOX: 'wxRadioBox', | |
192 | ID_NEW.COMBO_BOX: 'wxComboBox', | |
193 | ID_NEW.LIST_BOX: 'wxListBox', | |
306b6fe9 | 194 | ID_NEW.CHECK_LIST: 'wxCheckListBox', |
d14a1e28 RD |
195 | |
196 | ID_NEW.STATIC_LINE: 'wxStaticLine', | |
197 | ID_NEW.STATIC_BITMAP: 'wxStaticBitmap', | |
198 | ID_NEW.CHOICE: 'wxChoice', | |
199 | ID_NEW.SLIDER: 'wxSlider', | |
200 | ID_NEW.GAUGE: 'wxGauge', | |
201 | ID_NEW.SCROLL_BAR: 'wxScrollBar', | |
202 | ID_NEW.TREE_CTRL: 'wxTreeCtrl', | |
203 | ID_NEW.LIST_CTRL: 'wxListCtrl', | |
d14a1e28 | 204 | ID_NEW.NOTEBOOK: 'wxNotebook', |
306b6fe9 RR |
205 | ID_NEW.CHOICEBOOK: 'wxChoicebook', |
206 | ID_NEW.LISTBOOK: 'wxListbook', | |
68ae5821 | 207 | ID_NEW.SPLITTER_WINDOW: 'wxSplitterWindow', |
b372319f | 208 | ID_NEW.GRID: 'wxGrid', |
d14a1e28 RD |
209 | ID_NEW.SCROLLED_WINDOW: 'wxScrolledWindow', |
210 | ID_NEW.HTML_WINDOW: 'wxHtmlWindow', | |
211 | ID_NEW.CALENDAR_CTRL: 'wxCalendarCtrl', | |
306b6fe9 | 212 | ID_NEW.DATE_CTRL: 'wxDatePickerCtrl', |
b372319f | 213 | ID_NEW.FILE_PICKER_CTRL: 'wxFilePickerCtrl', |
d14a1e28 RD |
214 | ID_NEW.GENERIC_DIR_CTRL: 'wxGenericDirCtrl', |
215 | ID_NEW.SPIN_CTRL: 'wxSpinCtrl', | |
216 | ||
217 | ID_NEW.BOX_SIZER: 'wxBoxSizer', | |
218 | ID_NEW.STATIC_BOX_SIZER: 'wxStaticBoxSizer', | |
219 | ID_NEW.GRID_SIZER: 'wxGridSizer', | |
220 | ID_NEW.FLEX_GRID_SIZER: 'wxFlexGridSizer', | |
a4c013b2 | 221 | ID_NEW.GRID_BAG_SIZER: 'wxGridBagSizer', |
64bce500 | 222 | ID_NEW.STD_DIALOG_BUTTON_SIZER: 'wxStdDialogButtonSizer', |
d14a1e28 RD |
223 | ID_NEW.SPACER: 'spacer', |
224 | ID_NEW.UNKNOWN: 'unknown', | |
64b9ac75 RR |
225 | |
226 | ID_NEW.OK_BUTTON: 'wxButton', | |
227 | ID_NEW.YES_BUTTON: 'wxButton', | |
228 | ID_NEW.SAVE_BUTTON: 'wxButton', | |
229 | ID_NEW.APPLY_BUTTON: 'wxButton', | |
230 | ID_NEW.NO_BUTTON: 'wxButton', | |
231 | ID_NEW.CANCEL_BUTTON: 'wxButton', | |
232 | ID_NEW.HELP_BUTTON: 'wxButton', | |
233 | ID_NEW.CONTEXT_HELP_BUTTON: 'wxButton', | |
d14a1e28 RD |
234 | } |
235 | self.topLevel = [ | |
236 | (ID_NEW.PANEL, 'Panel', 'Create panel'), | |
237 | (ID_NEW.DIALOG, 'Dialog', 'Create dialog'), | |
238 | (ID_NEW.FRAME, 'Frame', 'Create frame'), | |
64bce500 | 239 | (ID_NEW.WIZARD, 'Wizard', 'Create wizard'), |
d14a1e28 RD |
240 | None, |
241 | (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'), | |
242 | (ID_NEW.MENU_BAR, 'MenuBar', 'Create menubar'), | |
306b6fe9 RR |
243 | (ID_NEW.MENU, 'Menu', 'Create menu'), |
244 | None, | |
245 | (ID_NEW.BITMAP, 'Bitmap', 'Create bitmap'), | |
246 | (ID_NEW.ICON, 'Icon', 'Create icon'), | |
d14a1e28 RD |
247 | ] |
248 | self.containers = [ | |
249 | (ID_NEW.PANEL, 'Panel', 'Create panel'), | |
250 | (ID_NEW.NOTEBOOK, 'Notebook', 'Create notebook control'), | |
306b6fe9 RR |
251 | (ID_NEW.CHOICEBOOK, 'Choicebook', 'Create choicebook control'), |
252 | (ID_NEW.LISTBOOK, 'Listbook', 'Create listbook control'), | |
68ae5821 | 253 | (ID_NEW.SPLITTER_WINDOW, 'SplitterWindow', 'Create splitter window'), |
d14a1e28 | 254 | (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'), |
306b6fe9 | 255 | (ID_NEW.STATUS_BAR, 'StatusBar', 'Create status bar'), |
64bce500 RR |
256 | # (ID_NEW.WIZARD_PAGE, 'WizardPage', 'Create wizard page'), |
257 | (ID_NEW.WIZARD_PAGE_SIMPLE, 'WizardPageSimple', 'Create simple wizard page'), | |
d14a1e28 RD |
258 | ] |
259 | self.sizers = [ | |
260 | (ID_NEW.BOX_SIZER, 'BoxSizer', 'Create box sizer'), | |
261 | (ID_NEW.STATIC_BOX_SIZER, 'StaticBoxSizer', | |
262 | 'Create static box sizer'), | |
263 | (ID_NEW.GRID_SIZER, 'GridSizer', 'Create grid sizer'), | |
264 | (ID_NEW.FLEX_GRID_SIZER, 'FlexGridSizer', | |
265 | 'Create flexgrid sizer'), | |
a4c013b2 RR |
266 | (ID_NEW.GRID_BAG_SIZER, 'GridBagSizer', |
267 | 'Create gridbag sizer'), | |
64bce500 RR |
268 | # (ID_NEW.STD_DIALOG_BUTTON_SIZER, 'StdDialogButtonSizer', |
269 | # 'Create standard button sizer'), | |
d14a1e28 RD |
270 | (ID_NEW.SPACER, 'Spacer', 'Create spacer'), |
271 | ] | |
272 | self.controls = [ | |
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.SPIN_CTRL, 'SpinCtrl', 'Create spin'), | |
282 | (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'), | |
283 | (ID_NEW.TREE_CTRL, 'TreeCtrl', 'Create tree'), | |
284 | (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list'), | |
b372319f | 285 | # (ID_NEW.GRID, 'Grid', 'Create grid'), |
d14a1e28 RD |
286 | (ID_NEW.SCROLLED_WINDOW, 'ScrolledWindow', 'Create scrolled window'), |
287 | (ID_NEW.HTML_WINDOW, 'HtmlWindow', 'Create HTML window'), | |
288 | (ID_NEW.CALENDAR_CTRL, 'CalendarCtrl', 'Create calendar control'), | |
306b6fe9 | 289 | (ID_NEW.DATE_CTRL, 'DatePickerCtrl', 'Create date picker control'), |
b372319f | 290 | # (ID_NEW.FILE_PICKER_CTRL, 'FilePickerCtrl', 'Create file picker control'), |
d14a1e28 RD |
291 | (ID_NEW.GENERIC_DIR_CTRL, 'GenericDirCtrl', 'Create generic dir control'), |
292 | (ID_NEW.UNKNOWN, 'Unknown', 'Create custom control placeholder'), | |
293 | ], | |
294 | ['button', 'Buttons', | |
295 | (ID_NEW.BUTTON, 'Button', 'Create button'), | |
296 | (ID_NEW.BITMAP_BUTTON, 'BitmapButton', 'Create bitmap button'), | |
297 | (ID_NEW.RADIO_BUTTON, 'RadioButton', 'Create radio button'), | |
298 | (ID_NEW.SPIN_BUTTON, 'SpinButton', 'Create spin button'), | |
3d49f2fb | 299 | (ID_NEW.TOGGLE_BUTTON, 'ToggleButton', 'Create toggle button'), |
d14a1e28 RD |
300 | ], |
301 | ['box', 'Boxes', | |
302 | (ID_NEW.STATIC_BOX, 'StaticBox', 'Create static box'), | |
303 | (ID_NEW.CHECK_BOX, 'CheckBox', 'Create check box'), | |
304 | (ID_NEW.RADIO_BOX, 'RadioBox', 'Create radio box'), | |
305 | (ID_NEW.COMBO_BOX, 'ComboBox', 'Create combo box'), | |
306 | (ID_NEW.LIST_BOX, 'ListBox', 'Create list box'), | |
306b6fe9 | 307 | (ID_NEW.CHECK_LIST, 'CheckListBox', 'Create checklist box'), |
d14a1e28 RD |
308 | ], |
309 | ['container', 'Containers', | |
310 | (ID_NEW.PANEL, 'Panel', 'Create panel'), | |
311 | (ID_NEW.NOTEBOOK, 'Notebook', 'Create notebook control'), | |
306b6fe9 RR |
312 | (ID_NEW.CHOICEBOOK, 'Choicebook', 'Create choicebook control'), |
313 | (ID_NEW.LISTBOOK, 'Listbook', 'Create listbook control'), | |
68ae5821 | 314 | (ID_NEW.SPLITTER_WINDOW, 'SplitterWindow', 'Create splitter window'), |
d14a1e28 | 315 | (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'), |
306b6fe9 | 316 | (ID_NEW.STATUS_BAR, 'StatusBar', 'Create status bar'), |
f65bb0f8 | 317 | (ID_NEW.MENU_BAR, 'MenuBar', 'Create menubar'), |
64bce500 RR |
318 | # (ID_NEW.WIZARD_PAGE, 'Wizard Page', 'Create wizard page'), |
319 | (ID_NEW.WIZARD_PAGE_SIMPLE, 'WizardPageSimple', 'Create simple wizard page'), | |
d14a1e28 RD |
320 | ], |
321 | ['sizer', 'Sizers', | |
322 | (ID_NEW.BOX_SIZER, 'BoxSizer', 'Create box sizer'), | |
323 | (ID_NEW.STATIC_BOX_SIZER, 'StaticBoxSizer', | |
324 | 'Create static box sizer'), | |
325 | (ID_NEW.GRID_SIZER, 'GridSizer', 'Create grid sizer'), | |
326 | (ID_NEW.FLEX_GRID_SIZER, 'FlexGridSizer', | |
327 | 'Create flexgrid sizer'), | |
a4c013b2 RR |
328 | (ID_NEW.GRID_BAG_SIZER, 'GridBagSizer', |
329 | 'Create gridbag sizer'), | |
d14a1e28 | 330 | (ID_NEW.SPACER, 'Spacer', 'Create spacer'), |
64bce500 RR |
331 | (ID_NEW.STD_DIALOG_BUTTON_SIZER, 'StdDialogButtonSizer', |
332 | 'Create standard button sizer'), | |
d14a1e28 RD |
333 | ] |
334 | ] | |
335 | self.menuControls = [ | |
336 | (ID_NEW.MENU, 'Menu', 'Create menu'), | |
337 | (ID_NEW.MENU_ITEM, 'MenuItem', 'Create menu item'), | |
338 | (ID_NEW.SEPARATOR, 'Separator', 'Create separator'), | |
339 | ] | |
340 | self.toolBarControls = [ | |
341 | (ID_NEW.TOOL, 'Tool', 'Create tool'), | |
342 | (ID_NEW.SEPARATOR, 'Separator', 'Create separator'), | |
343 | ['control', 'Various controls', | |
344 | (ID_NEW.STATIC_TEXT, 'Label', 'Create label'), | |
345 | (ID_NEW.STATIC_BITMAP, 'Bitmap', 'Create bitmap'), | |
346 | (ID_NEW.STATIC_LINE, 'Line', 'Create line'), | |
347 | (ID_NEW.TEXT_CTRL, 'TextBox', 'Create text box'), | |
348 | (ID_NEW.CHOICE, 'Choice', 'Create choice'), | |
349 | (ID_NEW.SLIDER, 'Slider', 'Create slider'), | |
350 | (ID_NEW.GAUGE, 'Gauge', 'Create gauge'), | |
351 | (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'), | |
352 | (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list control'), | |
d14a1e28 RD |
353 | ], |
354 | ['button', 'Buttons', | |
355 | (ID_NEW.BUTTON, 'Button', 'Create button'), | |
356 | (ID_NEW.BITMAP_BUTTON, 'BitmapButton', 'Create bitmap button'), | |
357 | (ID_NEW.RADIO_BUTTON, 'RadioButton', 'Create radio button'), | |
358 | (ID_NEW.SPIN_BUTTON, 'SpinButton', 'Create spin button'), | |
359 | ], | |
360 | ['box', 'Boxes', | |
361 | (ID_NEW.STATIC_BOX, 'StaticBox', 'Create static box'), | |
362 | (ID_NEW.CHECK_BOX, 'CheckBox', 'Create check box'), | |
363 | (ID_NEW.RADIO_BOX, 'RadioBox', 'Create radio box'), | |
364 | (ID_NEW.COMBO_BOX, 'ComboBox', 'Create combo box'), | |
365 | (ID_NEW.LIST_BOX, 'ListBox', 'Create list box'), | |
306b6fe9 | 366 | (ID_NEW.CHECK_LIST, 'CheckListBox', 'Create checklist box'), |
d14a1e28 RD |
367 | ], |
368 | ] | |
64b9ac75 RR |
369 | self.stdButtons = [ |
370 | (ID_NEW.OK_BUTTON, 'OK Button', 'Create standard button'), | |
371 | (ID_NEW.YES_BUTTON, 'YES Button', 'Create standard button'), | |
372 | (ID_NEW.SAVE_BUTTON, 'SAVE Button', 'Create standard button'), | |
373 | (ID_NEW.APPLY_BUTTON, 'APPLY Button', 'Create standard button'), | |
374 | (ID_NEW.NO_BUTTON, 'NO Button', 'Create standard button'), | |
375 | (ID_NEW.CANCEL_BUTTON, 'CANCEL Button', 'Create standard button'), | |
376 | (ID_NEW.HELP_BUTTON, 'HELP Button', 'Create standard button'), | |
377 | (ID_NEW.CONTEXT_HELP_BUTTON, 'CONTEXT HELP Button', 'Create standard button'), | |
378 | ] | |
379 | self.stdButtonIDs = { | |
380 | ID_NEW.OK_BUTTON: ('wxID_OK', '&Ok'), | |
381 | ID_NEW.YES_BUTTON: ('wxID_YES', '&Yes'), | |
382 | ID_NEW.SAVE_BUTTON: ('wxID_SAVE', '&Save'), | |
383 | ID_NEW.APPLY_BUTTON: ('wxID_APPLY', '&Apply'), | |
384 | ID_NEW.NO_BUTTON: ('wxID_NO', '&No'), | |
385 | ID_NEW.CANCEL_BUTTON: ('wxID_CANCEL', '&Cancel'), | |
386 | ID_NEW.HELP_BUTTON: ('wxID_HELP', '&Help'), | |
387 | ID_NEW.CONTEXT_HELP_BUTTON: ('wxID_CONTEXT_HELP', '&Help'), | |
388 | } | |
8c64c153 | 389 | self.custom = ['custom', 'User-defined controls'] |
c0d5ae74 RR |
390 | self.customMap = {} |
391 | ||
392 | def addCustom(self, klass): | |
8c64c153 RR |
393 | n = len(self.custom)-2 |
394 | self.custom.append((ID_NEW.CUSTOM + n, klass)) | |
c0d5ae74 | 395 | self.customMap[ID_NEW.CUSTOM + n] = klass |
64b9ac75 | 396 | |
d14a1e28 RD |
397 | |
398 | ################################################################################ | |
399 | ||
400 | # Set menu to list items. | |
401 | # Each menu command is a tuple (id, label, help) | |
402 | # submenus are lists [id, label, help, submenu] | |
64b9ac75 RR |
403 | # and separators are any other type. Shift is for making |
404 | # alternative sets of IDs. (+1000). | |
405 | def SetMenu(m, list, shift=False): | |
d14a1e28 RD |
406 | for l in list: |
407 | if type(l) == types.TupleType: | |
408 | # Shift ID | |
64b9ac75 | 409 | if shift: l = (1000 + l[0],) + l[1:] |
d14a1e28 RD |
410 | apply(m.Append, l) |
411 | elif type(l) == types.ListType: | |
29a41103 | 412 | subMenu = wx.Menu() |
0725108f | 413 | SetMenu(subMenu, l[2:], shift) |
29a41103 | 414 | m.AppendMenu(wx.NewId(), l[0], subMenu, l[1]) |
d14a1e28 RD |
415 | else: # separator |
416 | m.AppendSeparator() | |
417 | ||
418 | ################################################################################ | |
419 | ||
420 | class HighLightBox: | |
e5b889c9 | 421 | colour = None |
d14a1e28 | 422 | def __init__(self, pos, size): |
e5b889c9 RR |
423 | if not self.colour: colour = self.colour = wx.NamedColour(COLOUR_HL) |
424 | else: colour = self.colour | |
d14a1e28 RD |
425 | if size.width == -1: size.width = 0 |
426 | if size.height == -1: size.height = 0 | |
427 | w = g.testWin.panel | |
29a41103 | 428 | l1 = wx.Window(w, -1, pos, wx.Size(size.width, 2)) |
e5b889c9 | 429 | l1.SetBackgroundColour(self.colour) |
29a41103 | 430 | l2 = wx.Window(w, -1, pos, wx.Size(2, size.height)) |
e5b889c9 | 431 | l2.SetBackgroundColour(self.colour) |
29a41103 | 432 | l3 = wx.Window(w, -1, wx.Point(pos.x + size.width - 2, pos.y), wx.Size(2, size.height)) |
e5b889c9 | 433 | l3.SetBackgroundColour(self.colour) |
29a41103 | 434 | l4 = wx.Window(w, -1, wx.Point(pos.x, pos.y + size.height - 2), wx.Size(size.width, 2)) |
e5b889c9 | 435 | l4.SetBackgroundColour(self.colour) |
d14a1e28 | 436 | self.lines = [l1, l2, l3, l4] |
8c64c153 | 437 | self.size = size |
e5b889c9 | 438 | g.testWin.highLight = self |
d14a1e28 RD |
439 | # Move highlight to a new position |
440 | def Replace(self, pos, size): | |
441 | if size.width == -1: size.width = 0 | |
442 | if size.height == -1: size.height = 0 | |
443 | self.lines[0].SetDimensions(pos.x, pos.y, size.width, 2) | |
444 | self.lines[1].SetDimensions(pos.x, pos.y, 2, size.height) | |
445 | self.lines[2].SetDimensions(pos.x + size.width - 2, pos.y, 2, size.height) | |
446 | self.lines[3].SetDimensions(pos.x, pos.y + size.height - 2, size.width, 2) | |
8c64c153 | 447 | self.size = size |
d14a1e28 RD |
448 | # Remove it |
449 | def Remove(self): | |
29a41103 | 450 | map(wx.Window.Destroy, self.lines) |
d14a1e28 | 451 | g.testWin.highLight = None |
9a69d0aa | 452 | def Refresh(self): |
29a41103 | 453 | map(wx.Window.Refresh, self.lines) |
d14a1e28 | 454 | |
e5b889c9 RR |
455 | # Same for drop target |
456 | class HighLightDTBox(HighLightBox): | |
457 | colour = None | |
458 | def __init__(self, pos, size): | |
459 | if not self.colour: colour = self.colour = wx.NamedColour(COLOUR_DT) | |
460 | else: colour = self.colour | |
461 | if size.width == -1: size.width = 0 | |
462 | if size.height == -1: size.height = 0 | |
463 | w = g.testWin.panel | |
464 | l1 = wx.Window(w, -1, pos, wx.Size(size.width, 2)) | |
465 | l1.SetBackgroundColour(colour) | |
466 | l2 = wx.Window(w, -1, pos, wx.Size(2, size.height)) | |
467 | l2.SetBackgroundColour(colour) | |
468 | l3 = wx.Window(w, -1, wx.Point(pos.x + size.width - 2, pos.y), wx.Size(2, size.height)) | |
469 | l3.SetBackgroundColour(colour) | |
470 | l4 = wx.Window(w, -1, wx.Point(pos.x, pos.y + size.height - 2), wx.Size(size.width, 2)) | |
471 | l4.SetBackgroundColour(colour) | |
472 | self.lines = [l1, l2, l3, l4] | |
473 | self.size = size | |
474 | self.item = None | |
475 | # Remove it | |
476 | def Remove(self): | |
477 | map(wx.Window.Destroy, self.lines) | |
478 | g.testWin.highLightDT = None | |
479 | ||
480 | def updateHL(hl, hlClass, pos, size): | |
481 | if hl and hl.size == size: | |
482 | hl.Remove() | |
483 | hl = None | |
484 | if hl: | |
485 | hl.Replace(pos, size) | |
486 | hl.Refresh() | |
487 | else: | |
488 | hl = hlClass(pos, size) | |
489 | return hl | |
490 | ||
d14a1e28 RD |
491 | ################################################################################ |
492 | ||
29a41103 | 493 | class XML_Tree(wx.TreeCtrl): |
d14a1e28 | 494 | def __init__(self, parent, id): |
fe295b0d RR |
495 | wx.TreeCtrl.__init__(self, parent, id, |
496 | style = wx.TR_HAS_BUTTONS | wx.TR_MULTIPLE | wx.TR_EDIT_LABELS) | |
29a41103 | 497 | self.SetBackgroundColour(wx.Colour(224, 248, 224)) |
fe295b0d RR |
498 | self.fontComment = wx.FFont(self.GetFont().GetPointSize(), |
499 | self.GetFont().GetFamily(), | |
500 | wx.FONTFLAG_ITALIC) | |
d14a1e28 | 501 | # Register events |
29a41103 | 502 | wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged) |
d14a1e28 | 503 | # One works on Linux, another on Windows |
29a41103 RD |
504 | if wx.Platform == '__WXGTK__': |
505 | wx.EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated) | |
d14a1e28 | 506 | else: |
29a41103 RD |
507 | wx.EVT_LEFT_DCLICK(self, self.OnDClick) |
508 | wx.EVT_RIGHT_DOWN(self, self.OnRightDown) | |
509 | wx.EVT_TREE_ITEM_EXPANDED(self, self.GetId(), self.OnItemExpandedCollapsed) | |
510 | wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemExpandedCollapsed) | |
fe295b0d RR |
511 | self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnBeginLabelEdit) |
512 | self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnEndLabelEdit) | |
d14a1e28 RD |
513 | |
514 | self.selection = None | |
2458faeb | 515 | self.selectionChanging = False |
d14a1e28 RD |
516 | self.needUpdate = False |
517 | self.pendingHighLight = None | |
518 | self.ctrl = self.shift = False | |
519 | self.dom = None | |
520 | # Create image list | |
29a41103 | 521 | il = wx.ImageList(16, 16, True) |
d14a1e28 | 522 | self.rootImage = il.Add(images.getTreeRootImage().Scale(16,16).ConvertToBitmap()) |
b372319f | 523 | xxxComment.image = il.Add(images.getTreeCommentImage().Scale(16,16).ConvertToBitmap()) |
d14a1e28 RD |
524 | xxxObject.image = il.Add(images.getTreeDefaultImage().Scale(16,16).ConvertToBitmap()) |
525 | xxxPanel.image = il.Add(images.getTreePanelImage().Scale(16,16).ConvertToBitmap()) | |
526 | xxxDialog.image = il.Add(images.getTreeDialogImage().Scale(16,16).ConvertToBitmap()) | |
527 | xxxFrame.image = il.Add(images.getTreeFrameImage().Scale(16,16).ConvertToBitmap()) | |
528 | xxxMenuBar.image = il.Add(images.getTreeMenuBarImage().Scale(16,16).ConvertToBitmap()) | |
529 | xxxMenu.image = il.Add(images.getTreeMenuImage().Scale(16,16).ConvertToBitmap()) | |
530 | xxxMenuItem.image = il.Add(images.getTreeMenuItemImage().Scale(16,16).ConvertToBitmap()) | |
531 | xxxToolBar.image = il.Add(images.getTreeToolBarImage().Scale(16,16).ConvertToBitmap()) | |
532 | xxxTool.image = il.Add(images.getTreeToolImage().Scale(16,16).ConvertToBitmap()) | |
533 | xxxSeparator.image = il.Add(images.getTreeSeparatorImage().Scale(16,16).ConvertToBitmap()) | |
534 | xxxSizer.imageH = il.Add(images.getTreeSizerHImage().Scale(16,16).ConvertToBitmap()) | |
535 | xxxSizer.imageV = il.Add(images.getTreeSizerVImage().Scale(16,16).ConvertToBitmap()) | |
536 | xxxStaticBoxSizer.imageH = il.Add(images.getTreeStaticBoxSizerHImage().Scale(16,16).ConvertToBitmap()) | |
537 | xxxStaticBoxSizer.imageV = il.Add(images.getTreeStaticBoxSizerVImage().Scale(16,16).ConvertToBitmap()) | |
538 | xxxGridSizer.image = il.Add(images.getTreeSizerGridImage().Scale(16,16).ConvertToBitmap()) | |
539 | xxxFlexGridSizer.image = il.Add(images.getTreeSizerFlexGridImage().Scale(16,16).ConvertToBitmap()) | |
540 | self.il = il | |
541 | self.SetImageList(il) | |
542 | ||
543 | def RegisterKeyEvents(self): | |
29a41103 RD |
544 | wx.EVT_KEY_DOWN(self, g.tools.OnKeyDown) |
545 | wx.EVT_KEY_UP(self, g.tools.OnKeyUp) | |
546 | wx.EVT_ENTER_WINDOW(self, g.tools.OnMouse) | |
547 | wx.EVT_LEAVE_WINDOW(self, g.tools.OnMouse) | |
d14a1e28 | 548 | |
d14a1e28 RD |
549 | def ExpandAll(self, item): |
550 | if self.ItemHasChildren(item): | |
551 | self.Expand(item) | |
fdc1a8be | 552 | i, cookie = self.GetFirstChild(item) |
d14a1e28 RD |
553 | children = [] |
554 | while i.IsOk(): | |
555 | children.append(i) | |
556 | i, cookie = self.GetNextChild(item, cookie) | |
557 | for i in children: | |
558 | self.ExpandAll(i) | |
559 | def CollapseAll(self, item): | |
560 | if self.ItemHasChildren(item): | |
fdc1a8be | 561 | i, cookie = self.GetFirstChild(item) |
d14a1e28 RD |
562 | children = [] |
563 | while i.IsOk(): | |
564 | children.append(i) | |
565 | i, cookie = self.GetNextChild(item, cookie) | |
566 | for i in children: | |
567 | self.CollapseAll(i) | |
568 | self.Collapse(item) | |
569 | ||
570 | # Clear tree | |
571 | def Clear(self): | |
0725108f RR |
572 | self.selection = None |
573 | self.UnselectAll() | |
d14a1e28 RD |
574 | self.DeleteAllItems() |
575 | # Add minimal structure | |
576 | if self.dom: self.dom.unlink() | |
577 | self.dom = MyDocument() | |
578 | self.dummyNode = self.dom.createComment('dummy node') | |
579 | # Create main node | |
580 | self.mainNode = self.dom.createElement('resource') | |
581 | self.dom.appendChild(self.mainNode) | |
582 | self.rootObj = xxxMainNode(self.dom) | |
583 | self.root = self.AddRoot('XML tree', self.rootImage, | |
29a41103 | 584 | data=wx.TreeItemData(self.rootObj)) |
d14a1e28 | 585 | self.SetItemHasChildren(self.root) |
34b29ae7 RR |
586 | self.testElem = self.dom.createElement('dummy') |
587 | self.mainNode.appendChild(self.testElem) | |
fdc1a8be | 588 | self.Expand(self.root) |
d14a1e28 RD |
589 | |
590 | # Clear old data and set new | |
591 | def SetData(self, dom): | |
0725108f RR |
592 | self.selection = None |
593 | self.UnselectAll() | |
d14a1e28 RD |
594 | self.DeleteAllItems() |
595 | # Add minimal structure | |
596 | if self.dom: self.dom.unlink() | |
597 | self.dom = dom | |
598 | self.dummyNode = self.dom.createComment('dummy node') | |
599 | # Find 'resource' child, add it's children | |
600 | self.mainNode = dom.documentElement | |
601 | self.rootObj = xxxMainNode(self.dom) | |
602 | self.root = self.AddRoot('XML tree', self.rootImage, | |
29a41103 | 603 | data=wx.TreeItemData(self.rootObj)) |
e5b889c9 | 604 | self.itemColour = self.GetItemTextColour(self.root) |
d14a1e28 RD |
605 | self.SetItemHasChildren(self.root) |
606 | nodes = self.mainNode.childNodes[:] | |
607 | for node in nodes: | |
608 | if IsObject(node): | |
609 | self.AddNode(self.root, None, node) | |
610 | else: | |
611 | self.mainNode.removeChild(node) | |
612 | node.unlink() | |
34b29ae7 RR |
613 | if self.mainNode.firstChild: |
614 | self.testElem = self.dom.createElement('dummy') | |
615 | self.mainNode.insertBefore(self.testElem, self.mainNode.firstChild) | |
616 | else: | |
617 | self.testElem = self.dom.createElement('dummy') | |
618 | self.mainNode.appendChild(self.testElem) | |
d14a1e28 | 619 | self.Expand(self.root) |
d14a1e28 RD |
620 | |
621 | # Add tree item for given parent item if node is DOM element node with | |
03319b65 | 622 | # object/object_ref tag. xxxParent is parent xxx object |
d14a1e28 RD |
623 | def AddNode(self, itemParent, xxxParent, node): |
624 | # Set item data to current node | |
625 | try: | |
626 | xxx = MakeXXXFromDOM(xxxParent, node) | |
627 | except: | |
628 | print 'ERROR: MakeXXXFromDom(%s, %s)' % (xxxParent, node) | |
629 | raise | |
630 | treeObj = xxx.treeObject() | |
631 | # Append tree item | |
632 | item = self.AppendItem(itemParent, treeObj.treeName(), | |
633 | image=treeObj.treeImage(), | |
29a41103 | 634 | data=wx.TreeItemData(xxx)) |
b372319f RR |
635 | # Different color for comments and references |
636 | if xxx.className == 'comment': | |
e5b889c9 | 637 | self.SetItemTextColour(item, COLOUR_COMMENT) |
b372319f RR |
638 | self.SetItemFont(item, self.fontComment) |
639 | elif treeObj.ref: | |
e5b889c9 | 640 | self.SetItemTextColour(item, COLOUR_REF) |
75aa1946 | 641 | elif treeObj.hasStyle and treeObj.params.get('hidden', False): |
e5b889c9 | 642 | self.SetItemTextColour(item, COLOUR_HIDDEN) |
d14a1e28 RD |
643 | # Try to find children objects |
644 | if treeObj.hasChildren: | |
b372319f | 645 | nodes = treeObj.node.childNodes[:] |
d14a1e28 RD |
646 | for n in nodes: |
647 | if IsObject(n): | |
648 | self.AddNode(item, treeObj, n) | |
649 | elif n.nodeType != minidom.Node.ELEMENT_NODE: | |
b372319f | 650 | treeObj.node.removeChild(n) |
d14a1e28 RD |
651 | n.unlink() |
652 | ||
653 | # Insert new item at specific position | |
654 | def InsertNode(self, itemParent, parent, elem, nextItem): | |
655 | # Insert in XML tree and wxWin | |
656 | xxx = MakeXXXFromDOM(parent, elem) | |
657 | # If nextItem is None, we append to parent, otherwise insert before it | |
658 | if nextItem.IsOk(): | |
b372319f RR |
659 | node = self.GetPyData(nextItem).node |
660 | parent.node.insertBefore(elem, node) | |
d14a1e28 RD |
661 | # Inserting before is difficult, se we insert after or first child |
662 | index = self.ItemIndex(nextItem) | |
663 | newItem = self.InsertItemBefore(itemParent, index, | |
664 | xxx.treeName(), image=xxx.treeImage()) | |
665 | self.SetPyData(newItem, xxx) | |
666 | else: | |
b372319f | 667 | parent.node.appendChild(elem) |
d14a1e28 | 668 | newItem = self.AppendItem(itemParent, xxx.treeName(), image=xxx.treeImage(), |
29a41103 | 669 | data=wx.TreeItemData(xxx)) |
b372319f RR |
670 | treeObj = xxx.treeObject() |
671 | # Different color for references and comments | |
672 | if xxx.className == 'comment': | |
e5b889c9 | 673 | self.SetItemTextColour(newItem, COLOUR_COMMENT) |
fe295b0d | 674 | self.SetItemFont(newItem, self.fontComment) |
b372319f | 675 | elif treeObj.ref: |
e5b889c9 | 676 | self.SetItemTextColour(newItem, COLOUR_REF) |
b372319f | 677 | elif treeObj.hasStyle and treeObj.params.get('hidden', False): |
e5b889c9 | 678 | self.SetItemTextColour(newItem, COLOUR_HIDDEN) |
d14a1e28 RD |
679 | # Add children items |
680 | if xxx.hasChildren: | |
681 | treeObj = xxx.treeObject() | |
b372319f | 682 | for n in treeObj.node.childNodes: |
d14a1e28 RD |
683 | if IsObject(n): |
684 | self.AddNode(newItem, treeObj, n) | |
685 | return newItem | |
686 | ||
687 | # Remove leaf of tree, return it's data object | |
688 | def RemoveLeaf(self, leaf): | |
689 | xxx = self.GetPyData(leaf) | |
b372319f | 690 | node = xxx.node |
d14a1e28 RD |
691 | parent = node.parentNode |
692 | parent.removeChild(node) | |
693 | self.Delete(leaf) | |
694 | # Reset selection object | |
695 | self.selection = None | |
696 | return node | |
538a0c0d | 697 | |
d14a1e28 | 698 | # Find position relative to the top-level window |
64b9ac75 | 699 | def FindNodePos(self, item, obj=None): |
d14a1e28 | 700 | # Root at (0,0) |
29a41103 | 701 | if item == g.testWin.item: return wx.Point(0, 0) |
d14a1e28 | 702 | itemParent = self.GetItemParent(item) |
306b6fe9 | 703 | # Select book page |
64b9ac75 | 704 | if not obj: obj = self.FindNodeObject(item) |
306b6fe9 RR |
705 | if self.GetPyData(itemParent).treeObject().__class__ in \ |
706 | [xxxNotebook, xxxChoicebook, xxxListbook]: | |
707 | book = self.FindNodeObject(itemParent) | |
d14a1e28 | 708 | # Find position |
306b6fe9 RR |
709 | for i in range(book.GetPageCount()): |
710 | if book.GetPage(i) == obj: | |
711 | if book.GetSelection() != i: | |
712 | book.SetSelection(i) | |
fd919451 RR |
713 | # Remove highlight - otherwise highlight window won't be visible |
714 | if g.testWin.highLight: | |
715 | g.testWin.highLight.Remove() | |
d14a1e28 | 716 | break |
538a0c0d | 717 | # For sizers and notebooks we must select the first window-like parent |
d14a1e28 | 718 | winParent = itemParent |
e2dc45d8 | 719 | while self.GetPyData(winParent).isSizer: |
d14a1e28 | 720 | winParent = self.GetItemParent(winParent) |
e2dc45d8 RR |
721 | # Notebook children are layed out in a little strange way |
722 | # wxGTK places NB panels relative to the NB parent | |
723 | if wx.Platform == '__WXGTK__': | |
724 | if self.GetPyData(itemParent).treeObject().__class__ == xxxNotebook: | |
725 | winParent = self.GetItemParent(winParent) | |
538a0c0d | 726 | parentPos = self.FindNodePos(winParent) |
d14a1e28 | 727 | pos = obj.GetPosition() |
e2dc45d8 | 728 | # Position (-1,-1) is really (0,0) |
d14a1e28 RD |
729 | if pos == (-1,-1): pos = (0,0) |
730 | return parentPos + pos | |
731 | ||
732 | # Find window (or sizer) corresponding to a tree item. | |
733 | def FindNodeObject(self, item): | |
734 | testWin = g.testWin | |
735 | # If top-level, return testWin (or panel its panel) | |
736 | if item == testWin.item: return testWin.panel | |
737 | itemParent = self.GetItemParent(item) | |
738 | xxx = self.GetPyData(item).treeObject() | |
739 | parentWin = self.FindNodeObject(itemParent) | |
740 | # Top-level sizer? return window's sizer | |
29a41103 | 741 | if xxx.isSizer and isinstance(parentWin, wx.Window): |
d14a1e28 | 742 | return parentWin.GetSizer() |
0cbb7d59 | 743 | elif xxx.__class__ in [xxxMenu, xxxMenuItem, xxxSeparator]: return None |
6165053b RR |
744 | elif xxx.__class__ in [xxxToolBar, xxxMenuBar]: |
745 | # If it's the main toolbar or menubar, we can't really select it | |
c0026696 | 746 | if xxx.parent.__class__ == xxxFrame: return None |
837db46d | 747 | elif isinstance(xxx.parent, xxxToolBar): |
c0026696 | 748 | # Select complete toolbar |
03319b65 | 749 | return parentWin |
64b9ac75 RR |
750 | elif isinstance(xxx.parent, xxxStdDialogButtonSizer): |
751 | # This sizer returns non-existing children | |
752 | for ch in parentWin.GetChildren(): | |
753 | if ch.GetWindow() and ch.GetWindow().GetName() == xxx.name: | |
754 | return ch.GetWindow() | |
755 | return None | |
306b6fe9 RR |
756 | elif xxx.parent.__class__ in [xxxChoicebook, xxxListbook]: |
757 | # First window is controld | |
758 | return parentWin.GetChildren()[self.ItemIndex(item)+1] | |
d14a1e28 | 759 | # Otherwise get parent's object and it's child |
0cbb7d59 | 760 | child = parentWin.GetChildren()[self.WindowIndex(item)] |
d14a1e28 RD |
761 | # Return window or sizer for sizer items |
762 | if child.GetClassName() == 'wxSizerItem': | |
763 | if child.IsWindow(): child = child.GetWindow() | |
764 | elif child.IsSizer(): | |
765 | child = child.GetSizer() | |
d14a1e28 RD |
766 | return child |
767 | ||
768 | def OnSelChanged(self, evt): | |
83173c7a | 769 | if self.selectionChanging: return |
2458faeb | 770 | self.selectionChanging = True |
83173c7a RR |
771 | self.UnselectAll() |
772 | self.SelectItem(evt.GetItem()) | |
2458faeb | 773 | self.selectionChanging = False |
e5b889c9 | 774 | g.frame.SetStatusText('') |
fd919451 RR |
775 | |
776 | def ChangeSelection(self, item): | |
d14a1e28 RD |
777 | # Apply changes |
778 | # !!! problem with wxGTK - GetOldItem is Ok if nothing selected | |
779 | #oldItem = evt.GetOldItem() | |
780 | status = '' | |
781 | oldItem = self.selection | |
13542f49 RD |
782 | # use GetItemParent as a way to determine if the itemId is still valid |
783 | if oldItem and self.GetItemParent(oldItem): | |
d14a1e28 RD |
784 | xxx = self.GetPyData(oldItem) |
785 | # If some data was modified, apply changes | |
786 | if g.panel.IsModified(): | |
787 | self.Apply(xxx, oldItem) | |
d14a1e28 RD |
788 | if g.testWin: |
789 | if g.testWin.highLight: | |
790 | g.testWin.highLight.Remove() | |
791 | self.needUpdate = True | |
792 | status = 'Changes were applied' | |
e5b889c9 | 793 | if status: g.frame.SetStatusText(status) |
d14a1e28 | 794 | # Generate view |
fd919451 | 795 | self.selection = item |
d14a1e28 RD |
796 | if not self.selection.IsOk(): |
797 | self.selection = None | |
798 | return | |
799 | xxx = self.GetPyData(self.selection) | |
800 | # Update panel | |
801 | g.panel.SetData(xxx) | |
802 | # Update tools | |
803 | g.tools.UpdateUI() | |
d6922577 | 804 | # Highlighting is done in OnIdle |
d14a1e28 RD |
805 | self.pendingHighLight = self.selection |
806 | ||
807 | # Check if item is in testWin subtree | |
808 | def IsHighlatable(self, item): | |
809 | if item == g.testWin.item: return False | |
810 | while item != self.root: | |
811 | item = self.GetItemParent(item) | |
75aa1946 RR |
812 | if item == g.testWin.item: |
813 | return True | |
d14a1e28 RD |
814 | return False |
815 | ||
816 | # Highlight selected item | |
817 | def HighLight(self, item): | |
818 | self.pendingHighLight = None | |
819 | # Can highlight only with some top-level windows | |
820 | if not g.testWin or self.GetPyData(g.testWin.item).treeObject().__class__ \ | |
821 | not in [xxxDialog, xxxPanel, xxxFrame]: | |
822 | return | |
823 | # If a control from another window is selected, remove highlight | |
824 | if not self.IsHighlatable(item): | |
825 | if g.testWin.highLight: g.testWin.highLight.Remove() | |
826 | return | |
827 | # Get window/sizer object | |
64b9ac75 | 828 | obj = self.FindNodeObject(item) |
75aa1946 RR |
829 | xxx = self.GetPyData(item).treeObject() |
830 | # Remove existing HL if item not found or is hidden | |
831 | if not obj or xxx.hasStyle and xxx.params.get('hidden', False): | |
0cbb7d59 RR |
832 | if g.testWin.highLight: g.testWin.highLight.Remove() |
833 | return | |
8c64c153 | 834 | pos = self.FindNodePos(item, obj) |
d14a1e28 RD |
835 | size = obj.GetSize() |
836 | # Highlight | |
d6922577 | 837 | # Negative positions are not working quite well |
8c64c153 RR |
838 | # If highlight object has the same size SetDimension does not repaint it |
839 | # so we must remove the old HL window | |
e5b889c9 RR |
840 | g.testWin.highLight = updateHL(g.testWin.highLight, HighLightBox, pos, size) |
841 | g.testWin.highLight.item = item | |
d14a1e28 RD |
842 | |
843 | def ShowTestWindow(self, item): | |
844 | xxx = self.GetPyData(item) | |
845 | if g.panel.IsModified(): | |
846 | self.Apply(xxx, item) # apply changes | |
306b6fe9 RR |
847 | availableViews = ['wxFrame', 'wxPanel', 'wxDialog', |
848 | 'wxMenuBar', 'wxToolBar', 'wxWizard', | |
849 | 'wxWizardPageSimple'] | |
850 | originalItem = item | |
851 | # Walk up the tree until we find an item that has a view | |
852 | while item and self.GetPyData(item).treeObject().className not in availableViews: | |
853 | item = self.GetItemParent(item) | |
854 | if not item or not item.IsOk(): | |
29a41103 | 855 | wx.LogMessage('No view for this element (yet)') |
d14a1e28 RD |
856 | return |
857 | # Show item in bold | |
858 | if g.testWin: # Reset old | |
e2dc45d8 | 859 | self.UnselectAll() |
d14a1e28 | 860 | self.SetItemBold(g.testWin.item, False) |
306b6fe9 | 861 | try: |
29a41103 | 862 | wx.BeginBusyCursor() |
306b6fe9 RR |
863 | self.CreateTestWin(item) |
864 | finally: | |
29a41103 | 865 | wx.EndBusyCursor() |
d6922577 | 866 | # Maybe an error occurred, so we need to test |
306b6fe9 RR |
867 | if g.testWin: |
868 | self.SetItemBold(g.testWin.item) | |
869 | # Select original item | |
870 | self.ChangeSelection(originalItem) | |
d14a1e28 RD |
871 | |
872 | # Double-click on Linux | |
873 | def OnItemActivated(self, evt): | |
874 | if evt.GetItem() != self.root: | |
875 | self.ShowTestWindow(evt.GetItem()) | |
876 | ||
877 | # Double-click on Windows | |
878 | def OnDClick(self, evt): | |
879 | item, flags = self.HitTest(evt.GetPosition()) | |
29a41103 | 880 | if flags in [wx.TREE_HITTEST_ONITEMBUTTON, wx.TREE_HITTEST_ONITEMLABEL]: |
d14a1e28 RD |
881 | if item != self.root: self.ShowTestWindow(item) |
882 | else: | |
883 | evt.Skip() | |
884 | ||
885 | def OnItemExpandedCollapsed(self, evt): | |
886 | # Update tool palette | |
887 | g.tools.UpdateUI() | |
888 | evt.Skip() | |
889 | ||
890 | # (re)create test window | |
891 | def CreateTestWin(self, item): | |
892 | testWin = g.testWin | |
893 | # Create a window with this resource | |
894 | xxx = self.GetPyData(item).treeObject() | |
d14a1e28 RD |
895 | # Close old window, remember where it was |
896 | highLight = None | |
897 | if testWin: | |
898 | pos = testWin.GetPosition() | |
899 | if item == testWin.item: | |
900 | # Remember highlight if same top-level window | |
901 | if testWin.highLight: | |
902 | highLight = testWin.highLight.item | |
903 | if xxx.className == 'wxPanel': | |
904 | if testWin.highLight: | |
905 | testWin.pendingHighLight = highLight | |
906 | testWin.highLight.Remove() | |
907 | testWin.panel.Destroy() | |
908 | testWin.panel = None | |
909 | else: | |
910 | testWin.Destroy() | |
911 | testWin = g.testWin = None | |
912 | else: | |
913 | testWin.Destroy() | |
914 | testWin = g.testWin = None | |
915 | else: | |
916 | pos = g.testWinPos | |
917 | # Save in memory FS | |
918 | memFile = MemoryFile('xxx.xrc') | |
03319b65 | 919 | # Create memory XML file |
b372319f | 920 | elem = xxx.node.cloneNode(True) |
d14a1e28 RD |
921 | if not xxx.name: |
922 | name = 'noname' | |
923 | else: | |
924 | name = xxx.name | |
925 | elem.setAttribute('name', STD_NAME) | |
34b29ae7 RR |
926 | oldTestNode = self.testElem |
927 | self.testElem = elem | |
928 | self.mainNode.replaceChild(elem, oldTestNode) | |
929 | oldTestNode.unlink() | |
64bce500 RR |
930 | # Replace wizard page class temporarily |
931 | if xxx.__class__ in [xxxWizardPage, xxxWizardPageSimple]: | |
932 | oldCl = elem.getAttribute('class') | |
933 | elem.setAttribute('class', 'wxPanel') | |
d14a1e28 | 934 | parent = elem.parentNode |
03319b65 RR |
935 | encd = self.rootObj.params['encoding'].value() |
936 | if not encd: encd = None | |
34b29ae7 RR |
937 | try: |
938 | self.dom.writexml(memFile, encoding=encd) | |
939 | except: | |
940 | inf = sys.exc_info() | |
29a41103 RD |
941 | wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) |
942 | wx.LogError('Error writing temporary file') | |
d14a1e28 | 943 | memFile.close() # write to wxMemoryFS |
29a41103 | 944 | xmlFlags = xrc.XRC_NO_SUBCLASSING |
d14a1e28 | 945 | # Use translations if encoding is not specified |
9a69d0aa | 946 | if not g.currentEncoding: |
29a41103 RD |
947 | xmlFlags != xrc.XRC_USE_LOCALE |
948 | res = xrc.XmlResource('', xmlFlags) | |
e5b889c9 | 949 | res.InitAllHandlers() |
00d15346 RR |
950 | xrc.XmlResource.Set(res) # set as global |
951 | # Register handlers | |
c0d5ae74 | 952 | addHandlers() |
a6166197 | 953 | # Same module list |
d14a1e28 | 954 | res.Load('memory:xxx.xrc') |
a4c013b2 RR |
955 | try: |
956 | if xxx.__class__ == xxxFrame: | |
957 | # Frame can't have many children, | |
958 | # but it's first child possibly can... | |
959 | # child = self.GetFirstChild(item)[0] | |
960 | # if child.IsOk() and self.GetPyData(child).__class__ == xxxPanel: | |
961 | # # Clean-up before recursive call or error | |
29a41103 RD |
962 | # wx.MemoryFSHandler.RemoveFile('xxx.xrc') |
963 | # wx.EndBusyCursor() | |
a4c013b2 RR |
964 | # self.CreateTestWin(child) |
965 | # return | |
966 | # This currently works under GTK, but not under MSW | |
29a41103 | 967 | testWin = g.testWin = wx.PreFrame() |
a4c013b2 RR |
968 | res.LoadOnFrame(testWin, g.frame, STD_NAME) |
969 | # Create status bar | |
970 | testWin.panel = testWin | |
306b6fe9 | 971 | #testWin.CreateStatusBar() |
a4c013b2 | 972 | testWin.SetClientSize(testWin.GetBestSize()) |
a4c013b2 RR |
973 | testWin.SetPosition(pos) |
974 | testWin.Show(True) | |
975 | elif xxx.__class__ == xxxPanel: | |
976 | # Create new frame | |
977 | if not testWin: | |
29a41103 | 978 | testWin = g.testWin = wx.Frame(g.frame, -1, 'Panel: ' + name, |
a4c013b2 RR |
979 | pos=pos, name=STD_NAME) |
980 | testWin.panel = res.LoadPanel(testWin, STD_NAME) | |
981 | testWin.SetClientSize(testWin.GetBestSize()) | |
982 | testWin.Show(True) | |
983 | elif xxx.__class__ == xxxDialog: | |
d84cc8c1 | 984 | testWin = g.testWin = res.LoadDialog(g.frame, STD_NAME) |
a4c013b2 RR |
985 | testWin.panel = testWin |
986 | testWin.Layout() | |
987 | testWin.SetPosition(pos) | |
988 | testWin.Show(True) | |
29a41103 RD |
989 | # Dialog's default code does not produce wx.EVT_CLOSE |
990 | wx.EVT_BUTTON(testWin, wx.ID_OK, self.OnCloseTestWin) | |
991 | wx.EVT_BUTTON(testWin, wx.ID_CANCEL, self.OnCloseTestWin) | |
64bce500 | 992 | elif xxx.__class__ == xxxWizard: |
29a41103 | 993 | wiz = wx.wizard.PreWizard() |
d84cc8c1 | 994 | res.LoadOnObject(wiz, g.frame, STD_NAME, 'wxWizard') |
64bce500 RR |
995 | # Find first page (don't know better way) |
996 | firstPage = None | |
997 | for w in wiz.GetChildren(): | |
29a41103 | 998 | if isinstance(w, wx.wizard.WizardPage): |
64bce500 RR |
999 | firstPage = w |
1000 | break | |
1001 | if not firstPage: | |
29a41103 | 1002 | wx.LogError('Wizard is empty') |
64bce500 RR |
1003 | else: |
1004 | # Wizard should be modal | |
1005 | self.SetItemBold(item) | |
1006 | wiz.RunWizard(w) | |
1007 | self.SetItemBold(item, False) | |
1008 | wiz.Destroy() | |
1009 | elif xxx.__class__ in [xxxWizardPage, xxxWizardPageSimple]: | |
1010 | # Create new frame | |
1011 | if not testWin: | |
29a41103 | 1012 | testWin = g.testWin = wx.Frame(g.frame, -1, 'Wizard page: ' + name, |
64bce500 | 1013 | pos=pos, name=STD_NAME) |
29a41103 | 1014 | testWin.panel = wx.PrePanel() |
64bce500 RR |
1015 | res.LoadOnObject(testWin.panel, testWin, STD_NAME, 'wxPanel') |
1016 | testWin.SetClientSize(testWin.GetBestSize()) | |
1017 | testWin.Show(True) | |
a4c013b2 | 1018 | elif xxx.__class__ == xxxMenuBar: |
29a41103 | 1019 | testWin = g.testWin = wx.Frame(g.frame, -1, 'MenuBar: ' + name, |
a4c013b2 RR |
1020 | pos=pos, name=STD_NAME) |
1021 | testWin.panel = None | |
1022 | # Set status bar to display help | |
1023 | testWin.CreateStatusBar() | |
1024 | testWin.menuBar = res.LoadMenuBar(STD_NAME) | |
1025 | testWin.SetMenuBar(testWin.menuBar) | |
1026 | testWin.Show(True) | |
1027 | elif xxx.__class__ == xxxToolBar: | |
29a41103 | 1028 | testWin = g.testWin = wx.Frame(g.frame, -1, 'ToolBar: ' + name, |
d14a1e28 | 1029 | pos=pos, name=STD_NAME) |
a4c013b2 RR |
1030 | testWin.panel = None |
1031 | # Set status bar to display help | |
1032 | testWin.CreateStatusBar() | |
1033 | testWin.toolBar = res.LoadToolBar(testWin, STD_NAME) | |
1034 | testWin.SetToolBar(testWin.toolBar) | |
1035 | testWin.Show(True) | |
538a0c0d | 1036 | # Catch some events, set highlight |
64bce500 RR |
1037 | if testWin: |
1038 | testWin.item = item | |
29a41103 | 1039 | wx.EVT_CLOSE(testWin, self.OnCloseTestWin) |
538a0c0d | 1040 | wx.EVT_SIZE(testWin, self.OnSizeTestWin) |
e5b889c9 RR |
1041 | # Add drop target |
1042 | testWin.SetDropTarget(DropTarget()) | |
1043 | # Reset highlights | |
1044 | testWin.highLight = testWin.highLightDT = None | |
64bce500 RR |
1045 | if highLight and not self.pendingHighLight: |
1046 | self.HighLight(highLight) | |
a4c013b2 RR |
1047 | except: |
1048 | if g.testWin: | |
1049 | self.SetItemBold(item, False) | |
1050 | g.testWinPos = g.testWin.GetPosition() | |
1051 | g.testWin.Destroy() | |
1052 | g.testWin = None | |
1053 | inf = sys.exc_info() | |
29a41103 RD |
1054 | wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) |
1055 | wx.LogError('Error loading resource') | |
c0d5ae74 RR |
1056 | # Cleanup |
1057 | res.Unload('xxx.xrc') | |
1058 | xrc.XmlResource.Set(None) | |
29a41103 | 1059 | wx.MemoryFSHandler.RemoveFile('xxx.xrc') |
d14a1e28 | 1060 | |
64bce500 RR |
1061 | def CloseTestWindow(self): |
1062 | if not g.testWin: return | |
d14a1e28 | 1063 | self.SetItemBold(g.testWin.item, False) |
016f67ba | 1064 | g.frame.tb.ToggleTool(g.frame.ID_TOOL_LOCATE, False) |
d14a1e28 RD |
1065 | g.testWinPos = g.testWin.GetPosition() |
1066 | g.testWin.Destroy() | |
1067 | g.testWin = None | |
1068 | ||
64bce500 RR |
1069 | def OnCloseTestWin(self, evt): |
1070 | self.CloseTestWindow() | |
1071 | ||
538a0c0d RR |
1072 | def OnSizeTestWin(self, evt): |
1073 | if g.testWin.highLight: | |
1074 | self.HighLight(g.testWin.highLight.item) | |
1075 | evt.Skip() | |
1076 | ||
0cbb7d59 RR |
1077 | # Return index in parent, for real window children |
1078 | def WindowIndex(self, item): | |
1079 | n = 0 # index of sibling | |
1080 | prev = self.GetPrevSibling(item) | |
1081 | while prev.IsOk(): | |
1082 | # MenuBar is not a child | |
1083 | if not isinstance(self.GetPyData(prev), xxxMenuBar): | |
1084 | n += 1 | |
1085 | prev = self.GetPrevSibling(prev) | |
1086 | return n | |
1087 | ||
d14a1e28 RD |
1088 | # Return item index in parent |
1089 | def ItemIndex(self, item): | |
1090 | n = 0 # index of sibling | |
1091 | prev = self.GetPrevSibling(item) | |
1092 | while prev.IsOk(): | |
1093 | prev = self.GetPrevSibling(prev) | |
1094 | n += 1 | |
1095 | return n | |
1096 | ||
1097 | # Full tree index of an item - list of positions | |
1098 | def ItemFullIndex(self, item): | |
1099 | if not item.IsOk(): return None | |
1100 | l = [] | |
1101 | while item != self.root: | |
1102 | l.insert(0, self.ItemIndex(item)) | |
1103 | item = self.GetItemParent(item) | |
1104 | return l | |
1105 | # Get item position from full index | |
1106 | def ItemAtFullIndex(self, index): | |
29a41103 | 1107 | if index is None: return wx.TreeItemId() |
d14a1e28 RD |
1108 | item = self.root |
1109 | for i in index: | |
fdc1a8be | 1110 | item = self.GetFirstChild(item)[0] |
d14a1e28 RD |
1111 | for k in range(i): item = self.GetNextSibling(item) |
1112 | return item | |
1113 | ||
1114 | # True if next item should be inserted after current (vs. appended to it) | |
1115 | def NeedInsert(self, item): | |
1116 | xxx = self.GetPyData(item) | |
1117 | if item == self.root: return False # root item | |
1118 | if xxx.hasChildren and not self.GetChildrenCount(item, False): | |
1119 | return False | |
1120 | return not (self.IsExpanded(item) and self.GetChildrenCount(item, False)) | |
1121 | ||
83173c7a RR |
1122 | # Override to use like single-selection tree |
1123 | def GetSelection(self): | |
a24d7726 | 1124 | return self.selection |
83173c7a RR |
1125 | def SelectItem(self, item): |
1126 | self.UnselectAll() | |
1127 | self.ChangeSelection(item) | |
29a41103 | 1128 | wx.TreeCtrl.SelectItem(self, item) |
83173c7a | 1129 | |
d14a1e28 RD |
1130 | # Pull-down |
1131 | def OnRightDown(self, evt): | |
1132 | pullDownMenu = g.pullDownMenu | |
1133 | # select this item | |
1134 | pt = evt.GetPosition(); | |
1135 | item, flags = self.HitTest(pt) | |
29a41103 | 1136 | if item.Ok() and flags & wx.TREE_HITTEST_ONITEM: |
d14a1e28 RD |
1137 | self.SelectItem(item) |
1138 | ||
1139 | # Setup menu | |
29a41103 | 1140 | menu = wx.Menu() |
d14a1e28 RD |
1141 | |
1142 | item = self.selection | |
1143 | if not item: | |
1144 | menu.Append(g.pullDownMenu.ID_EXPAND, 'Expand', 'Expand tree') | |
1145 | menu.Append(g.pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse tree') | |
1146 | else: | |
1147 | # self.ctrl = evt.ControlDown() # save Ctrl state | |
1148 | # self.shift = evt.ShiftDown() # and Shift too | |
29a41103 | 1149 | m = wx.Menu() # create menu |
d14a1e28 RD |
1150 | if self.ctrl: |
1151 | needInsert = True | |
1152 | else: | |
1153 | needInsert = self.NeedInsert(item) | |
1154 | if item == self.root or needInsert and self.GetItemParent(item) == self.root: | |
1155 | SetMenu(m, pullDownMenu.topLevel) | |
03319b65 RR |
1156 | m.AppendSeparator() |
1157 | m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node') | |
b372319f | 1158 | m.Append(ID_NEW.COMMENT, 'comment', 'Create comment node') |
d14a1e28 RD |
1159 | else: |
1160 | xxx = self.GetPyData(item).treeObject() | |
1161 | # Check parent for possible child nodes if inserting sibling | |
1162 | if needInsert: xxx = xxx.parent | |
1163 | if xxx.__class__ == xxxMenuBar: | |
1164 | m.Append(ID_NEW.MENU, 'Menu', 'Create menu') | |
1165 | elif xxx.__class__ in [xxxToolBar, xxxTool] or \ | |
1166 | xxx.__class__ == xxxSeparator and xxx.parent.__class__ == xxxToolBar: | |
1167 | SetMenu(m, pullDownMenu.toolBarControls) | |
1168 | elif xxx.__class__ in [xxxMenu, xxxMenuItem]: | |
1169 | SetMenu(m, pullDownMenu.menuControls) | |
64b9ac75 RR |
1170 | elif xxx.__class__ == xxxStdDialogButtonSizer: |
1171 | SetMenu(m, pullDownMenu.stdButtons) | |
d14a1e28 RD |
1172 | else: |
1173 | SetMenu(m, pullDownMenu.controls) | |
306b6fe9 | 1174 | if xxx.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook]: |
d14a1e28 RD |
1175 | m.Enable(m.FindItem('sizer'), False) |
1176 | elif not (xxx.isSizer or xxx.parent and xxx.parent.isSizer): | |
1177 | m.Enable(ID_NEW.SPACER, False) | |
f65bb0f8 RD |
1178 | if xxx.__class__ is not xxxFrame: |
1179 | m.Enable(ID_NEW.MENU_BAR, False) | |
c0d5ae74 | 1180 | # Add custom controls menu |
8c64c153 RR |
1181 | if len(pullDownMenu.custom) > 2: |
1182 | SetMenu(m, [pullDownMenu.custom]) | |
a6166197 RR |
1183 | m.AppendSeparator() |
1184 | m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node') | |
1185 | m.Append(ID_NEW.COMMENT, 'comment', 'Create comment node') | |
d14a1e28 RD |
1186 | # Select correct label for create menu |
1187 | if not needInsert: | |
1188 | if self.shift: | |
29a41103 | 1189 | menu.AppendMenu(wx.NewId(), 'Insert Child', m, |
d14a1e28 RD |
1190 | 'Create child object as the first child') |
1191 | else: | |
29a41103 | 1192 | menu.AppendMenu(wx.NewId(), 'Append Child', m, |
d14a1e28 RD |
1193 | 'Create child object as the last child') |
1194 | else: | |
1195 | if self.shift: | |
29a41103 | 1196 | menu.AppendMenu(wx.NewId(), 'Create Sibling', m, |
d14a1e28 RD |
1197 | 'Create sibling before selected object') |
1198 | else: | |
29a41103 | 1199 | menu.AppendMenu(wx.NewId(), 'Create Sibling', m, |
d14a1e28 RD |
1200 | 'Create sibling after selected object') |
1201 | # Build replace menu | |
1202 | if item != self.root: | |
1203 | xxx = self.GetPyData(item).treeObject() | |
29a41103 | 1204 | m = wx.Menu() # create replace menu |
d14a1e28 RD |
1205 | if xxx.__class__ == xxxMenuBar: |
1206 | m.Append(1000 + ID_NEW.MENU, 'Menu', 'Create menu') | |
1207 | elif xxx.__class__ in [xxxMenu, xxxMenuItem]: | |
64b9ac75 | 1208 | SetMenu(m, pullDownMenu.menuControls, shift=True) |
d14a1e28 RD |
1209 | elif xxx.__class__ == xxxToolBar and \ |
1210 | self.GetItemParent(item) == self.root: | |
64b9ac75 | 1211 | SetMenu(m, [], shift=True) |
d14a1e28 | 1212 | elif xxx.__class__ in [xxxFrame, xxxDialog, xxxPanel]: |
64b9ac75 | 1213 | SetMenu(m, [ |
d14a1e28 RD |
1214 | (ID_NEW.PANEL, 'Panel', 'Create panel'), |
1215 | (ID_NEW.DIALOG, 'Dialog', 'Create dialog'), | |
64b9ac75 | 1216 | (ID_NEW.FRAME, 'Frame', 'Create frame')], shift=True) |
75aa1946 | 1217 | elif xxx.isSizer and self.ItemHasChildren(item): |
64b9ac75 | 1218 | SetMenu(m, pullDownMenu.sizers, shift=True) |
d14a1e28 | 1219 | else: |
64b9ac75 | 1220 | SetMenu(m, pullDownMenu.controls, shift=True) |
b372319f RR |
1221 | if xxx.isElement: |
1222 | id = wx.NewId() | |
1223 | menu.AppendMenu(id, 'Replace With', m) | |
1224 | if not m.GetMenuItemCount(): menu.Enable(id, False) | |
1225 | menu.Append(pullDownMenu.ID_SUBCLASS, 'Subclass...', | |
1226 | 'Set "subclass" property') | |
d14a1e28 RD |
1227 | menu.AppendSeparator() |
1228 | # Not using standart IDs because we don't want to show shortcuts | |
29a41103 RD |
1229 | menu.Append(wx.ID_CUT, 'Cut', 'Cut to the clipboard') |
1230 | menu.Append(wx.ID_COPY, 'Copy', 'Copy to the clipboard') | |
d14a1e28 RD |
1231 | if self.ctrl and item != self.root: |
1232 | menu.Append(pullDownMenu.ID_PASTE_SIBLING, 'Paste Sibling', | |
1233 | 'Paste from the clipboard as a sibling') | |
1234 | else: | |
29a41103 | 1235 | menu.Append(wx.ID_PASTE, 'Paste', 'Paste from the clipboard') |
d14a1e28 RD |
1236 | menu.Append(pullDownMenu.ID_DELETE, |
1237 | 'Delete', 'Delete object') | |
1238 | if self.ItemHasChildren(item): | |
1239 | menu.AppendSeparator() | |
1240 | menu.Append(pullDownMenu.ID_EXPAND, 'Expand', 'Expand subtree') | |
1241 | menu.Append(pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse subtree') | |
1242 | self.PopupMenu(menu, evt.GetPosition()) | |
1243 | menu.Destroy() | |
1244 | ||
c37cba89 RR |
1245 | # Redefine to force the update of font dimentions on wxGTK |
1246 | if wx.Platform == '__WXGTK__': | |
1247 | def SetItemBold(self, item, state=True): | |
1248 | wx.TreeCtrl.SetItemBold(self, item, state) | |
1249 | self.SetIndent(self.GetIndent()) | |
75aa1946 | 1250 | |
d14a1e28 RD |
1251 | # Apply changes |
1252 | def Apply(self, xxx, item): | |
1253 | g.panel.Apply() | |
1254 | # Update tree view | |
1255 | xxx = xxx.treeObject() | |
1256 | if xxx.hasName and self.GetItemText(item) != xxx.name: | |
1257 | self.SetItemText(item, xxx.treeName()) | |
1258 | # Item width may have changed | |
1259 | # !!! Tric to update tree width (wxGTK, ??) | |
1260 | self.SetIndent(self.GetIndent()) | |
b372319f RR |
1261 | elif xxx.className == 'comment': |
1262 | self.SetItemText(item, xxx.treeName()) | |
d14a1e28 RD |
1263 | # Change tree icon for sizers |
1264 | if isinstance(xxx, xxxBoxSizer): | |
1265 | self.SetItemImage(item, xxx.treeImage()) | |
1266 | # Set global modified state | |
03319b65 | 1267 | g.frame.SetModified() |
1fded56b | 1268 | |
fe295b0d RR |
1269 | def OnBeginLabelEdit(self, evt): |
1270 | xxx = self.GetPyData(evt.GetItem()) | |
1271 | if xxx.isElement: | |
1272 | evt.Veto() | |
1273 | else: | |
1274 | evt.Skip() | |
1275 | ||
1276 | def OnEndLabelEdit(self, evt): | |
1277 | xxx = self.GetPyData(evt.GetItem()) | |
1278 | node = xxx.node | |
1279 | if not xxx.isElement: | |
1280 | node.data = evt.GetLabel() | |
1281 | g.panel.SetData(xxx) | |
1282 | evt.Skip() | |
e5b889c9 RR |
1283 | |
1284 | ################################################################################ | |
1285 | ||
1286 | # DragAndDrop | |
1287 | ||
1288 | class DropTarget(wx.PyDropTarget): | |
1289 | def __init__(self): | |
1290 | self.do = MyDataObject() | |
1291 | wx.DropTarget.__init__(self, self.do) | |
1292 | ||
1293 | # Find best object for dropping | |
1294 | def WhereToDrop(self, x, y, d): | |
1295 | # Find object by position | |
1296 | obj = wx.FindWindowAtPoint(g.testWin.ClientToScreen((x,y))) | |
1297 | if not obj: | |
1298 | return wx.DragNone, () | |
1299 | item = g.frame.FindObject(g.testWin.item, obj) | |
1300 | if not item: | |
1301 | return wx.DragNone, () | |
1302 | xxx = g.tree.GetPyData(item).treeObject() | |
1303 | parentItem = None | |
1304 | # Check if window has a XRC sizer, then use it as parent | |
1305 | if obj.GetSizer(): | |
1306 | sizer = obj.GetSizer() | |
1307 | sizerItem = g.frame.FindObject(g.testWin.item, sizer) | |
1308 | if sizerItem: | |
1309 | parentItem = sizerItem | |
1310 | obj = sizer | |
1311 | item = wx.TreeItemId() | |
1312 | # if not sizer but can have children, it is parent with free placement | |
1313 | elif xxx.hasChildren: | |
1314 | parentItem = item | |
1315 | item = wx.TreeItemId() | |
1316 | # Otherwise, try to add to item's parent | |
1317 | if not parentItem: | |
1318 | parentItem = g.tree.GetItemParent(item) | |
1319 | obj = g.tree.FindNodeObject(parentItem) | |
1320 | parent = g.tree.GetPyData(parentItem).treeObject() | |
1321 | return d,(obj,parent,parentItem,item) | |
1322 | ||
1323 | # Drop | |
1324 | def OnData(self, x, y, d): | |
1325 | self.GetData() | |
1326 | id = int(self.do.GetDataHere()) | |
1327 | d,other = self.WhereToDrop(x, y, d) | |
1328 | if d != wx.DragNone: | |
1329 | obj,parent,parentItem,item = other | |
1330 | g.tree.selection = parentItem | |
1331 | xxx = g.frame.CreateXXX(parent, parentItem, item, id) | |
1332 | # Set coordinates if parent is not sizer | |
1333 | if not parent.isSizer: | |
1334 | xxx.set('pos', '%d,%d' % (x, y)) | |
1335 | g.panel.SetData(xxx) | |
1336 | g.frame.SetStatusText('Object created') | |
1337 | self.RemoveHL() | |
1338 | return d | |
1339 | ||
1340 | def OnDragOver(self, x, y, d): | |
1341 | d,other = self.WhereToDrop(x, y, d) | |
1342 | if d != wx.DragNone: | |
1343 | obj,parent,parentItem,item = other | |
1344 | pos, size = g.tree.FindNodePos(parentItem, obj), obj.GetSize() | |
1345 | # Change tree item colour | |
1346 | hl = g.testWin.highLightDT | |
1347 | if hl and hl.item and hl.item != parentItem: | |
1348 | g.tree.SetItemTextColour(hl.item, g.tree.itemColour) | |
1349 | g.testWin.highLightDT = updateHL(hl, HighLightDTBox, pos, size) | |
1350 | g.testWin.highLightDT.item = parentItem | |
1351 | g.tree.SetItemTextColour(parentItem, COLOUR_DT) | |
1352 | g.tree.EnsureVisible(parentItem) | |
1353 | g.frame.SetStatusText('Drop target: %s' % parent.treeName()) | |
1354 | else: | |
1355 | g.frame.SetStatusText('Inappropriate drop target') | |
1356 | self.RemoveHL() | |
1357 | return d | |
1358 | ||
1359 | def OnLeave(self): | |
1360 | self.RemoveHL() | |
1361 | ||
1362 | def RemoveHL(self): | |
1363 | hl = g.testWin.highLightDT | |
1364 | if hl: | |
1365 | if hl.item: g.tree.SetItemTextColour(hl.item, g.tree.itemColour) | |
1366 | hl.Remove() | |
1367 |