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