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