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