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