Package gui :: Package wizards :: Module wiz_objects
[hide private]
[frames] | no frames]

Source Code for Module gui.wizards.wiz_objects

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