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