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

Source Code for Module gui.relax_gui

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2009 Michael Bieri                                            # 
  4  # Copyright (C) 2010-2015 Edward d'Auvergne                                   # 
  5  #                                                                             # 
  6  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  7  #                                                                             # 
  8  # This program is free software: you can redistribute it and/or modify        # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation, either version 3 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # This program is distributed in the hope that it will be useful,             # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """Main module for the relax graphical user interface.""" 
 25   
 26  # Python module imports. 
 27  from os import F_OK, access, getcwd, sep 
 28  import platform 
 29  from re import search 
 30  import sys 
 31  from time import sleep 
 32  import webbrowser 
 33  import wx 
 34   
 35  # relax module imports. 
 36  from data_store import Relax_data_store; ds = Relax_data_store() 
 37  from data_store.gui import Gui 
 38  from graphics import IMAGE_PATH, fetch_icon 
 39  from gui.about import About_relax 
 40  from gui.analyses import Analysis_controller 
 41  from gui.spin_viewer.frame import Spin_view_window 
 42  from gui.controller import Controller 
 43  from gui.export_bmrb import Export_bmrb_window 
 44  from gui.filedialog import RelaxFileDialog 
 45  from gui.fonts import font 
 46  from gui.icons import relax_icons 
 47  from gui.interpreter import Interpreter 
 48  from gui.menu import Menu 
 49  from gui.message import error_message, Question 
 50  from gui.misc import bitmap_setup, gui_raise, open_file, protected_exec 
 51  from gui.pipe_editor import Pipe_editor 
 52  from gui.references import References 
 53  from gui.relax_prompt import Prompt 
 54  from gui.results_viewer import Results_viewer 
 55  from gui.components.free_file_format import Free_file_format_window 
 56  from gui.string_conv import gui_to_str 
 57  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 58  from info import Info_box 
 59  from lib.errors import RelaxNoPipeError 
 60  from lib.io import io_streams_restore 
 61  from pipe_control import state 
 62  from pipe_control.pipes import cdp_name 
 63  from pipe_control.reset import reset 
 64  from status import Status; status = Status() 
 65  from version import version 
 66   
 67   
 68  # wx IDs for the toolbar. 
 69  TB_FILE_NEW = wx.NewId() 
 70  TB_FILE_CLOSE = wx.NewId() 
 71  TB_FILE_CLOSE_ALL = wx.NewId() 
 72  TB_FILE_OPEN = wx.NewId() 
 73  TB_FILE_SAVE = wx.NewId() 
 74  TB_FILE_SAVE_AS = wx.NewId() 
 75  TB_VIEW_CONTROLLER = wx.NewId() 
 76  TB_VIEW_SPIN_VIEW = wx.NewId() 
 77  TB_VIEW_RESULTS = wx.NewId() 
 78  TB_VIEW_PIPE_EDIT = wx.NewId() 
 79  TB_VIEW_PROMPT = wx.NewId() 
 80   
 81   
 82   
83 -class Main(wx.Frame):
84 """The main GUI class.""" 85 86 # Hard coded variables. 87 min_width = 1000 88 min_height = 600 89
90 - def __init__(self, parent=None, id=-1, title=""):
91 """Initialise the main relax GUI frame.""" 92 93 # Store the wxPython info for os/machine/version specific hacks. 94 status.wx_info = {} 95 status.wx_info["version"] = wx.__version__.split('.') 96 status.wx_info["minor"] = "%s.%s" % (status.wx_info["version"][0], status.wx_info["version"][1]) 97 status.wx_info["os"] = sys.platform 98 status.wx_info["build"] = None 99 if search('gtk2', wx.version()): 100 status.wx_info["build"] = 'gtk' 101 elif search('cocoa', wx.version()): 102 status.wx_info["build"] = 'cocoa' 103 elif search('mac-unicode', wx.version()): 104 status.wx_info["build"] = 'carbon' 105 status.wx_info["full"] = None 106 if status.wx_info["build"]: 107 status.wx_info["full"] = "%s-%s" % (status.wx_info["os"], status.wx_info["build"]) 108 109 # Some internal variables. 110 self.test_suite_flag = False 111 112 # The main window style. 113 style = wx.DEFAULT_FRAME_STYLE 114 if not status.debug and status.wx_info["os"] != 'darwin': 115 style = style | wx.MAXIMIZE 116 117 # Execute the base class __init__ method. 118 super(Main, self).__init__(parent=parent, id=id, title=title, style=style) 119 120 # Force the main window to start maximised (needed for MS Windows). 121 if not status.debug and status.wx_info["os"] != 'darwin': 122 self.Maximize() 123 124 # Set up some standard interface-wide fonts. 125 font.setup() 126 127 # Set up the relax icons. 128 relax_icons.setup() 129 self.SetIcons(relax_icons) 130 131 # Set up the Mac OS X task bar icon. 132 #if status.wx_info["os"] == 'darwin' and status.wx_info["build"] != 'gtk': 133 # self.taskbar_icon = Relax_task_bar_icon(self) 134 135 # Initialise some variables for the GUI. 136 self.launch_dir = getcwd() 137 138 # Set up the frame. 139 self.Layout() 140 self.SetSize((self.min_width, self.min_height)) 141 self.SetMinSize((self.min_width, self.min_height)) 142 self.Centre() 143 144 # The analysis window object storage. 145 self.analysis = Analysis_controller(self) 146 147 # The calculation threads list. 148 self.calc_threads = [] 149 150 # Initialise the GUI data. 151 self.init_data() 152 153 # Build the menu bar. 154 self.menu = Menu(self) 155 156 # Build the toolbar. 157 self.build_toolbar() 158 159 # Build the controller, but don't show it. 160 self.controller = Controller(self) 161 162 # Set the title. 163 self.SetTitle("relax " + version) 164 165 # Set up the status bar. 166 self.status_bar = self.CreateStatusBar(3, 0) 167 self.status_bar.SetStatusWidths([-4, -1, -2]) 168 self.update_status_bar() 169 170 # Add the start screen. 171 self.add_start_screen() 172 173 # Close Box event. 174 self.Bind(wx.EVT_CLOSE, self.exit_gui) 175 176 # Initialise the special interpreter thread object. 177 self.interpreter = Interpreter() 178 179 # Register functions with the observer objects. 180 status.observers.pipe_alteration.register('status bar', self.update_status_bar, method_name='update_status_bar') 181 status.observers.result_file.register('gui', self.show_results_viewer_no_warn, method_name='show_results_viewer_no_warn') 182 status.observers.exec_lock.register('gui', self.enable, method_name='enab') 183 184 # Assume a script has been run and there is data in the store. 185 self.analysis.load_from_store()
186 187
188 - def about_relax(self, event=None):
189 """The about message for relax. 190 191 @keyword event: The wx event. 192 @type event: wx event 193 """ 194 195 # Build the dialog. 196 dialog = About_relax(None, -1) 197 198 # The dialog. 199 if status.show_gui: 200 dialog.Show()
201 202
203 - def action_export_bmrb(self, event=None):
204 """Export the contents of the current data pipe for BMRB deposition. 205 206 @keyword event: The wx event. 207 @type event: wx event 208 """ 209 210 # No current data pipe. 211 if not cdp_name(): 212 gui_raise(RelaxNoPipeError()) 213 return 214 215 # Open the export window. 216 Export_bmrb_window(self)
217 218
219 - def action_state_save(self, event=None):
220 """Save the program state. 221 222 @keyword event: The wx event. 223 @type event: wx event 224 """ 225 226 # Not saved yet, therefore pass execution to state_save_as(). 227 if not self.save_file: 228 self.action_state_save_as(event) 229 return 230 231 # Save. 232 self.state_save()
233 234
235 - def action_state_save_as(self, event=None):
236 """Save the program state with file name selection. 237 238 @keyword event: The wx event. 239 @type event: wx event 240 """ 241 242 # The dialog. 243 dialog = RelaxFileDialog(parent=self, message='Select the relax save state file', defaultFile='state.bz2', wildcard='relax save file (*.bz2)|*.bz2', style=wx.FD_SAVE) 244 245 # Show the dialog and catch if no file has been selected. 246 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 247 # Don't do anything. 248 return 249 250 # The file. 251 file_name = dialog.get_file() 252 253 # Set the file name. 254 self.save_file = file_name 255 256 # Save. 257 self.state_save()
258 259
260 - def add_start_screen(self):
261 """Create a start screen for the main window when no analyses exist.""" 262 263 # The sizer for the main GUI window. 264 sizer = wx.BoxSizer(wx.VERTICAL) 265 self.SetSizer(sizer) 266 267 # The relax icon. 268 image = wx.StaticBitmap(self, -1, bitmap_setup(IMAGE_PATH+'ulysses_shadowless_400x168.png')) 269 270 # Add the icon to the main spacer with spacing. 271 sizer.AddStretchSpacer() 272 sizer.Add(image, 0, wx.ALIGN_CENTER_HORIZONTAL, 0) 273 sizer.AddStretchSpacer() 274 275 # Re-perform the layout of the GUI elements, and refresh. 276 self.Layout() 277 self.Refresh()
278 279
280 - def build_toolbar(self):
281 """Create the toolbar.""" 282 283 # Init. 284 self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL|wx.TB_FLAT) 285 286 # The new analysis button. 287 self.toolbar.AddLabelTool(TB_FILE_NEW, "New analysis", wx.Bitmap(fetch_icon('oxygen.actions.document-new', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="New analysis") 288 self.Bind(wx.EVT_TOOL, self.analysis.menu_new, id=TB_FILE_NEW) 289 290 # The close analysis button. 291 self.toolbar.AddLabelTool(TB_FILE_CLOSE, "Close analysis", wx.Bitmap(fetch_icon('oxygen.actions.document-close', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Close analysis") 292 self.Bind(wx.EVT_TOOL, self.analysis.menu_close, id=TB_FILE_CLOSE) 293 294 # The close all analyses button. 295 self.toolbar.AddLabelTool(TB_FILE_CLOSE_ALL, "Close all analyses", wx.Bitmap(fetch_icon('oxygen.actions.dialog-close', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Close all analyses") 296 self.Bind(wx.EVT_TOOL, self.analysis.menu_close_all, id=TB_FILE_CLOSE_ALL) 297 298 # A separator. 299 self.toolbar.AddSeparator() 300 301 # The open state button. 302 self.toolbar.AddLabelTool(TB_FILE_OPEN, "Open relax state", wx.Bitmap(fetch_icon('oxygen.actions.document-open', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Open relax state") 303 self.Bind(wx.EVT_TOOL, self.state_load, id=TB_FILE_OPEN) 304 305 # The save state button. 306 self.toolbar.AddLabelTool(TB_FILE_SAVE, "Save relax state", wx.Bitmap(fetch_icon('oxygen.actions.document-save', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Save relax state") 307 self.Bind(wx.EVT_TOOL, self.action_state_save, id=TB_FILE_SAVE) 308 309 # The save as button. 310 self.toolbar.AddLabelTool(TB_FILE_SAVE_AS, "Save as", wx.Bitmap(fetch_icon('oxygen.actions.document-save-as', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Save as") 311 self.Bind(wx.EVT_TOOL, self.action_state_save_as, id=TB_FILE_SAVE_AS) 312 313 # A separator. 314 self.toolbar.AddSeparator() 315 316 # The relax controller button. 317 self.toolbar.AddLabelTool(TB_VIEW_CONTROLLER, "Controller", wx.Bitmap(fetch_icon('oxygen.apps.preferences-system-performance', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="relax controller") 318 self.Bind(wx.EVT_TOOL, self.show_controller, id=TB_VIEW_CONTROLLER) 319 320 # The spin viewer button. 321 self.toolbar.AddLabelTool(TB_VIEW_SPIN_VIEW, "Spin viewer", wx.Bitmap(fetch_icon('relax.spin', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Spin viewer window") 322 self.Bind(wx.EVT_TOOL, self.show_tree, id=TB_VIEW_SPIN_VIEW) 323 324 # The results viewer button. 325 self.toolbar.AddLabelTool(TB_VIEW_RESULTS, "Results viewer", wx.Bitmap(fetch_icon('oxygen.actions.view-statistics', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Results viewer window") 326 self.Bind(wx.EVT_TOOL, self.show_results_viewer, id=TB_VIEW_RESULTS) 327 328 # The data pipe editor button. 329 self.toolbar.AddLabelTool(TB_VIEW_PIPE_EDIT, "Data pipe editor", wx.Bitmap(fetch_icon('relax.pipe', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Data pipe editor") 330 self.Bind(wx.EVT_TOOL, self.show_pipe_editor, id=TB_VIEW_PIPE_EDIT) 331 332 # The relax prompt button. 333 self.toolbar.AddLabelTool(TB_VIEW_PROMPT, "relax prompt", wx.Bitmap(fetch_icon('oxygen.mimetypes.application-x-executable-script', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="The relax prompt GUI window") 334 self.Bind(wx.EVT_TOOL, self.show_prompt, id=TB_VIEW_PROMPT) 335 336 # Build the toolbar. 337 self.toolbar.Realize()
338 339
340 - def close_windows(self):
341 """Throw a warning to close all of the non-essential windows when execution is locked. 342 343 This is to speed up the calculations by avoiding window updates. 344 """ 345 346 # Init the window list. 347 win_list = [] 348 349 # Is the spin viewer window open? 350 if hasattr(self, 'spin_viewer') and self.spin_viewer.IsShown(): 351 win_list.append('The spin viewer window') 352 353 # Is the pipe editor window open? 354 if hasattr(self, 'pipe_editor') and self.pipe_editor.IsShown(): 355 win_list.append('The data pipe editor window') 356 357 # Is the results viewer window open? 358 if hasattr(self, 'results_viewer') and self.results_viewer.IsShown(): 359 win_list.append('The results viewer window') 360 361 # The windows are not open, so quit. 362 if not len(win_list): 363 return 364 365 # The text. 366 text = "The following windows are currently open:\n\n" 367 for win in win_list: 368 text = "%s\t%s.\n" % (text, win) 369 text = text + "\nClosing these will significantly speed up the calculations." 370 371 # Display the error message dialog. 372 dlg = wx.MessageDialog(self, text, caption="Close windows", style=wx.OK|wx.ICON_EXCLAMATION|wx.STAY_ON_TOP) 373 if status.show_gui: 374 dlg.ShowModal() 375 376 # Otherwise output to stderr. 377 else: 378 sys.stderr.write(text)
379 380
381 - def contact_relax(self, event=None):
382 """Write an email to the relax mailing-list using the standard mailing program. 383 384 @keyword event: The wx event. 385 @type event: wx event 386 """ 387 388 webbrowser.open_new('mailto:relax-users@gna.org')
389 390
391 - def enable(self):
392 """Enable and disable certain parts of the main window with the execution lock.""" 393 394 # Flag for enabling or disabling the elements. 395 enable = False 396 if not status.exec_lock.locked(): 397 enable = True 398 399 # The toolbar. 400 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_NEW, enable) 401 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_CLOSE, enable) 402 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_CLOSE_ALL, enable) 403 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_OPEN, enable) 404 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_SAVE, enable) 405 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_SAVE_AS, enable)
406 407
408 - def exit_gui(self, event=None):
409 """Catch the main window closure and perform the exit procedure. 410 411 @keyword event: The wx event. 412 @type event: wx event 413 """ 414 415 # Ask if the user is sure they would like to exit. 416 doexit = wx.ID_YES 417 if status.show_gui and not ds.is_empty(): 418 doexit = Question('Are you sure you would like to quit relax? All unsaved data will be lost.', title='Exit relax', default=True).ShowModal() 419 420 # Exit. 421 if doexit == wx.ID_YES: 422 # Restore the IO streams. 423 io_streams_restore(verbosity=0) 424 425 # The relax information box. 426 info = Info_box() 427 428 # The width of the printout. 429 if platform.uname()[0] in ['Windows', 'Microsoft']: 430 width = 80 431 else: 432 width = 100 433 434 # Remove the Mac OS X task bar icon. 435 if hasattr(self, 'taskbar_icon'): 436 self.taskbar_icon.Destroy() 437 438 # Terminate the interpreter thread to allow for a cleaner exit. 439 self.interpreter.exit() 440 441 # End the GUI main loop. 442 app = wx.GetApp() 443 app.ExitMainLoop()
444 445
446 - def init_data(self):
447 """Initialise the data used by the GUI interface.""" 448 449 # Temporary data: the save file. 450 self.save_file = None 451 452 # Add the GUI object to the data store, if not present. 453 if not hasattr(ds, 'relax_gui'): 454 ds.relax_gui = Gui()
455 456
457 - def free_file_format_settings(self, event=None):
458 """Open the free file format settings window. 459 460 @keyword event: The wx event. 461 @type event: wx event 462 """ 463 464 # Build the window. 465 win = Free_file_format_window() 466 467 # Show the window. 468 if status.show_gui: 469 win.Show()
470 471
472 - def references(self, event=None):
473 """Display the references relevant for relax. 474 475 @keyword event: The wx event. 476 @type event: wx event 477 """ 478 479 # Build and show the references window. 480 self.references = References(self) 481 if status.show_gui: 482 self.references.Show()
483 484
485 - def relax_manual(self, event=None):
486 """Display the relax manual. 487 488 @keyword event: The wx event. 489 @type event: wx event 490 """ 491 492 # The PDF manual. 493 file = status.install_path + sep+"docs"+sep+"relax.pdf" 494 495 # Test if it exists. 496 if not access(file, F_OK): 497 error_message("The relax manual '%s' cannot be found. Please compile using the scons program." % file) 498 return 499 500 # Open the relax PDF manual using the native PDF reader. 501 open_file(file)
502 503
504 - def reset(self):
505 """Reset the GUI.""" 506 507 # Close some GUI windows, if open. 508 windows = ['pipe_editor', 'relax_prompt', 'results_viewer', 'spin_viewer'] 509 for window in windows: 510 if hasattr(self, window): 511 # Get the object. 512 win_obj = getattr(self, window) 513 514 # Close the window. 515 win_obj.Close() 516 517 # Flush all wx events to make sure the GUI is ready for the next test. 518 wx.Yield() 519 520 # Reset the relax controller. 521 self.controller.reset()
522 523
524 - def run_test_suite(self, event=None, categories=['system', 'unit', 'gui', 'verification']):
525 """Execute the full test suite. 526 527 @keyword event: The wx event. 528 @type event: wx event 529 @keyword categories: The list of test categories to run, for example ['system', 'unit', 'gui', 'verification'] for all tests. 530 @type categories: list of str 531 """ 532 533 # Ask if this should be done. 534 msg = "In running the test suite, relax will be reset and all data lost. Are you sure you would like to run the test suite?" 535 if Question(msg, parent=self, size=(400, 150), default=False).ShowModal() == wx.ID_NO: 536 return 537 538 # Set the test suite flag. 539 self.test_suite_flag = True 540 541 # Change the cursor to waiting. 542 wx.BeginBusyCursor() 543 544 # Set a new style to stay on top, refreshing to update the style (needed for Mac OS X and MS Windows). 545 orig_style = self.controller.GetWindowStyle() 546 self.controller.SetWindowStyle(orig_style | wx.STAY_ON_TOP) 547 self.controller.Refresh() 548 549 # Make the relax controller modal so that all other windows are deactivated (to stop users from clicking on things). 550 self.controller.MakeModal(True) 551 552 # Close all open windows. 553 if hasattr(self, 'spin_viewer'): 554 self.spin_viewer.Close() 555 if hasattr(self, 'pipe_editor'): 556 self.pipe_editor.Close() 557 if hasattr(self, 'results_viewer'): 558 self.results_viewer.Close() 559 if hasattr(self, 'relax_prompt'): 560 self.relax_prompt.Close() 561 562 # Reset relax. 563 reset() 564 565 # Show the relax controller. 566 self.show_controller(event) 567 568 # Yield 569 wx.GetApp().Yield(True) 570 571 # Prevent all new GUI elements from being shown. 572 status.show_gui = False 573 574 # Run the tests (with the import here to break a nasty circular import). 575 import test_suite.test_suite_runner 576 runner = test_suite.test_suite_runner.Test_suite_runner([], from_gui=True, categories=categories) 577 runner.run_all_tests() 578 579 # Reactive the GUI. 580 status.show_gui = True 581 582 # Turn off the busy cursor. 583 if wx.IsBusy(): 584 wx.EndBusyCursor() 585 586 # Restore the controller. 587 self.controller.SetWindowStyle(orig_style) 588 self.controller.MakeModal(False) 589 self.controller.Refresh() 590 591 # Unset the test suite flag. 592 self.test_suite_flag = False 593 594 # Set the controller main gauge to 100%. 595 wx.CallAfter(self.controller.main_gauge.SetValue, 100)
596 597
598 - def run_test_suite_gui(self, event=None):
599 """Execute the GUI tests. 600 601 @keyword event: The wx event. 602 @type event: wx event 603 """ 604 605 # Forward the call. 606 self.run_test_suite(event, categories=['gui'])
607 608
609 - def run_test_suite_sys(self, event=None):
610 """Execute the system tests. 611 612 @keyword event: The wx event. 613 @type event: wx event 614 """ 615 616 # Forward the call. 617 self.run_test_suite(event, categories=['system'])
618 619
620 - def run_test_suite_unit(self, event=None):
621 """Execute the unit tests. 622 623 @keyword event: The wx event. 624 @type event: wx event 625 """ 626 627 # Forward the call. 628 self.run_test_suite(event, categories=['unit'])
629 630
631 - def run_test_suite_verification(self, event=None):
632 """Execute the verification tests. 633 634 @keyword event: The wx event. 635 @type event: wx event 636 """ 637 638 # Forward the call. 639 self.run_test_suite(event, categories=['verification'])
640 641
642 - def show_controller(self, event=None):
643 """Display the relax controller window. 644 645 @keyword event: The wx event. 646 @type event: wx event 647 """ 648 649 # Bring the window to the front. 650 if self.controller.IsShown(): 651 self.controller.Raise() 652 return 653 654 # Open the window. 655 if status.show_gui: 656 self.controller.Show()
657 658
659 - def show_pipe_editor(self, event=None):
660 """Display the data pipe editor window. 661 662 @keyword event: The wx event. 663 @type event: wx event 664 """ 665 666 # Throw a warning if the execution lock is on. 667 if status.exec_lock.locked(): 668 dlg = wx.MessageDialog(self, "Leaving the pipe editor window open will slow down the calculations.", caption="Warning", style=wx.OK|wx.ICON_EXCLAMATION|wx.STAY_ON_TOP) 669 if status.show_gui: 670 dlg.ShowModal() 671 672 # Build the pipe editor if needed. 673 if not hasattr(self, 'pipe_editor'): 674 self.pipe_editor = Pipe_editor(gui=self) 675 676 # Bring the window to the front. 677 if self.pipe_editor.IsShown(): 678 self.pipe_editor.Raise() 679 return 680 681 # Open the window. 682 if status.show_gui and not self.pipe_editor.IsShown(): 683 self.pipe_editor.Show() 684 685 # Update the grid. 686 self.pipe_editor.update_grid() 687 self.pipe_editor.activate() 688 689 # Register the grid for updating when a user function completes or when the GUI analysis tabs change (needed here for the window hiding and associated unregistering). 690 self.pipe_editor.observer_setup(register=True)
691 692
693 - def show_prompt(self, event=None):
694 """Display the relax prompt window. 695 696 @keyword event: The wx event. 697 @type event: wx event 698 """ 699 700 # Build the relax prompt if needed. 701 if not hasattr(self, 'relax_prompt'): 702 self.relax_prompt = Prompt(None, -1, "", parent=self) 703 704 # Bring the window to the front. 705 if self.relax_prompt.IsShown(): 706 self.relax_prompt.Raise() 707 return 708 709 # Open the window. 710 if status.show_gui: 711 self.relax_prompt.Show()
712 713
714 - def show_results_viewer(self, event=None):
715 """Display the analysis results. 716 717 @keyword event: The wx event. 718 @type event: wx event 719 """ 720 721 # Show the results viewer in a thread safe way. 722 wx.CallAfter(self.show_results_viewer_safe, warn=True)
723 724
725 - def show_results_viewer_safe(self, warn=False):
726 """Display the analysis results in a thread safe wx.CallAfter call. 727 728 @keyword warn: A flag which if True will cause a message dialog to appear warning about keeping the window open with the execution lock. 729 @type warn: bool 730 """ 731 732 # Throw a warning if the execution lock is on. 733 if warn and status.exec_lock.locked(): 734 dlg = wx.MessageDialog(self, "Leaving the results viewer window open will slow down the calculations.", caption="Warning", style=wx.OK|wx.ICON_EXCLAMATION|wx.STAY_ON_TOP) 735 if status.show_gui: 736 wx.CallAfter(dlg.ShowModal) 737 738 # Create the results viewer window if needed. 739 if not hasattr(self, 'results_viewer'): 740 self.results_viewer = Results_viewer(self) 741 742 # Bring the window to the front. 743 if self.results_viewer.IsShown(): 744 self.results_viewer.Raise() 745 return 746 747 # Open the window. 748 if status.show_gui and not self.results_viewer.IsShown(): 749 self.results_viewer.Show()
750 751
753 """Display the analysis results.""" 754 755 # Show the results viewer in a thread safe way with no warning dialog. 756 wx.CallAfter(self.show_results_viewer_safe, warn=False)
757 758
759 - def show_tree(self, event=None):
760 """Display the molecule, residue, and spin tree window. 761 762 @keyword event: The wx event. 763 @type event: wx event 764 """ 765 766 # Throw a warning if the execution lock is on. 767 if status.exec_lock.locked(): 768 dlg = wx.MessageDialog(self, "Leaving the spin viewer window open will slow down the calculations.", caption="Warning", style=wx.OK|wx.ICON_EXCLAMATION|wx.STAY_ON_TOP) 769 if status.show_gui: 770 dlg.ShowModal() 771 772 # Build the spin view window. 773 if not hasattr(self, 'spin_viewer'): 774 self.spin_viewer = Spin_view_window(None, -1, "", parent=self) 775 776 # Bring the window to the front. 777 if self.spin_viewer.IsShown(): 778 self.spin_viewer.Raise() 779 return 780 781 # Open the window (the GUI flag check is inside the Show method). 782 if not self.spin_viewer.IsShown(): 783 self.spin_viewer.Show(show=status.show_gui)
784 785
786 - def state_load(self, event=None, file_name=None):
787 """Load the program state. 788 789 @keyword event: The wx event. 790 @type event: wx event 791 @keyword file_name: The name of the file to load (for dialogless operation). 792 @type file_name: str 793 """ 794 795 # Execution lock. 796 if status.exec_lock.locked(): 797 return 798 799 # Warning. 800 if not self.analysis.init_state or not ds.is_empty(): 801 # The message. 802 msg = "Loading a saved relax state file will cause all unsaved data to be lost. Are you sure you would to open a save file?" 803 804 # The dialog. 805 if status.show_gui and Question(msg, default=True, size=(400, 150)).ShowModal() == wx.ID_NO: 806 return 807 808 # Open the dialog. 809 if not file_name: 810 dialog = RelaxFileDialog(parent=self, message='Select the relax save state file', defaultFile='state.bz2', wildcard='relax save files (*.bz2;*.gz)|*.bz2;*.gz|All files (*)|*', style=wx.FD_OPEN) 811 812 # Show the dialog and catch if no file has been selected. 813 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 814 # Don't do anything. 815 return 816 817 # The file. 818 file_name = gui_to_str(dialog.get_file()) 819 820 # Yield to allow the cursor to be changed. 821 wx.Yield() 822 823 # Change the cursor to waiting, and freeze the GUI. 824 wx.BeginBusyCursor() 825 self.Freeze() 826 827 # Make sure the GUI returns to normal if a failure occurs. 828 try: 829 # Delete the current tabs. 830 self.analysis.delete_all() 831 832 # Reset the relax data store. 833 reset() 834 835 # The new save file name. 836 self.save_file = file_name 837 838 # Load the relax state. 839 if protected_exec(state.load_state, file_name, verbosity=0): 840 # Update the core of the GUI to match the new data store. 841 self.sync_ds(upload=False) 842 843 # File loading failure. 844 else: 845 # Reset relax to clear any partially loaded data. 846 reset() 847 848 # Reinitialise the GUI data store structure. 849 self.init_data() 850 851 # Reset the cursor, and thaw the GUI. 852 finally: 853 self.Thaw() 854 855 # Turn off the busy cursor. 856 if wx.IsBusy(): 857 wx.EndBusyCursor()
858 859
860 - def state_save(self):
861 """Save the program state.""" 862 863 # Update the data store to match the GUI. 864 self.sync_ds(upload=True) 865 866 # Save the relax state (with save user feedback). 867 try: 868 wx.BeginBusyCursor() 869 state.save_state(self.save_file, verbosity=0, force=True) 870 871 # Sleep a little so the user sees the busy cursor and knows that a save has occurred! 872 sleep(1) 873 874 # Turn off the user feedback. 875 finally: 876 if wx.IsBusy(): 877 wx.EndBusyCursor()
878 879
880 - def sync_ds(self, upload=False):
881 """Synchronise the GUI and the relax data store, both ways. 882 883 This method allows the GUI information to be uploaded into the relax data store, or for the information in the relax data store to be downloaded by the GUI. 884 885 @keyword upload: A flag which if True will cause the GUI to send data to the relax data store. If False, data will be downloaded from the relax data store to update the GUI. 886 @type upload: bool 887 """ 888 889 # Loop over each analysis. 890 for page in self.analysis.analysis_loop(): 891 # Execute the analysis page specific update methods. 892 if hasattr(page, 'sync_ds'): 893 page.sync_ds(upload)
894 895
896 - def uf_call(self, event=None):
897 """Catch the user function call to properly specify the parent window. 898 899 @keyword event: The wx event. 900 @type event: wx event 901 """ 902 903 # The user function ID. 904 uf_id = event.GetId() 905 906 # Get the user function name. 907 name = uf_store.get_uf(uf_id) 908 909 # Call the user function GUI object. 910 uf_store[name](event=event, wx_parent=self)
911 912
913 - def update_status_bar(self):
914 """Update the status bar info.""" 915 916 # Set the current data pipe info. 917 pipe = cdp_name() 918 919 # No data pipe. 920 if pipe == None: 921 pipe = '' 922 923 # The relax information box. 924 info = Info_box() 925 926 # Set the status. 927 wx.CallAfter(self.status_bar.SetStatusText, info.copyright[1], 0) 928 wx.CallAfter(self.status_bar.SetStatusText, "Current data pipe:", 1) 929 wx.CallAfter(self.status_bar.SetStatusText, pipe, 2)
930