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-2013 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 # A printout. 433 text = "\n\nThank you for citing:\n" 434 text += "\n\n%srelaxGUI%s\n\n" % (ansi.relax_prompt, ansi.end) 435 for line in wrap(info.bib['Bieri11'].cite_short(), width): 436 text += line + '\n' 437 text += "\n\n\n%srelax%s\n\n" % (ansi.relax_prompt, ansi.end) 438 for line in wrap(info.bib['dAuvergneGooley08a'].cite_short(), width): 439 text += line + '\n' 440 text += '\n' 441 for line in wrap(info.bib['dAuvergneGooley08b'].cite_short(), width): 442 text += line + '\n' 443 text += '\n' 444 text += '\n' 445 sys.stdout.write(text) 446 447 # Remove the Mac OS X task bar icon. 448 if hasattr(self, 'taskbar_icon'): 449 self.taskbar_icon.Destroy() 450 451 # Terminate the interpreter thread to allow for a cleaner exit. 452 self.interpreter.exit() 453 454 # End the GUI main loop. 455 app = wx.GetApp() 456 app.ExitMainLoop()
457 458
459 - def init_data(self):
460 """Initialise the data used by the GUI interface.""" 461 462 # Temporary data: the save file. 463 self.save_file = None 464 465 # Add the GUI object to the data store, if not present. 466 if not hasattr(ds, 'relax_gui'): 467 ds.relax_gui = Gui()
468 469
470 - def free_file_format_settings(self, event=None):
471 """Open the free file format settings window. 472 473 @keyword event: The wx event. 474 @type event: wx event 475 """ 476 477 # Build the window. 478 win = Free_file_format_window() 479 480 # Show the window. 481 if status.show_gui: 482 win.Show()
483 484
485 - def references(self, event=None):
486 """Display the references relevant for relax. 487 488 @keyword event: The wx event. 489 @type event: wx event 490 """ 491 492 # Build and show the references window. 493 self.references = References(self) 494 if status.show_gui: 495 self.references.Show()
496 497
498 - def relax_manual(self, event=None):
499 """Display the relax manual. 500 501 @keyword event: The wx event. 502 @type event: wx event 503 """ 504 505 # The PDF manual. 506 file = status.install_path + sep+"docs"+sep+"relax.pdf" 507 508 # Test if it exists. 509 if not access(file, F_OK): 510 error_message("The relax manual '%s' cannot be found. Please compile using the scons program." % file) 511 return 512 513 # Open the relax PDF manual using the native PDF reader. 514 open_file(file)
515 516
517 - def reset(self):
518 """Reset the GUI.""" 519 520 # Close some GUI windows, if open. 521 windows = ['pipe_editor', 'relax_prompt', 'results_viewer', 'spin_viewer'] 522 for window in windows: 523 if hasattr(self, window): 524 # Get the object. 525 win_obj = getattr(self, window) 526 527 # Close the window. 528 win_obj.Close() 529 530 # Flush all wx events to make sure the GUI is ready for the next test. 531 wx.Yield() 532 533 # Reset the relax controller. 534 self.controller.reset()
535 536
537 - def run_test_suite(self, event=None, categories=['system', 'unit', 'gui']):
538 """Execute the full test suite. 539 540 @keyword event: The wx event. 541 @type event: wx event 542 @keyword categories: The list of test categories to run, for example ['system', 'unit', 'gui'] for all tests. 543 @type categories: list of str 544 """ 545 546 # Ask if this should be done. 547 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?" 548 if Question(msg, parent=self, size=(400, 150), default=False).ShowModal() == wx.ID_NO: 549 return 550 551 # Set the test suite flag. 552 self.test_suite_flag = True 553 554 # Change the cursor to waiting. 555 wx.BeginBusyCursor() 556 557 # Set a new style to stay on top, refreshing to update the style (needed for Mac OS X and MS Windows). 558 orig_style = self.controller.GetWindowStyle() 559 self.controller.SetWindowStyle(orig_style | wx.STAY_ON_TOP) 560 self.controller.Refresh() 561 562 # Make the relax controller modal so that all other windows are deactivated (to stop users from clicking on things). 563 self.controller.MakeModal(True) 564 565 # Close all open windows. 566 if hasattr(self, 'spin_viewer'): 567 self.spin_viewer.Close() 568 if hasattr(self, 'pipe_editor'): 569 self.pipe_editor.Close() 570 if hasattr(self, 'results_viewer'): 571 self.results_viewer.Close() 572 if hasattr(self, 'relax_prompt'): 573 self.relax_prompt.Close() 574 575 # Reset relax. 576 reset() 577 578 # Show the relax controller. 579 self.show_controller(event) 580 581 # Yield 582 wx.GetApp().Yield(True) 583 584 # Prevent all new GUI elements from being shown. 585 status.show_gui = False 586 587 # Run the tests (with the import here to break a nasty circular import). 588 import test_suite.test_suite_runner 589 runner = test_suite.test_suite_runner.Test_suite_runner([], from_gui=True, categories=categories) 590 runner.run_all_tests() 591 592 # Reactive the GUI. 593 status.show_gui = True 594 595 # Turn off the busy cursor. 596 if wx.IsBusy(): 597 wx.EndBusyCursor() 598 599 # Restore the controller. 600 self.controller.SetWindowStyle(orig_style) 601 self.controller.MakeModal(False) 602 self.controller.Refresh() 603 604 # Unset the test suite flag. 605 self.test_suite_flag = False 606 607 # Set the controller main gauge to 100%. 608 wx.CallAfter(self.controller.main_gauge.SetValue, 100)
609 610
611 - def run_test_suite_gui(self, event=None):
612 """Execute the GUI tests. 613 614 @keyword event: The wx event. 615 @type event: wx event 616 """ 617 618 # Forward the call. 619 self.run_test_suite(event, categories=['gui'])
620 621
622 - def run_test_suite_sys(self, event=None):
623 """Execute the system tests. 624 625 @keyword event: The wx event. 626 @type event: wx event 627 """ 628 629 # Forward the call. 630 self.run_test_suite(event, categories=['system'])
631 632
633 - def run_test_suite_unit(self, event=None):
634 """Execute the unit tests. 635 636 @keyword event: The wx event. 637 @type event: wx event 638 """ 639 640 # Forward the call. 641 self.run_test_suite(event, categories=['unit'])
642 643
644 - def show_controller(self, event=None):
645 """Display the relax controller window. 646 647 @keyword event: The wx event. 648 @type event: wx event 649 """ 650 651 # Bring the window to the front. 652 if self.controller.IsShown(): 653 self.controller.Raise() 654 return 655 656 # Open the window. 657 if status.show_gui: 658 self.controller.Show()
659 660
661 - def show_pipe_editor(self, event=None):
662 """Display the data pipe editor window. 663 664 @keyword event: The wx event. 665 @type event: wx event 666 """ 667 668 # Throw a warning if the execution lock is on. 669 if status.exec_lock.locked(): 670 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) 671 if status.show_gui: 672 dlg.ShowModal() 673 674 # Build the pipe editor if needed. 675 if not hasattr(self, 'pipe_editor'): 676 self.pipe_editor = Pipe_editor(gui=self) 677 678 # Bring the window to the front. 679 if self.pipe_editor.IsShown(): 680 self.pipe_editor.Raise() 681 return 682 683 # Open the window. 684 if status.show_gui and not self.pipe_editor.IsShown(): 685 self.pipe_editor.Show() 686 687 # Update the grid. 688 self.pipe_editor.update_grid() 689 self.pipe_editor.activate() 690 691 # 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). 692 self.pipe_editor.observer_setup(register=True)
693 694
695 - def show_prompt(self, event=None):
696 """Display the relax prompt window. 697 698 @keyword event: The wx event. 699 @type event: wx event 700 """ 701 702 # Build the relax prompt if needed. 703 if not hasattr(self, 'relax_prompt'): 704 self.relax_prompt = Prompt(None, -1, "", parent=self) 705 706 # Bring the window to the front. 707 if self.relax_prompt.IsShown(): 708 self.relax_prompt.Raise() 709 return 710 711 # Open the window. 712 if status.show_gui: 713 self.relax_prompt.Show()
714 715
716 - def show_results_viewer(self, event=None):
717 """Display the analysis results. 718 719 @keyword event: The wx event. 720 @type event: wx event 721 """ 722 723 # Show the results viewer in a thread safe way. 724 wx.CallAfter(self.show_results_viewer_safe, warn=True)
725 726
727 - def show_results_viewer_safe(self, warn=False):
728 """Display the analysis results in a thread safe wx.CallAfter call. 729 730 @keyword warn: A flag which if True will cause a message dialog to appear warning about keeping the window open with the execution lock. 731 @type warn: bool 732 """ 733 734 # Throw a warning if the execution lock is on. 735 if warn and status.exec_lock.locked(): 736 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) 737 if status.show_gui: 738 wx.CallAfter(dlg.ShowModal) 739 740 # Create the results viewer window if needed. 741 if not hasattr(self, 'results_viewer'): 742 self.results_viewer = Results_viewer(self) 743 744 # Bring the window to the front. 745 if self.results_viewer.IsShown(): 746 self.results_viewer.Raise() 747 return 748 749 # Open the window. 750 if status.show_gui and not self.results_viewer.IsShown(): 751 self.results_viewer.Show()
752 753
755 """Display the analysis results.""" 756 757 # Show the results viewer in a thread safe way with no warning dialog. 758 wx.CallAfter(self.show_results_viewer_safe, warn=False)
759 760
761 - def show_tree(self, event=None):
762 """Display the molecule, residue, and spin tree window. 763 764 @keyword event: The wx event. 765 @type event: wx event 766 """ 767 768 # Throw a warning if the execution lock is on. 769 if status.exec_lock.locked(): 770 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) 771 if status.show_gui: 772 dlg.ShowModal() 773 774 # Build the spin view window. 775 if not hasattr(self, 'spin_viewer'): 776 self.spin_viewer = Spin_view_window(None, -1, "", parent=self) 777 778 # Bring the window to the front. 779 if self.spin_viewer.IsShown(): 780 self.spin_viewer.Raise() 781 return 782 783 # Open the window (the GUI flag check is inside the Show method). 784 if status.show_gui and not self.spin_viewer.IsShown(): 785 self.spin_viewer.Show()
786 787
788 - def state_load(self, event=None, file_name=None):
789 """Load the program state. 790 791 @keyword event: The wx event. 792 @type event: wx event 793 @keyword file_name: The name of the file to load (for dialogless operation). 794 @type file_name: str 795 """ 796 797 # Execution lock. 798 if status.exec_lock.locked(): 799 return 800 801 # Warning. 802 if not self.analysis.init_state or not ds.is_empty(): 803 # The message. 804 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?" 805 806 # The dialog. 807 if status.show_gui and Question(msg, default=True, size=(400, 150)).ShowModal() == wx.ID_NO: 808 return 809 810 # Open the dialog. 811 if not file_name: 812 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) 813 814 # Show the dialog and catch if no file has been selected. 815 if status.show_gui and dialog.ShowModal() != wx.ID_OK: 816 # Don't do anything. 817 return 818 819 # The file. 820 file_name = gui_to_str(dialog.get_file()) 821 822 # Yield to allow the cursor to be changed. 823 wx.Yield() 824 825 # Change the cursor to waiting, and freeze the GUI. 826 wx.BeginBusyCursor() 827 self.Freeze() 828 829 # Make sure the GUI returns to normal if a failure occurs. 830 try: 831 # Delete the current tabs. 832 self.analysis.delete_all() 833 834 # Reset the relax data store. 835 reset() 836 837 # The new save file name. 838 self.save_file = file_name 839 840 # Load the relax state. 841 if protected_exec(state.load_state, file_name, verbosity=0): 842 # Update the core of the GUI to match the new data store. 843 self.sync_ds(upload=False) 844 845 # File loading failure. 846 else: 847 # Reset relax to clear any partially loaded data. 848 reset() 849 850 # Reinitialise the GUI data store structure. 851 self.init_data() 852 853 # Reset the cursor, and thaw the GUI. 854 finally: 855 self.Thaw() 856 857 # Turn off the busy cursor. 858 if wx.IsBusy(): 859 wx.EndBusyCursor()
860 861
862 - def state_save(self):
863 """Save the program state.""" 864 865 # Update the data store to match the GUI. 866 self.sync_ds(upload=True) 867 868 # Save the relax state (with save user feedback). 869 try: 870 wx.BeginBusyCursor() 871 state.save_state(self.save_file, verbosity=0, force=True) 872 873 # Sleep a little so the user sees the busy cursor and knows that a save has occurred! 874 sleep(1) 875 876 # Turn off the user feedback. 877 finally: 878 if wx.IsBusy(): 879 wx.EndBusyCursor()
880 881
882 - def sync_ds(self, upload=False):
883 """Synchronise the GUI and the relax data store, both ways. 884 885 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. 886 887 @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. 888 @type upload: bool 889 """ 890 891 # Loop over each analysis. 892 for page in self.analysis.analysis_loop(): 893 # Execute the analysis page specific update methods. 894 if hasattr(page, 'sync_ds'): 895 page.sync_ds(upload)
896 897
898 - def uf_call(self, event=None):
899 """Catch the user function call to properly specify the parent window. 900 901 @keyword event: The wx event. 902 @type event: wx event 903 """ 904 905 # The user function ID. 906 uf_id = event.GetId() 907 908 # Get the user function name. 909 name = uf_store.get_uf(uf_id) 910 911 # Call the user function GUI object. 912 uf_store[name](event=event, wx_parent=self)
913 914
915 - def update_status_bar(self):
916 """Update the status bar info.""" 917 918 # Set the current data pipe info. 919 pipe = cdp_name() 920 921 # No data pipe. 922 if pipe == None: 923 pipe = '' 924 925 # Set the status. 926 wx.CallAfter(self.status_bar.SetStatusText, "(C) 2001-2013 the relax development team", 0) 927 wx.CallAfter(self.status_bar.SetStatusText, "Current data pipe:", 1) 928 wx.CallAfter(self.status_bar.SetStatusText, pipe, 2)
929