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