Package gui :: Module wizard
[hide private]
[frames] | no frames]

Source Code for Module gui.wizard

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2010-2012 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """Base class module for the wizard GUI elements.""" 
 24   
 25  # Python module imports. 
 26  import wx 
 27  from wx.lib import buttons, scrolledpanel 
 28   
 29  # relax module imports. 
 30  from data import Relax_data_store; ds = Relax_data_store() 
 31  from relax_errors import RelaxImplementError 
 32  from status import Status; status = Status() 
 33   
 34  # relax GUI module imports. 
 35  from gui.interpreter import Interpreter; interpreter = Interpreter() 
 36  from gui.filedialog import RelaxFileDialog 
 37  from gui.fonts import font 
 38  from gui.icons import relax_icons 
 39  from gui.misc import add_border, bitmap_setup, open_file, protected_exec 
 40  from gui import paths 
 41  from gui.string_conv import bool_to_gui, gui_to_int, gui_to_str, int_to_gui, str_to_gui 
 42   
 43   
44 -class Wiz_page(wx.Panel):
45 """The wizard pages to be placed inside the wizard. 46 47 To inherit from this class, you must minimally supply the add_contents() method. This method should build the specific GUI elements. The following methods are also designed to be overwritten: 48 49 - add_artwork(), this builds the left hand artwork section of the page. 50 - add_contents(), this builds the right hand section of the page. 51 - on_display(), this is executed when the page is displayed. 52 - on_display_post(), this is executed when the page is displayed, directly after the on_display method. 53 - on_execute(), this is executed when the wizard is terminated or the apply button is hit. 54 - on_next(), this is executed when moving to the next wizard page. 55 56 The following methods can be used by add_contents() to create standard GUI elements: 57 58 - chooser() 59 - combo_box() 60 - file_selection() 61 - input_field() 62 - text() 63 64 These are described in full detail in their docstrings. 65 """ 66 67 # Some class variables. 68 art_spacing = 20 69 divider = None 70 height_element = 27 71 image_path = paths.IMAGE_PATH + "relax.gif" 72 main_text = '' 73 setup_fail = False 74 size_button = (100, 33) 75 size_square_button = (33, 33) 76 title = '' 77
78 - def __init__(self, parent, height_desc=220):
79 """Set up the window. 80 81 @param parent: The parent GUI element. 82 @type parent: wx.object instance 83 @keyword height_desc: The height in pixels of the description part of the wizard. 84 @type height_desc: int or None 85 """ 86 87 # Store the args. 88 self.parent = parent 89 self.height_desc = height_desc 90 91 # Execute the base class method. 92 wx.Panel.__init__(self, parent, id=-1) 93 94 # Initilise some variables. 95 self.exec_status = False 96 97 # The wizard GUI element storage. 98 self._elements = {} 99 100 # Pack a sizer into the panel. 101 box_main = wx.BoxSizer(wx.HORIZONTAL) 102 self.SetSizer(box_main) 103 104 # Add the artwork. 105 self.add_artwork(box_main) 106 107 # The size of the image. 108 image_x, image_y = self.image.GetSize() 109 110 # Calculate the size of the main section, and the subdivisions. 111 self._main_size = parent._size_x - image_x - self.art_spacing - 2*parent._border 112 if self.divider: 113 self._div_left = self.divider 114 self._div_right = self._main_size - self.divider 115 else: 116 self._div_left = self._div_right = self._main_size / 2 117 118 # Add the main sizer. 119 main_sizer = self._build_main_section(box_main) 120 121 # Add the title. 122 self._add_title(main_sizer) 123 124 # Add the description. 125 self.add_desc(main_sizer, max_y=self.height_desc) 126 127 # Add the specific GUI elements (bounded by spacers). 128 main_sizer.AddStretchSpacer() 129 self.add_contents(main_sizer)
130 131
132 - def _add_title(self, sizer):
133 """Add the title to the dialog. 134 135 @param sizer: A sizer object. 136 @type sizer: wx.Sizer instance 137 """ 138 139 # Spacing. 140 sizer.AddSpacer(10) 141 142 # The text. 143 title = wx.StaticText(self, -1, self.title) 144 145 # Font. 146 title.SetFont(font.title) 147 148 # Add the title. 149 sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 0) 150 151 # Spacing. 152 sizer.AddSpacer(10)
153 154
155 - def _apply(self, event=None):
156 """Apply the operation. 157 158 @keyword event: The wx event. 159 @type event: wx event 160 """ 161 162 # Execute. 163 self.exec_status = self.on_execute() 164 165 # Execution failure. 166 if not self.exec_status: 167 return 168 169 # Finished. 170 self.on_completion() 171 172 # Execute the on_apply() method. 173 self.on_apply()
174 175
176 - def _build_main_section(self, sizer):
177 """Add the main part of the dialog. 178 179 @param sizer: A sizer object. 180 @type sizer: wx.Sizer instance 181 @return: The sizer object for the main part of the dialog. 182 @rtype: wx.Sizer instance 183 """ 184 185 # Use a grid sizer for packing the elements. 186 main_sizer = wx.BoxSizer(wx.VERTICAL) 187 188 # Pack the sizer. 189 sizer.Add(main_sizer, 1, wx.EXPAND|wx.ALL, 0) 190 191 # Return the sizer. 192 return main_sizer
193 194
195 - def add_artwork(self, sizer):
196 """Add the artwork to the dialog. 197 198 @param sizer: A sizer object. 199 @type sizer: wx.Sizer instance 200 """ 201 202 # Add the graphics. 203 if self.image_path: 204 self.image = wx.StaticBitmap(self, -1, bitmap_setup(self.image_path)) 205 sizer.Add(self.image, 0, wx.TOP|wx.ALIGN_CENTER_HORIZONTAL, 0) 206 207 # A spacer. 208 sizer.AddSpacer(self.art_spacing)
209 210
211 - def add_contents(self, sizer):
212 """Add the specific GUI elements (dummy method). 213 214 @param sizer: A sizer object. 215 @type sizer: wx.Sizer instance 216 """ 217 218 # This must be supplied. 219 raise RelaxImplementError
220 221
222 - def add_desc(self, sizer, max_y=220):
223 """Add the description to the dialog. 224 225 @param sizer: A sizer object. 226 @type sizer: wx.Sizer instance 227 @keyword max_y: The maximum height, in number of pixels, for the description. 228 @type max_y: int 229 """ 230 231 # A line with spacing. 232 sizer.AddSpacer(5) 233 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 234 sizer.AddSpacer(5) 235 236 # Create a scrolled panel. 237 panel = scrolledpanel.ScrolledPanel(self, -1, name="desc") 238 239 # A sizer for the panel. 240 panel_sizer = wx.BoxSizer(wx.VERTICAL) 241 242 # The text. 243 text = wx.StaticText(panel, -1, self.main_text, style=wx.TE_MULTILINE) 244 text.SetFont(font.normal) 245 246 # Wrap the text. 247 text.Wrap(self._main_size - 20) 248 249 # The text size. 250 x, y = text.GetSizeTuple() 251 252 # Scrolling needed. 253 if y > max_y-10: 254 # Set the panel size. 255 panel.SetInitialSize((self._main_size, max_y)) 256 257 # No scrolling. 258 else: 259 # Rewrap the text. 260 text.Wrap(self._main_size) 261 262 # Set the panel size. 263 panel.SetInitialSize(text.GetSize()) 264 265 # Add the text. 266 panel_sizer.Add(text, 0, wx.ALIGN_LEFT, 0) 267 268 # Set up and add the panel to the sizer. 269 panel.SetSizer(panel_sizer) 270 panel.SetAutoLayout(1) 271 panel.SetupScrolling(scroll_x=False, scroll_y=True) 272 sizer.Add(panel, 0, wx.ALL|wx.EXPAND) 273 274 # A line with spacing. 275 sizer.AddSpacer(5) 276 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 277 sizer.AddSpacer(5)
278 279
280 - def on_apply(self):
281 """To be over-ridden if an action is to be performed on hitting the apply button. 282 283 This method will be called when clicking on the apply button. 284 """
285 286
287 - def on_back(self):
288 """To be over-ridden if an action is to be performed just before moving back to the previous page. 289 290 This method is called when moving back to the previous page of the wizard. 291 """
292 293
294 - def on_completion(self):
295 """To be over-ridden if an action is to be performed just after executing self.on_execute(). 296 297 This method is called just after self.on_execute() has been called 298 """
299 300
301 - def on_display(self):
302 """To be over-ridden if an action is to be performed prior to displaying the page. 303 304 This method will be called by the wizard class method _display_page() just after hiding all other pages but prior to displaying this page. 305 """
306 307
308 - def on_display_post(self):
309 """To be over-ridden if an action is to be performed after the execution of the on_display() method. 310 311 This method will be called by the wizard class method _display_page() just after hiding all other pages but prior to displaying this page. 312 """
313 314
315 - def on_execute(self):
316 """To be over-ridden if an action is to be performed just before exiting the page. 317 318 This method is called when terminating the wizard or hitting the apply button. 319 """ 320 321 return True
322 323
324 - def on_init(self):
325 """To be over-ridden if an action is to be performed when a page is newly displayed. 326 327 This method will be called by the wizard class method _display_page() at the very end. 328 """
329 330
331 - def on_next(self):
332 """To be over-ridden if an action is to be performed just before moving to the next page. 333 334 This method is called when moving to the next page of the wizard. 335 """
336 337 338
339 -class Wiz_window(wx.Dialog):
340 """The wizard.""" 341 342 # Some class variables. 343 _size_button = (100, 33) 344 ICON_APPLY = paths.icon_22x22.dialog_ok_apply 345 ICON_BACK = paths.icon_22x22.go_previous_view 346 ICON_CANCEL = paths.icon_22x22.dialog_cancel 347 ICON_FINISH = paths.icon_22x22.dialog_ok 348 ICON_NEXT = paths.icon_22x22.go_next_view 349 ICON_OK = paths.icon_22x22.dialog_ok 350 ICON_SKIP = paths.icon_22x22.skip 351 TEXT_APPLY = " Apply" 352 TEXT_BACK = " Back" 353 TEXT_CANCEL = " Cancel" 354 TEXT_FINISH = " Finish" 355 TEXT_NEXT = " Next" 356 TEXT_OK = " OK" 357 TEXT_SKIP = " Skip" 358 359
360 - def __init__(self, parent=None, size_x=400, size_y=400, title='', border=10, style=wx.DEFAULT_DIALOG_STYLE):
361 """Set up the window. 362 363 @keyword parent: The parent window. 364 @type parent: wx.Window instance 365 @keyword size_x: The width of the wizard. 366 @type size_x: int 367 @keyword size_y: The height of the wizard. 368 @type size_y: int 369 @keyword title: The title of the wizard dialog. 370 @type title: str 371 @keyword border: The size of the border inside the wizard. 372 @type border: int 373 @keyword style: The dialog style. 374 @type style: wx style 375 """ 376 377 # Store the args. 378 self._size_x = size_x 379 self._size_y = size_y 380 self._border = border 381 382 # Execute the base class method. 383 wx.Dialog.__init__(self, parent, id=-1, title=title, style=style) 384 385 # Set up the window icon. 386 self.SetIcons(relax_icons) 387 388 # The sizer for the dialog. 389 sizer = wx.BoxSizer(wx.VERTICAL) 390 self.SetSizer(sizer) 391 392 # Build the central sizer, with borders. 393 self._main_sizer = add_border(sizer, border=border, packing=wx.VERTICAL) 394 395 # Set the default size of the dialog. 396 self.SetSize((size_x, size_y)) 397 398 # Centre the dialog. 399 self.Centre() 400 401 # Initialise the page storage. 402 self._current_page = 0 403 self._num_pages = 0 404 self._pages = [] 405 self._page_sizers = [] 406 self._button_sizers = [] 407 self._button_apply_flag = [] 408 self._button_skip_flag = [] 409 self._buttons = [] 410 self._button_ids = [] 411 self._exec_on_next = [] 412 self._exec_count = [] 413 self._proceed_on_error = [] 414 self._uf_flush = [] 415 self._seq_fn_list = [] 416 self._seq_next = [] 417 self._seq_prev = [] 418 self._skip_flag = [] 419 420 # A max of 10 pages should be plenty enough (any more and the developer should be shot!). 421 for i in range(10): 422 # Append some Nones. 423 self._pages.append(None) 424 425 # Initialise all box sizers for the wizard pages. 426 self._page_sizers.append(wx.BoxSizer(wx.VERTICAL)) 427 428 # Initialise all box sizers for the buttons. 429 self._button_sizers.append(wx.BoxSizer(wx.HORIZONTAL)) 430 431 # Set all button flags. 432 self._button_apply_flag.append(True) 433 self._button_skip_flag.append(False) 434 435 # Initialise the button storage. 436 self._buttons.append({'back': None, 437 'apply': None, 438 'next': None, 439 'ok': None, 440 'finish': None, 441 'cancel': None}) 442 443 # Initialise a set of unique button IDs. 444 self._button_ids.append({'back': wx.NewId(), 445 'apply': wx.NewId(), 446 'next': wx.NewId(), 447 'ok': wx.NewId(), 448 'finish': wx.NewId(), 449 'cancel': wx.NewId()}) 450 451 # Execute on next by default. 452 self._exec_on_next.append(True) 453 454 # Execution count. 455 self._exec_count.append(0) 456 457 # Proceed to next page on errors by default. 458 self._proceed_on_error.append(True) 459 460 # No user function flushing of the GUI interpreter thread prior to proceeding. 461 self._uf_flush.append(False) 462 463 # Page sequence initialisation. 464 self._seq_fn_list.append(self._next_fn) 465 self._seq_next.append(None) 466 self._seq_prev.append(None) 467 468 # Page skipping. 469 self._skip_flag.append(False) 470 471 # Flag to suppress later button addition. 472 self._buttons_built = False 473 474 # Bind some events. 475 self.Bind(wx.EVT_CLOSE, self._handler_close)
476 477
478 - def _apply(self, event=None):
479 """Execute the current page's 'Apply' method. 480 481 @keyword event: The wx event. 482 @type event: wx event 483 """ 484 485 # Execute the current page's apply() method. 486 self._pages[self._current_page]._apply()
487 488
489 - def _build_buttons(self):
490 """Construct the buttons for all pages of the wizard.""" 491 492 # Loop over each page. 493 for i in range(self._num_pages): 494 # The back button (only for multi-pages, after the first). 495 if self._num_pages > 1 and i > 0: 496 # Create the button. 497 button = buttons.ThemedGenBitmapTextButton(self, -1, None, self.TEXT_BACK) 498 button.SetBitmapLabel(wx.Bitmap(self.ICON_BACK, wx.BITMAP_TYPE_ANY)) 499 button.SetFont(font.normal) 500 button.SetToolTipString("Return to the previous page") 501 button.SetMinSize(self._size_button) 502 self._button_sizers[i].Add(button, 0, wx.ADJUST_MINSIZE, 0) 503 self.Bind(wx.EVT_BUTTON, self._go_back, button) 504 self._buttons[i]['back'] = button 505 506 # Spacer. 507 self._button_sizers[i].AddSpacer(5) 508 509 # The apply button. 510 if self._button_apply_flag[i]: 511 # Create the button. 512 button = buttons.ThemedGenBitmapTextButton(self, -1, None, self.TEXT_APPLY) 513 button.SetBitmapLabel(wx.Bitmap(self.ICON_APPLY, wx.BITMAP_TYPE_ANY)) 514 button.SetFont(font.normal) 515 button.SetToolTipString("Apply the operation") 516 button.SetMinSize(self._size_button) 517 self._button_sizers[i].Add(button, 0, wx.ADJUST_MINSIZE, 0) 518 self.Bind(wx.EVT_BUTTON, self._pages[i]._apply, button) 519 self._buttons[i]['apply'] = button 520 521 # Spacer. 522 self._button_sizers[i].AddSpacer(5) 523 524 # The skip button. 525 if self._button_skip_flag[i]: 526 # Create the button. 527 button = buttons.ThemedGenBitmapTextButton(self, -1, None, self.TEXT_SKIP) 528 button.SetBitmapLabel(wx.Bitmap(self.ICON_SKIP, wx.BITMAP_TYPE_ANY)) 529 button.SetFont(font.normal) 530 button.SetToolTipString("Skip the operation") 531 button.SetMinSize(self._size_button) 532 self._button_sizers[i].Add(button, 0, wx.ADJUST_MINSIZE, 0) 533 self.Bind(wx.EVT_BUTTON, self._skip, button) 534 self._buttons[i]['skip'] = button 535 536 # Spacer. 537 self._button_sizers[i].AddSpacer(5) 538 539 # The next button (only for multi-pages, excluding the last). 540 if self._num_pages > 1 and i < self._num_pages - 1: 541 # Create the button. 542 button = buttons.ThemedGenBitmapTextButton(self, -1, None, self.TEXT_NEXT) 543 button.SetBitmapLabel(wx.Bitmap(self.ICON_NEXT, wx.BITMAP_TYPE_ANY)) 544 button.SetFont(font.normal) 545 button.SetToolTipString("Move to the next page") 546 button.SetMinSize(self._size_button) 547 self._button_sizers[i].Add(button, 0, wx.ADJUST_MINSIZE, 0) 548 self.Bind(wx.EVT_BUTTON, self._go_next, button) 549 self._buttons[i]['next'] = button 550 551 # The OK button (only for single pages). 552 if self._num_pages == 1: 553 button = buttons.ThemedGenBitmapTextButton(self, -1, None, self.TEXT_OK) 554 button.SetBitmapLabel(wx.Bitmap(self.ICON_OK, wx.BITMAP_TYPE_ANY)) 555 button.SetFont(font.normal) 556 button.SetToolTipString("Accept the operation") 557 button.SetMinSize(self._size_button) 558 self._button_sizers[i].Add(button, 0, wx.ADJUST_MINSIZE, 0) 559 self.Bind(wx.EVT_BUTTON, self._ok, button) 560 self._buttons[i]['ok'] = button 561 562 # The finish button (only for the last page with multi-pages). 563 if self._num_pages > 1 and i == self._num_pages - 1: 564 button = buttons.ThemedGenBitmapTextButton(self, -1, None, self.TEXT_FINISH) 565 button.SetBitmapLabel(wx.Bitmap(self.ICON_FINISH, wx.BITMAP_TYPE_ANY)) 566 button.SetFont(font.normal) 567 button.SetToolTipString("Accept the operation") 568 button.SetMinSize(self._size_button) 569 self._button_sizers[i].Add(button, 0, wx.ADJUST_MINSIZE, 0) 570 self.Bind(wx.EVT_BUTTON, self._ok, button) 571 self._buttons[i]['finish'] = button 572 573 # Spacer. 574 self._button_sizers[i].AddSpacer(15) 575 576 # The cancel button. 577 button = buttons.ThemedGenBitmapTextButton(self, -1, None, self.TEXT_CANCEL) 578 button.SetBitmapLabel(wx.Bitmap(self.ICON_CANCEL, wx.BITMAP_TYPE_ANY)) 579 button.SetFont(font.normal) 580 button.SetToolTipString("Abort the operation") 581 button.SetMinSize(self._size_button) 582 self._button_sizers[i].Add(button, 0, wx.ADJUST_MINSIZE, 0) 583 self.Bind(wx.EVT_BUTTON, self._cancel, button) 584 self._buttons[i]['cancel'] = button 585 586 # Flag to suppress later button addition. 587 self._buttons_built = True
588 589
590 - def _cancel(self, event=None):
591 """Cancel the operation. 592 593 @keyword event: The wx event. 594 @type event: wx event 595 """ 596 597 # Execute the page's on_next() method to allow the page to clean itself up. 598 self._pages[self._current_page].on_next() 599 600 # Close the window. 601 self.Close()
602 603
604 - def _display_page(self, i):
605 """Display the given page. 606 607 @param i: The index of the page to display. 608 @type i: int 609 """ 610 611 # Hide all of the original contents. 612 for j in range(self._num_pages): 613 if self._main_sizer.IsShown(self._page_sizers[j]): 614 self._main_sizer.Hide(self._page_sizers[j]) 615 616 # Show the desired page. 617 if status.show_gui: 618 self._main_sizer.Show(self._page_sizers[i]) 619 620 # Execute the page's on_display() method. 621 self._pages[i].on_display() 622 self._pages[i].on_display_post() 623 624 # Re-perform the window layout. 625 self.Layout() 626 self.Refresh() 627 628 # Execute the page's on_init() method. 629 self._pages[i].on_init()
630 631
632 - def _go_back(self, event=None):
633 """Return to the previous page. 634 635 @keyword event: The wx event. 636 @type event: wx event 637 """ 638 639 # Execute the page's on_next() method. 640 self._pages[self._current_page].on_back() 641 642 # Work back in the sequence. 643 self._current_page = self._seq_prev[self._current_page] 644 645 # Display the previous page. 646 self._display_page(self._current_page)
647 648
649 - def _go_next(self, event=None):
650 """Move to the next page. 651 652 @keyword event: The wx event. 653 @type event: wx event 654 """ 655 656 # Execute the page's on_next() method. 657 self._pages[self._current_page].on_next() 658 659 # Operations for non-skipped pages. 660 if not self._skip_flag[self._current_page]: 661 # Execute the page's on_execute() method (via the _apply() method). 662 if self._exec_on_next[self._current_page]: 663 self._pages[self._current_page]._apply(event) 664 665 # UF flush. 666 if self._uf_flush[self._current_page]: 667 interpreter.flush() 668 669 # Check for execution errors. 670 if not self._pages[self._current_page].exec_status: 671 # Do not proceed. 672 if not self._proceed_on_error[self._current_page]: 673 return 674 675 # Increment the execution counter. 676 self._exec_count[self._current_page] += 1 677 678 # Determine the next page. 679 next_page = self._seq_fn_list[self._current_page]() 680 681 # No next page, so terminate. 682 if self._pages[next_page] == None: 683 self._ok(None) 684 return 685 686 # Update the sequence lists. 687 self._seq_next[self._current_page] = next_page 688 self._seq_prev[next_page] = self._current_page 689 690 # Change the current page. 691 self._current_page = next_page 692 693 # Display the next page. 694 self._display_page(self._current_page)
695 696
697 - def _handler_close(self, event=None):
698 """Event handler for the close window action. 699 700 @keyword event: The wx event. 701 @type event: wx event 702 """ 703 704 # Execute the page's on_next() method to allow the page to clean itself up. 705 self._pages[self._current_page].on_next() 706 707 # Continue with the window closing. 708 event.Skip()
709 710
711 - def _next_fn(self):
712 """Standard function for setting the next page to the one directly next in the sequence. 713 714 @return: The index of the next page, which is the current page index plus one. 715 @rtype: int 716 """ 717 718 # Return the next page. 719 return self._current_page + 1
720 721
722 - def _ok(self, event=None):
723 """Accept the operation. 724 725 @keyword event: The wx event. 726 @type event: wx event 727 """ 728 729 # Loop over the pages in the sequence and execute their _apply() methods, if not already done and not skipped. 730 for i in self._seq_loop(): 731 if not self._exec_count[i] and not self._skip_flag[i]: 732 # Execute the _apply method. 733 self._pages[i]._apply(event) 734 735 # UF flush. 736 if self._uf_flush[i]: 737 interpreter.flush() 738 739 # Check for execution errors. 740 if not self._pages[self._current_page].exec_status: 741 # Do not proceed. 742 if not self._proceed_on_error[self._current_page]: 743 return 744 745 # Increment the execution counter. 746 self._exec_count[i] += 1 747 748 # Execute the current page's on_next() method to allow the page to clean itself up. 749 self._pages[self._current_page].on_next() 750 751 # Then close the dialog. 752 if self.IsModal(): 753 self.EndModal(wx.ID_OK) 754 else: 755 self.Close()
756 757
758 - def _seq_loop(self):
759 """Loop over the sequence in the forwards direction.""" 760 761 # Initialise. 762 current = 0 763 764 # First yield the initial element (always zero!). 765 yield current 766 767 # Loop over the sequence. 768 while True: 769 # Update. 770 next = self._seq_next[current] 771 current = next 772 773 # End of the sequence. 774 if next == None: 775 break 776 777 # Yield the next index. 778 yield next
779 780
781 - def _skip(self, event=None):
782 """Skip the page. 783 784 @keyword event: The wx event. 785 @type event: wx event 786 """ 787 788 # Set the skip flag. 789 self._skip_flag[self._current_page] = True 790 791 # Go to the next page. 792 self._go_next(None)
793 794
795 - def add_page(self, panel, apply_button=True, skip_button=False, exec_on_next=True, proceed_on_error=True, uf_flush=False):
796 """Add a new page to the wizard. 797 798 @param panel: The page to add to the wizard. 799 @type panel: wx.Panel instance 800 @keyword apply_button: A flag which if true will show the apply button for that page. 801 @type apply_button: bool 802 @keyword skip_button: A flag which if true will show the skip button for that page. 803 @type skip_button: bool 804 @keyword exec_on_next: A flag which if true will run the on_execute() method when clicking on the next button. 805 @type exec_on_next: bool 806 @keyword proceed_on_error: A flag which if True will proceed to the next page (or quit if there are no more pages) despite the occurrence of an error in execution. If False, the page will remain open (the GUI interpreter thread will be flushed first to synchronise). 807 @type proceed_on_error: bool 808 @keyword uf_flush: A flag which if True will cause the GUI interpreter thread to be flushed to clear out all user function call prior to proceeding. 809 @type uf_flush: bool 810 @return: The index of the page in the wizard. 811 @rtype: int 812 """ 813 814 # Store the page. 815 index = self._num_pages 816 self._num_pages += 1 817 self._pages[index] = panel 818 819 # Store a new sizer for the page and its buttons. 820 self._main_sizer.Add(self._page_sizers[index], 1, wx.ALL|wx.EXPAND, 0) 821 822 # Add the sizer for the top half. 823 top_sizer = wx.BoxSizer(wx.VERTICAL) 824 self._page_sizers[index].Add(top_sizer, 1, wx.ALL|wx.EXPAND, 0) 825 826 # Add the page to the top sizer. 827 top_sizer.Add(panel, 1, wx.ALL|wx.EXPAND, 0) 828 829 # Add the sizer for the wizard buttons. 830 self._page_sizers[index].Add(self._button_sizers[index], 0, wx.ALIGN_RIGHT|wx.ALL, 0) 831 832 # Store the flags. 833 self._button_apply_flag[index] = apply_button 834 self._button_skip_flag[index] = skip_button 835 self._exec_on_next[index] = exec_on_next 836 self._proceed_on_error[index] = proceed_on_error 837 if not proceed_on_error or uf_flush: 838 self._uf_flush[index] = True 839 840 # Store the index of the page. 841 panel.page_index = self._num_pages - 1 842 843 # Return the index of the page. 844 return panel.page_index
845 846
847 - def block_next(self, block=True):
848 """Prevent moving forwards (or unblock). 849 850 @keyword block: A flag which if True will block forwards movement and if False will unblock. 851 @type block: bool 852 """ 853 854 # The buttons to disable. 855 buttons = ['next', 'ok', 'finish'] 856 857 # Disable or enable the buttons. 858 for i in range(len(buttons)): 859 # The button. 860 button = self._buttons[self._current_page][buttons[i]] 861 if button == None: 862 continue 863 864 # Block. 865 if block: 866 button.Disable() 867 868 # Unblock. 869 else: 870 button.Enable()
871 872
873 - def get_page(self, index):
874 """Get a page from the wizard. 875 876 @param index: The index of the page. 877 @type index: int 878 @return: The page object. 879 @rtype: Wiz_page instance. 880 """ 881 882 # Return the page. 883 return self._pages[index]
884 885
886 - def reset(self):
887 """Reset the wizard.""" 888 889 # Clear the execution counts. 890 for i in range(len(self._exec_count)): 891 self._exec_count[i] = 0
892 893
894 - def run(self, modal=False):
895 """Execute the wizard. 896 897 @keyword modal: A flag which if True will cause the wizard to be run as a modal dialog. 898 @type modal: bool 899 @return: The status from the modal operation, i.e. True if the wizard is run, False if cancelled or other error occur. For modeless operation, this returns nothing. 900 @rtype: bool or None 901 """ 902 903 # Check that all pages have been set up correctly, returning without doing anything if not. 904 for i in range(self._num_pages): 905 if self._pages[i].setup_fail: 906 return 907 908 # Build the buttons for the entire wizard. 909 if not self._buttons_built: 910 self._build_buttons() 911 912 # Display the first page. 913 self._display_page(0) 914 915 # Display failure. 916 if self._pages[0].setup_fail: 917 return 918 919 # No GUI. 920 if not status.show_gui: 921 return 922 923 # Modal operation. 924 if modal: 925 # Show the wizard (it should be closed by the _cancel() or _ok() methods). 926 wiz_status = self.ShowModal() 927 928 # Return the status. 929 return wiz_status 930 931 # Modeless operation. 932 else: 933 # Show the wizard. 934 self.Show()
935 936
937 - def set_seq_next_fn(self, index, fn):
938 """A user specified function for non-linear page changing. 939 940 @param index: The index of the page the function should be associated with. 941 @type index: int 942 @param fn: The function for determining the page after the current. This function should return the index of the next page. 943 @type fn: func or method. 944 """ 945 946 # Store the function. 947 self._seq_fn_list[index] = fn
948