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