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