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