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