1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 """Main module for the relax graphical user interface."""
26
27
28 from os import F_OK, access, getcwd, sep
29 import platform
30 from re import search
31 import sys
32 from time import sleep
33 from warnings import warn
34 import webbrowser
35 import wx
36
37
38 from data_store import Relax_data_store; ds = Relax_data_store()
39 from data_store.gui import Gui
40 import dep_check
41 from graphics import IMAGE_PATH, fetch_icon
42 from gui.about import About_relax
43 from gui.analyses import Analysis_controller
44 from gui.spin_viewer.frame import Spin_view_window
45 from gui.controller import Controller
46 from gui.export_bmrb import Export_bmrb_window
47 from gui.filedialog import RelaxDirDialog, RelaxFileDialog
48 from gui.fonts import font
49 from gui.icons import Relax_icons
50 from gui.interpreter import Interpreter
51 from gui.menu import Menu
52 from gui.message import error_message, Question
53 from gui.misc import bitmap_setup, gui_raise, open_file, protected_exec
54 from gui.pipe_editor import Pipe_editor
55 from gui.references import References
56 from gui.relax_prompt import Prompt
57 from gui.results_viewer import Results_viewer
58 from gui.components.free_file_format import Free_file_format_window
59 from gui.string_conv import gui_to_str
60 from gui.uf_objects import Uf_storage; uf_store = Uf_storage()
61 from info import Info_box
62 from lib.errors import RelaxNoPipeError
63 from lib.warnings import RelaxWarning
64 from lib.io import io_streams_restore
65 from pipe_control import state
66 from pipe_control.pipes import cdp_name
67 from pipe_control.reset import reset
68 from pipe_control.system import pwd
69 from status import Status; status = Status()
70 from version import repo_head, version
71
72
73
74 TB_FILE_NEW = wx.NewId()
75 TB_FILE_CLOSE = wx.NewId()
76 TB_FILE_CLOSE_ALL = wx.NewId()
77 TB_FILE_CWD = wx.NewId()
78 TB_FILE_OPEN = wx.NewId()
79 TB_FILE_SAVE = wx.NewId()
80 TB_FILE_SAVE_AS = wx.NewId()
81 TB_VIEW_CONTROLLER = wx.NewId()
82 TB_VIEW_SPIN_VIEW = wx.NewId()
83 TB_VIEW_RESULTS = wx.NewId()
84 TB_VIEW_PIPE_EDIT = wx.NewId()
85 TB_VIEW_PROMPT = wx.NewId()
86
87
88
89 -class Main(wx.Frame):
90 """The main GUI class."""
91
92
93 min_width = 1000
94 min_height = 600
95
96 - def __init__(self, parent=None, id=-1, title=""):
97 """Initialise the main relax GUI frame."""
98
99
100 status.wx_info = {}
101 status.wx_info["version"] = wx.__version__.split('.')
102 status.wx_info["minor"] = "%s.%s" % (status.wx_info["version"][0], status.wx_info["version"][1])
103 status.wx_info["os"] = sys.platform
104 status.wx_info["build"] = None
105 if search('gtk2', wx.version()):
106 status.wx_info["build"] = 'gtk'
107 elif search('cocoa', wx.version()):
108 status.wx_info["build"] = 'cocoa'
109 elif search('mac-unicode', wx.version()):
110 status.wx_info["build"] = 'carbon'
111 status.wx_info["full"] = None
112 if status.wx_info["build"]:
113 status.wx_info["full"] = "%s-%s" % (status.wx_info["os"], status.wx_info["build"])
114
115
116 self.test_suite_flag = False
117
118
119 style = wx.DEFAULT_FRAME_STYLE
120 if not status.debug and status.wx_info["os"] != 'darwin':
121 style = style | wx.MAXIMIZE
122
123
124 super(Main, self).__init__(parent=parent, id=id, title=title, style=style)
125
126
127 if not status.debug and status.wx_info["os"] != 'darwin':
128 self.Maximize()
129
130
131 font.setup()
132
133
134 relax_icons = Relax_icons()
135 relax_icons.setup()
136 self.SetIcons(relax_icons)
137
138
139 self.launch_dir = getcwd()
140
141
142 self.Layout()
143 self.SetSize((self.min_width, self.min_height))
144 self.SetMinSize((self.min_width, self.min_height))
145 self.Centre()
146
147
148 self.analysis = Analysis_controller(self)
149
150
151 self.calc_threads = []
152
153
154 self.init_data()
155
156
157 self.menu = Menu(self)
158
159
160 self.build_toolbar()
161
162
163 self.controller = Controller(self)
164
165
166 if version == "repository commit":
167 win_title = "relax %s %s" % (version, repo_head)
168 else:
169 win_title = "relax %s" % version
170 self.SetTitle(win_title)
171
172
173 self.status_bar = self.CreateStatusBar(4, 0)
174 self.status_bar.SetStatusWidths([-4, -4, -1, -2])
175 self.update_status_bar()
176
177
178 self.add_start_screen()
179
180
181 self.Bind(wx.EVT_CLOSE, self.exit_gui)
182
183
184 self.interpreter = Interpreter()
185
186
187 status.observers.pipe_alteration.register('status bar', self.update_status_bar, method_name='update_status_bar')
188 status.observers.system_cwd_path.register('status bar', self.update_status_bar, method_name='update_status_bar')
189 status.observers.result_file.register('gui', self.show_results_viewer_no_warn, method_name='show_results_viewer_no_warn')
190 status.observers.exec_lock.register('gui', self.enable, method_name='enab')
191
192
193 self.analysis.load_from_store()
194
195
196 - def about_relax(self, event=None):
197 """The about message for relax.
198
199 @keyword event: The wx event.
200 @type event: wx event
201 """
202
203
204 dialog = About_relax(None, -1)
205
206
207 if status.show_gui:
208 dialog.Show()
209
210
211 - def action_export_bmrb(self, event=None):
212 """Export the contents of the current data pipe for BMRB deposition.
213
214 @keyword event: The wx event.
215 @type event: wx event
216 """
217
218
219 if not cdp_name():
220 gui_raise(RelaxNoPipeError())
221 return
222
223
224 Export_bmrb_window(self)
225
226
227 - def action_state_save(self, event=None):
228 """Save the program state.
229
230 @keyword event: The wx event.
231 @type event: wx event
232 """
233
234
235 if not self.save_file:
236 self.action_state_save_as(event)
237 return
238
239
240 self.state_save()
241
242
243 - def action_state_save_as(self, event=None):
244 """Save the program state with file name selection.
245
246 @keyword event: The wx event.
247 @type event: wx event
248 """
249
250
251 dialog = RelaxFileDialog(parent=self, message='Select the relax save state file', defaultFile='state.bz2', wildcard='relax save file (*.bz2)|*.bz2', style=wx.FD_SAVE)
252
253
254 if status.show_gui and dialog.ShowModal() != wx.ID_OK:
255
256 return
257
258
259 file_name = dialog.get_file()
260
261
262 self.save_file = file_name
263
264
265 self.state_save()
266
267
269 """Create a start screen for the main window when no analyses exist."""
270
271
272 sizer = wx.BoxSizer(wx.VERTICAL)
273 self.SetSizer(sizer)
274
275
276 image = wx.StaticBitmap(self, -1, bitmap_setup(IMAGE_PATH+'ulysses_shadowless_400x168.png'))
277 sizer.AddStretchSpacer()
278 sizer.Add(image, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
279 sizer.AddStretchSpacer()
280
281
282 if not dep_check.wx_stable:
283 text = [
284 "wxPython-Phoenix version %s.%s.%s detected." % (wx.VERSION[0], wx.VERSION[1], wx.VERSION[2]),
285 "This version of Phoenix is not stable and relax support is experimental.",
286 "Not all features of the GUI may be available or functional.",
287 "Please use wxPython-Phoenix version >= 4.1.0 or \"Classic\" instead - otherwise use at your own risk."
288 ]
289 for i in range(len(text)):
290 element = wx.StaticText(self, -1, text[i])
291 element.SetFont(font.roman_font_18)
292 element.SetForegroundColour("red")
293 sizer.Add(element, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE, 0)
294 sizer.AddStretchSpacer()
295 warn(RelaxWarning(" ".join(text)))
296
297
298 self.Layout()
299 self.Refresh()
300
301
303 """Create the toolbar."""
304
305
306 self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL|wx.TB_FLAT)
307
308
309 if dep_check.wx_classic:
310 self.toolbar.AddLabelTool(TB_FILE_NEW, "New analysis", wx.Bitmap(fetch_icon('oxygen.actions.document-new', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="New analysis")
311 else:
312 self.toolbar.AddTool(TB_FILE_NEW, "New analysis", wx.Bitmap(fetch_icon('oxygen.actions.document-new', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="New analysis")
313 self.Bind(wx.EVT_TOOL, self.analysis.menu_new, id=TB_FILE_NEW)
314
315
316 if dep_check.wx_classic:
317 self.toolbar.AddLabelTool(TB_FILE_CLOSE, "Close analysis", wx.Bitmap(fetch_icon('oxygen.actions.document-close', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Close analysis")
318 else:
319 self.toolbar.AddTool(TB_FILE_CLOSE, "Close analysis", wx.Bitmap(fetch_icon('oxygen.actions.document-close', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Close analysis")
320 self.Bind(wx.EVT_TOOL, self.analysis.menu_close, id=TB_FILE_CLOSE)
321
322
323 if dep_check.wx_classic:
324 self.toolbar.AddLabelTool(TB_FILE_CLOSE_ALL, "Close all analyses", wx.Bitmap(fetch_icon('oxygen.actions.dialog-close', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Close all analyses")
325 else:
326 self.toolbar.AddTool(TB_FILE_CLOSE_ALL, "Close all analyses", wx.Bitmap(fetch_icon('oxygen.actions.dialog-close', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Close all analyses")
327 self.Bind(wx.EVT_TOOL, self.analysis.menu_close_all, id=TB_FILE_CLOSE_ALL)
328
329
330 self.toolbar.AddSeparator()
331
332
333 if dep_check.wx_classic:
334 self.toolbar.AddLabelTool(TB_FILE_CWD, "Change working directory", wx.Bitmap(fetch_icon('oxygen.places.folder-favorites', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Change working directory")
335 else:
336 self.toolbar.AddTool(TB_FILE_CWD, "Change working directory", wx.Bitmap(fetch_icon('oxygen.places.folder-favorites', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Change working directory")
337 self.Bind(wx.EVT_TOOL, self.system_cwd, id=TB_FILE_CWD)
338
339
340 if dep_check.wx_classic:
341 self.toolbar.AddLabelTool(TB_FILE_OPEN, "Open relax state", wx.Bitmap(fetch_icon('oxygen.actions.document-open', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Open relax state")
342 else:
343 self.toolbar.AddTool(TB_FILE_OPEN, "Open relax state", wx.Bitmap(fetch_icon('oxygen.actions.document-open', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Open relax state")
344 self.Bind(wx.EVT_TOOL, self.state_load, id=TB_FILE_OPEN)
345
346
347 if dep_check.wx_classic:
348 self.toolbar.AddLabelTool(TB_FILE_SAVE, "Save relax state", wx.Bitmap(fetch_icon('oxygen.actions.document-save', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Save relax state")
349 else:
350 self.toolbar.AddTool(TB_FILE_SAVE, "Save relax state", wx.Bitmap(fetch_icon('oxygen.actions.document-save', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Save relax state")
351 self.Bind(wx.EVT_TOOL, self.action_state_save, id=TB_FILE_SAVE)
352
353
354 if dep_check.wx_classic:
355 self.toolbar.AddLabelTool(TB_FILE_SAVE_AS, "Save as", wx.Bitmap(fetch_icon('oxygen.actions.document-save-as', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Save as")
356 else:
357 self.toolbar.AddTool(TB_FILE_SAVE_AS, "Save as", wx.Bitmap(fetch_icon('oxygen.actions.document-save-as', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Save as")
358 self.Bind(wx.EVT_TOOL, self.action_state_save_as, id=TB_FILE_SAVE_AS)
359
360
361 self.toolbar.AddSeparator()
362
363
364 if dep_check.wx_classic:
365 self.toolbar.AddLabelTool(TB_VIEW_CONTROLLER, "Controller", wx.Bitmap(fetch_icon('oxygen.apps.preferences-system-performance', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="relax controller")
366 else:
367 self.toolbar.AddTool(TB_VIEW_CONTROLLER, "Controller", wx.Bitmap(fetch_icon('oxygen.apps.preferences-system-performance', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="relax controller")
368 self.Bind(wx.EVT_TOOL, self.show_controller, id=TB_VIEW_CONTROLLER)
369
370
371 if dep_check.wx_classic:
372 self.toolbar.AddLabelTool(TB_VIEW_SPIN_VIEW, "Spin viewer", wx.Bitmap(fetch_icon('relax.spin', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Spin viewer window")
373 else:
374 self.toolbar.AddTool(TB_VIEW_SPIN_VIEW, "Spin viewer", wx.Bitmap(fetch_icon('relax.spin', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Spin viewer window")
375 self.Bind(wx.EVT_TOOL, self.show_tree, id=TB_VIEW_SPIN_VIEW)
376
377
378 if dep_check.wx_classic:
379 self.toolbar.AddLabelTool(TB_VIEW_RESULTS, "Results viewer", wx.Bitmap(fetch_icon('oxygen.actions.view-statistics', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Results viewer window")
380 else:
381 self.toolbar.AddTool(TB_VIEW_RESULTS, "Results viewer", wx.Bitmap(fetch_icon('oxygen.actions.view-statistics', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Results viewer window")
382 self.Bind(wx.EVT_TOOL, self.show_results_viewer, id=TB_VIEW_RESULTS)
383
384
385 if dep_check.wx_classic:
386 self.toolbar.AddLabelTool(TB_VIEW_PIPE_EDIT, "Data pipe editor", wx.Bitmap(fetch_icon('relax.pipe', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Data pipe editor")
387 else:
388 self.toolbar.AddTool(TB_VIEW_PIPE_EDIT, "Data pipe editor", wx.Bitmap(fetch_icon('relax.pipe', "22x22"), wx.BITMAP_TYPE_ANY), shortHelp="Data pipe editor")
389 self.Bind(wx.EVT_TOOL, self.show_pipe_editor, id=TB_VIEW_PIPE_EDIT)
390
391
392 if dep_check.wx_classic:
393 self.toolbar.AddLabelTool(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")
394 else:
395 self.toolbar.AddTool(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")
396 self.Bind(wx.EVT_TOOL, self.show_prompt, id=TB_VIEW_PROMPT)
397
398
399 self.toolbar.Realize()
400
401
402 - def close_windows(self):
403 """Throw a warning to close all of the non-essential windows when execution is locked.
404
405 This is to speed up the calculations by avoiding window updates.
406 """
407
408
409 win_list = []
410
411
412 if hasattr(self, 'spin_viewer') and self.spin_viewer.IsShown():
413 win_list.append('The spin viewer window')
414
415
416 if hasattr(self, 'pipe_editor') and self.pipe_editor.IsShown():
417 win_list.append('The data pipe editor window')
418
419
420 if hasattr(self, 'results_viewer') and self.results_viewer.IsShown():
421 win_list.append('The results viewer window')
422
423
424 if not len(win_list):
425 return
426
427
428 text = "The following windows are currently open:\n\n"
429 for win in win_list:
430 text = "%s\t%s.\n" % (text, win)
431 text = text + "\nClosing these will significantly speed up the calculations."
432
433
434 dlg = wx.MessageDialog(self, text, caption="Close windows", style=wx.OK|wx.ICON_EXCLAMATION|wx.STAY_ON_TOP)
435 if status.show_gui:
436 dlg.ShowModal()
437
438
439 else:
440 sys.stderr.write(text)
441 sys.stderr.flush()
442
443
445 """Write an email to the relax mailing-list using the standard mailing program.
446
447 @keyword event: The wx event.
448 @type event: wx event
449 """
450
451 webbrowser.open_new('mailto:relax-users@gna.org')
452
453
455 """Enable and disable certain parts of the main window with the execution lock."""
456
457
458 enable = False
459 if not status.exec_lock.locked():
460 enable = True
461
462
463 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_NEW, enable)
464 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_CLOSE, enable)
465 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_CLOSE_ALL, enable)
466 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_CWD, enable)
467 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_OPEN, enable)
468 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_SAVE, enable)
469 wx.CallAfter(self.toolbar.EnableTool, TB_FILE_SAVE_AS, enable)
470
471
472 - def exit_gui(self, event=None):
473 """Catch the main window closure and perform the exit procedure.
474
475 @keyword event: The wx event.
476 @type event: wx event
477 """
478
479
480 doexit = wx.ID_YES
481 if status.show_gui and not ds.is_empty():
482 doexit = Question('Are you sure you would like to quit relax? All unsaved data will be lost.', title='Exit relax', default=True).ShowModal()
483
484
485 if doexit == wx.ID_YES:
486
487 io_streams_restore(verbosity=0)
488
489
490 info = Info_box()
491
492
493 if platform.uname()[0] in ['Windows', 'Microsoft']:
494 width = 80
495 else:
496 width = 100
497
498
499 if hasattr(self, 'taskbar_icon'):
500 self.taskbar_icon.Destroy()
501
502
503 self.interpreter.exit()
504
505
506 app = wx.GetApp()
507 app.ExitMainLoop()
508
509
510 - def init_data(self):
511 """Initialise the data used by the GUI interface."""
512
513
514 self.save_file = None
515 self.system_cwd_path = pwd(verbose=False)
516
517
518 if not hasattr(ds, 'relax_gui'):
519 ds.relax_gui = Gui()
520
521
523 """Open the free file format settings window.
524
525 @keyword event: The wx event.
526 @type event: wx event
527 """
528
529
530 win = Free_file_format_window()
531
532
533 if status.show_gui:
534 win.Show()
535
536
537 - def references(self, event=None):
538 """Display the references relevant for relax.
539
540 @keyword event: The wx event.
541 @type event: wx event
542 """
543
544
545 self.references = References(self)
546 if status.show_gui:
547 self.references.Show()
548
549
550 - def relax_manual(self, event=None):
551 """Display the relax manual.
552
553 @keyword event: The wx event.
554 @type event: wx event
555 """
556
557
558 file = status.install_path + sep+"docs"+sep+"relax.pdf"
559
560
561 if not access(file, F_OK):
562 error_message("The relax manual '%s' cannot be found. Please compile using the scons program." % file)
563 return
564
565
566 open_file(file)
567
568
570 """Reset the GUI."""
571
572
573 windows = ['pipe_editor', 'relax_prompt', 'results_viewer', 'spin_viewer']
574 for window in windows:
575 if hasattr(self, window):
576
577 win_obj = getattr(self, window)
578
579
580 win_obj.Close()
581
582
583 wx.Yield()
584
585
586 self.controller.reset()
587
588
589 - def run_test_suite(self, event=None, categories=['system', 'unit', 'gui', 'verification']):
590 """Execute the full test suite.
591
592 @keyword event: The wx event.
593 @type event: wx event
594 @keyword categories: The list of test categories to run, for example ['system', 'unit', 'gui', 'verification'] for all tests.
595 @type categories: list of str
596 """
597
598
599 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?"
600 if Question(msg, parent=self, size=(400, 150), default=False).ShowModal() == wx.ID_NO:
601 return
602
603
604 self.test_suite_flag = True
605
606
607 wx.BeginBusyCursor()
608
609
610 orig_style = self.controller.GetWindowStyle()
611 self.controller.SetWindowStyle(orig_style | wx.STAY_ON_TOP)
612 self.controller.Refresh()
613
614
615 self.controller.MakeModal(True)
616
617
618 if hasattr(self, 'spin_viewer'):
619 self.spin_viewer.Close()
620 if hasattr(self, 'pipe_editor'):
621 self.pipe_editor.Close()
622 if hasattr(self, 'results_viewer'):
623 self.results_viewer.Close()
624 if hasattr(self, 'relax_prompt'):
625 self.relax_prompt.Close()
626
627
628 reset()
629
630
631 self.show_controller(event)
632
633
634 wx.GetApp().Yield(True)
635
636
637 status.show_gui = False
638
639
640 import test_suite.test_suite_runner
641 runner = test_suite.test_suite_runner.Test_suite_runner([], from_gui=True, categories=categories)
642 runner.run_all_tests()
643
644
645 status.show_gui = True
646
647
648 if wx.IsBusy():
649 wx.EndBusyCursor()
650
651
652 self.controller.SetWindowStyle(orig_style)
653 self.controller.MakeModal(False)
654 self.controller.Refresh()
655
656
657 self.test_suite_flag = False
658
659
660 wx.CallAfter(self.controller.main_gauge.SetValue, 100)
661
662
663 - def run_test_suite_gui(self, event=None):
664 """Execute the GUI tests.
665
666 @keyword event: The wx event.
667 @type event: wx event
668 """
669
670
671 self.run_test_suite(event, categories=['gui'])
672
673
674 - def run_test_suite_sys(self, event=None):
675 """Execute the system tests.
676
677 @keyword event: The wx event.
678 @type event: wx event
679 """
680
681
682 self.run_test_suite(event, categories=['system'])
683
684
685 - def run_test_suite_unit(self, event=None):
686 """Execute the unit tests.
687
688 @keyword event: The wx event.
689 @type event: wx event
690 """
691
692
693 self.run_test_suite(event, categories=['unit'])
694
695
696 - def run_test_suite_verification(self, event=None):
697 """Execute the verification tests.
698
699 @keyword event: The wx event.
700 @type event: wx event
701 """
702
703
704 self.run_test_suite(event, categories=['verification'])
705
706
707 - def show_controller(self, event=None):
708 """Display the relax controller window.
709
710 @keyword event: The wx event.
711 @type event: wx event
712 """
713
714
715 if self.controller.IsShown():
716 self.controller.Raise()
717 return
718
719
720 if status.show_gui:
721 self.controller.Show()
722
723
724 - def show_pipe_editor(self, event=None):
725 """Display the data pipe editor window.
726
727 @keyword event: The wx event.
728 @type event: wx event
729 """
730
731
732 if status.exec_lock.locked():
733 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)
734 if status.show_gui:
735 dlg.ShowModal()
736
737
738 if not hasattr(self, 'pipe_editor'):
739 self.pipe_editor = Pipe_editor(gui=self)
740
741
742 if self.pipe_editor.IsShown():
743 self.pipe_editor.Raise()
744 return
745
746
747 if status.show_gui and not self.pipe_editor.IsShown():
748 self.pipe_editor.Show()
749
750
751 self.pipe_editor.update_grid()
752 self.pipe_editor.activate()
753
754
755 self.pipe_editor.observer_setup(register=True)
756
757
758 - def show_prompt(self, event=None):
759 """Display the relax prompt window.
760
761 @keyword event: The wx event.
762 @type event: wx event
763 """
764
765
766 if not hasattr(self, 'relax_prompt'):
767 self.relax_prompt = Prompt(None, -1, "", parent=self)
768
769
770 if self.relax_prompt.IsShown():
771 self.relax_prompt.Raise()
772 return
773
774
775 if status.show_gui:
776 self.relax_prompt.Show()
777
778
779 - def show_results_viewer(self, event=None):
780 """Display the analysis results.
781
782 @keyword event: The wx event.
783 @type event: wx event
784 """
785
786
787 wx.CallAfter(self.show_results_viewer_safe, warn=True)
788
789
790 - def show_results_viewer_safe(self, warn=False):
791 """Display the analysis results in a thread safe wx.CallAfter call.
792
793 @keyword warn: A flag which if True will cause a message dialog to appear warning about keeping the window open with the execution lock.
794 @type warn: bool
795 """
796
797
798 if warn and status.exec_lock.locked():
799 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)
800 if status.show_gui:
801 wx.CallAfter(dlg.ShowModal)
802
803
804 if not hasattr(self, 'results_viewer'):
805 self.results_viewer = Results_viewer(self)
806
807
808 if self.results_viewer.IsShown():
809 self.results_viewer.Raise()
810 return
811
812
813 if status.show_gui and not self.results_viewer.IsShown():
814 self.results_viewer.Show()
815
816
818 """Display the analysis results."""
819
820
821 wx.CallAfter(self.show_results_viewer_safe, warn=False)
822
823
824 - def show_tree(self, event=None):
825 """Display the molecule, residue, and spin tree window.
826
827 @keyword event: The wx event.
828 @type event: wx event
829 """
830
831
832 if status.exec_lock.locked():
833 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)
834 if status.show_gui:
835 dlg.ShowModal()
836
837
838 if not hasattr(self, 'spin_viewer'):
839 self.spin_viewer = Spin_view_window(None, -1, "", parent=self)
840
841
842 if self.spin_viewer.IsShown():
843 self.spin_viewer.Raise()
844 return
845
846
847 if not self.spin_viewer.IsShown():
848 self.spin_viewer.Show(show=status.show_gui)
849
850
851 - def state_load(self, event=None, file_name=None):
852 """Load the program state.
853
854 @keyword event: The wx event.
855 @type event: wx event
856 @keyword file_name: The name of the file to load (for dialogless operation).
857 @type file_name: str
858 """
859
860
861 if status.exec_lock.locked():
862 return
863
864
865 if not self.analysis.init_state or not ds.is_empty():
866
867 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?"
868
869
870 if status.show_gui and Question(msg, default=True, size=(400, 150)).ShowModal() == wx.ID_NO:
871 return
872
873
874 if not file_name:
875 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)
876
877
878 if status.show_gui and dialog.ShowModal() != wx.ID_OK:
879
880 return
881
882
883 file_name = gui_to_str(dialog.get_file())
884
885
886 wx.Yield()
887
888
889 wx.BeginBusyCursor()
890 self.Freeze()
891
892
893 try:
894
895 self.analysis.delete_all()
896
897
898 reset()
899
900
901 self.save_file = file_name
902
903
904 if protected_exec(state.load_state, file_name, verbosity=0):
905
906 self.sync_ds(upload=False)
907
908
909 else:
910
911 reset()
912
913
914 self.init_data()
915
916
917 finally:
918 self.Thaw()
919
920
921 if wx.IsBusy():
922 wx.EndBusyCursor()
923
924
925 - def state_save(self):
926 """Save the program state."""
927
928
929 self.sync_ds(upload=True)
930
931
932 try:
933 wx.BeginBusyCursor()
934 state.save_state(self.save_file, verbosity=0, force=True)
935
936
937 sleep(1)
938
939
940 finally:
941 if wx.IsBusy():
942 wx.EndBusyCursor()
943
944
945 - def sync_ds(self, upload=False):
946 """Synchronise the GUI and the relax data store, both ways.
947
948 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.
949
950 @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.
951 @type upload: bool
952 """
953
954
955 for page in self.analysis.analysis_loop():
956
957 if hasattr(page, 'sync_ds'):
958 page.sync_ds(upload)
959
960
961 - def system_cwd(self, event=None):
962 """Change the system current working directory.
963
964 @keyword event: The wx event.
965 @type event: wx event
966 """
967
968
969 dialog = RelaxDirDialog(parent=self, message="Select working directory", defaultPath=wx.EmptyString, style=wx.DD_CHANGE_DIR)
970
971
972 if status.show_gui and dialog.ShowModal() != wx.ID_OK:
973
974 return
975
976
977 self.system_cwd_path = dialog.get_path()
978
979
980 self.update_status_bar()
981
982
983 try:
984 wx.BeginBusyCursor()
985
986
987 sleep(1)
988
989
990 finally:
991 if wx.IsBusy():
992 wx.EndBusyCursor()
993
994
995 - def uf_call(self, event=None):
996 """Catch the user function call to properly specify the parent window.
997
998 @keyword event: The wx event.
999 @type event: wx event
1000 """
1001
1002
1003 uf_id = event.GetId()
1004
1005
1006 name = uf_store.get_uf(uf_id)
1007
1008
1009 uf_store[name](event=event, wx_parent=self)
1010
1011
1013 """Update the status bar info."""
1014
1015
1016 pipe = cdp_name()
1017
1018
1019 if pipe == None:
1020 pipe = ''
1021
1022
1023 self.system_cwd_path = pwd(verbose=False)
1024
1025
1026 info = Info_box()
1027
1028
1029 wx.CallAfter(self.status_bar.SetStatusText, info.copyright_short, 0)
1030 wx.CallAfter(self.status_bar.SetStatusText, self.system_cwd_path, 1)
1031 wx.CallAfter(self.status_bar.SetStatusText, "Data pipe:", 2)
1032 wx.CallAfter(self.status_bar.SetStatusText, pipe, 3)
1033