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