1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21   
 22   
 23  """Module for the analysis selection wizard.""" 
 24   
 25   
 26  from os import sep 
 27  from time import asctime, localtime 
 28  import wx 
 29  from wx.lib import buttons 
 30   
 31   
 32  from graphics import ANALYSIS_IMAGE_PATH, IMAGE_PATH, WIZARD_IMAGE_PATH 
 33  from gui.input_elements.value import Value 
 34  from gui.misc import bitmap_setup 
 35  from gui.string_conv import gui_to_str, str_to_gui 
 36  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 37  from gui.wizards.wiz_objects import Wiz_page, Wiz_window 
 38  from lib.text.gui import r1, r2 
 39   
 40   
 41   
 42  BUTTON_ID_NOE = wx.NewId() 
 43  BUTTON_ID_R1 = wx.NewId() 
 44  BUTTON_ID_R2 = wx.NewId() 
 45  BUTTON_ID_MF = wx.NewId() 
 46  BUTTON_ID_RELAX_DISP = wx.NewId() 
 47  BUTTON_ID_CONSIST_TEST = wx.NewId() 
 48  BUTTON_ID_CUSTOM = wx.NewId() 
 49  BUTTON_ID_RESERVED = wx.NewId() 
 50   
 51   
 52   
 54      """The analysis selection wizard.""" 
 55   
 57          """Properly delete the wizard and all its elements.""" 
 58   
 59          self.wizard.Destroy() 
  60   
 61   
 63          """Run through the analysis selection wizard, returning the results. 
 64   
 65          @return:    The analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list. 
 66          @rtype:     tuple of str 
 67          """ 
 68   
 69           
 70          wx.Yield() 
 71          wx.BeginBusyCursor() 
 72   
 73           
 74          self.wizard = Wiz_window(size_x=1000, size_y=700, title='Analysis selection wizard') 
 75   
 76           
 77          self.wizard.TEXT_FINISH = " Start" 
 78   
 79           
 80          self.new_page = New_analysis_page(self.wizard) 
 81          self.wizard.add_page(self.new_page, apply_button=False) 
 82          self.wizard.set_seq_next_fn(0, self.wizard_page_after_analysis) 
 83   
 84           
 85          self.pipe_page = Data_pipe_page(self.wizard, height_desc=400) 
 86          self.wizard.add_page(self.pipe_page, apply_button=False) 
 87   
 88           
 89          if wx.IsBusy(): 
 90              wx.EndBusyCursor() 
 91   
 92           
 93          setup = self.wizard.run(modal=True) 
 94          if setup != wx.ID_OK: 
 95              return 
 96   
 97           
 98          return self.get_data() 
  99   
100   
102          """Assemble and return the analysis type, analysis name, and pipe name. 
103   
104          @return:    The analysis type, analysis name, data pipe name, data pipe bundle name, and list of user function on_execute methods. 
105          @rtype:     str, str, str, str, list of methods 
106          """ 
107   
108           
109          analysis_type = gui_to_str(self.wizard.analysis_type) 
110          analysis_name = gui_to_str(self.new_page.analysis_name.GetValue()) 
111          pipe_name = gui_to_str(self.pipe_page.pipe_name.GetValue()) 
112          pipe_bundle = gui_to_str(self.pipe_page.pipe_bundle.GetValue()) 
113   
114           
115          uf_exec = [] 
116   
117           
118          return analysis_type, analysis_name, pipe_name, pipe_bundle, uf_exec 
 119   
120   
122          """Set the page after the data pipe setup. 
123   
124          @return:    The index of the next page, which is the current page index plus one. 
125          @rtype:     int 
126          """ 
127   
128           
129          analysis_name = gui_to_str(self.new_page.analysis_name.GetValue()) 
130   
131           
132          return 1 
  133   
134   
135   
136 -class Data_pipe_page(Wiz_page): 
 137      """The panel for setting the data pipe name.""" 
138   
139       
140      image_path = WIZARD_IMAGE_PATH + 'pipe.png' 
141      main_text = "Select the name of the data pipe used at the start of the analysis and the name of the data pipe bundle to be associated with this analysis.  All data in relax is kept within a special structure known as the relax data store.  This store is composed of multiple data pipes, each being associated with a specific analysis type.  Data pipe bundles are simple groupings of the pipes within the data store and each analysis tab is coupled to a specific bundle.\n\nSimple analyses such as the steady-state NOE and the %s and %s curve-fitting will be located within a single data pipe.  More complex analyses such as the automated model-free analysis will be spread across multiple data pipes, internally created by forking the original data pipe which holds the input data, all grouped together within a single bundle.\n\nThe initialisation of a new analysis will call the pipe.create user function with the pipe name and pipe bundle as given below." % (r1, r2) 
142      title = 'Data pipe set up' 
143   
144 -    def add_contents(self, sizer): 
 145          """Add the specific GUI elements (dummy method). 
146   
147          @param sizer:   A sizer object. 
148          @type sizer:    wx.Sizer instance 
149          """ 
150   
151           
152          self.pipe_name = Value(name='pipe_name', parent=self, value_type='str', sizer=sizer, desc="The starting data pipe for the analysis:", divider=self._div_left, height_element=self.height_element) 
153   
154           
155          self.pipe_bundle = Value(name='pipe_bundle', parent=self, value_type='str', sizer=sizer, desc="The data pipe bundle:", divider=self._div_left, height_element=self.height_element) 
156   
157           
158          sizer.AddStretchSpacer(3) 
 159   
160   
161 -    def on_display(self): 
 162          """Update the pipe name.""" 
163   
164           
165          name = "%s (%s)" % (self.parent.analysis_type, asctime(localtime())) 
166   
167           
168          self.pipe_name.SetValue(str_to_gui("origin - %s" % name)) 
169          self.pipe_bundle.SetValue(str_to_gui(name)) 
  170   
171   
172   
206   
207   
208   
209 -class New_analysis_page(Wiz_page): 
 210      """The panel for selection of the new analysis.""" 
211   
212       
213      image_path = IMAGE_PATH + "relax.gif" 
214      main_text = "A number of automatic analyses to be preformed using relax in GUI mode.  Although not as flexible or powerful as the prompt/scripting modes, this provides a quick and easy setup and execution for a number of analysis types.   These currently include the calculation of the steady-state NOE, the exponential curve-fitting for the %s and %s relaxation rates, and for a full and automatic model-free analysis using the d'Auvergne and Gooley, 2008b protocol.  All analyses perform error propagation using the gold standard Monte Calro simulations.  Please select from one of the following analysis types:" % (r1, r2) 
215      title = "Start a new analysis" 
216   
217 -    def add_artwork(self, sizer): 
 218          """Add the artwork to the dialog. 
219   
220          @param sizer:   A sizer object. 
221          @type sizer:    wx.Sizer instance 
222          """ 
223   
224           
225          sizer2 = wx.BoxSizer(wx.VERTICAL) 
226   
227           
228          sizer2.AddSpacer(30) 
229   
230           
231          self.image = wx.StaticBitmap(self, -1, bitmap_setup(self.image_path)) 
232          sizer2.Add(self.image, 0, wx.TOP|wx.ALIGN_CENTER_HORIZONTAL, 0) 
233   
234           
235          sizer.Add(sizer2) 
236   
237           
238          sizer.AddSpacer(self.art_spacing) 
 239   
240   
242          """The widget of analysis buttons. 
243   
244          @param box:     A sizer object. 
245          @type box:      wx.BoxSizer instance 
246          """ 
247   
248           
249          size = (170, 170) 
250   
251           
252          self._select_flag = False 
253   
254           
255          sizer1 = wx.BoxSizer(wx.HORIZONTAL) 
256          sizer2 = wx.BoxSizer(wx.HORIZONTAL) 
257   
258           
259          self.button_noe = self.create_button(id=BUTTON_ID_NOE, box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"noe_150x150.png", tooltip="Steady-state NOE analysis", fn=self.select_noe) 
260   
261           
262          self.button_r1 = self.create_button(id=BUTTON_ID_R1, box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"r1_150x150.png", tooltip="%s relaxation curve-fitting analysis" % r1, fn=self.select_r1) 
263   
264           
265          self.button_r2 = self.create_button(id=BUTTON_ID_R2, box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"r2_150x150.png", tooltip="%s relaxation curve-fitting analysis" % r2, fn=self.select_r2) 
266   
267           
268          self.button_mf = self.create_button(id=BUTTON_ID_MF, box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"model_free"+sep+"model_free_150x150.png", tooltip="Model-free analysis", fn=self.select_mf) 
269   
270           
271          self.button_disp = self.create_button(id=BUTTON_ID_RELAX_DISP, box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"relax_disp_150x150.png", tooltip="Relaxation dispersion analysis", fn=self.select_disp) 
272   
273           
274          self.button_consist_test = self.create_button(id=BUTTON_ID_CONSIST_TEST, box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"consistency_testing_150x70.png", tooltip="Relaxation data consistency testing (disabled)", fn=self.select_consist_test, disabled=True) 
275   
276           
277          self.button_custom = self.create_button(id=BUTTON_ID_CUSTOM, box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"custom_150x150.png", tooltip="Custom analysis (disabled)", fn=self.select_custom, disabled=True) 
278   
279           
280          self.button_reserved = self.create_button(id=BUTTON_ID_RESERVED, box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"blank_150x150.png", tooltip=None, fn=None, disabled=True) 
281   
282           
283          box.Add(sizer1, 0, wx.ALIGN_CENTER_HORIZONTAL, 0) 
284          box.Add(sizer2, 0, wx.ALIGN_CENTER_HORIZONTAL, 0) 
 285   
286   
287 -    def add_contents(self, sizer): 
 288          """Add the specific GUI elements (dummy method). 
289   
290          @param sizer:   A sizer object. 
291          @type sizer:    wx.Sizer instance 
292          """ 
293   
294           
295          self.add_buttons(sizer) 
296   
297           
298          sizer.AddStretchSpacer(2) 
299   
300           
301          self.analysis_name = Value(name='analysis_name', parent=self, value_type='str', sizer=sizer, desc="The name of the new analysis:", tooltip='The name of the analysis can be changed to any text.', divider=self._div_left, height_element=self.height_element) 
 302   
303   
304 -    def create_button(self, id=-1, box=None, size=None, bmp=None, text='', tooltip='', fn=None, disabled=False): 
 305          """Create a button for the new analysis selector panel. 
306   
307          @keyword id:        The unique ID number. 
308          @type id:           int 
309          @keyword box:       The box sizer to place the button into. 
310          @type box:          wx.BoxSizer instance 
311          @keyword size:      The size of the button. 
312          @type size:         tuple of int 
313          @keyword bmp:       The full path of the bitmap image to use for the button. 
314          @type bmp:          str 
315          @keyword text:      The text for the button. 
316          @type text:         str 
317          @keyword tooltip:   The button tooltip text. 
318          @type tooltip:      str or None 
319          @keyword fn:        The function to bind the button click to. 
320          @type fn:           method 
321          @return:            The button. 
322          @rtype:             wx.lib.buttons.ThemedGenBitmapTextToggleButton instance 
323          """ 
324   
325           
326          if bmp: 
327              image = wx.Bitmap(bmp, wx.BITMAP_TYPE_ANY) 
328              button = New_analysis_button(self, id, image) 
329          else: 
330              button = New_analysis_button(self, id) 
331   
332           
333          if tooltip != None: 
334              button.SetToolTipString(tooltip) 
335   
336           
337          button.SetMinSize(size) 
338   
339           
340          box.Add(button) 
341   
342           
343          if fn != None: 
344              self.Bind(wx.EVT_BUTTON, fn, button) 
345   
346           
347          if disabled: 
348              button.Disable() 
349   
350           
351          return button 
 352   
353   
354 -    def on_display(self): 
 355          """Disable the next button until an analysis is selected.""" 
356   
357           
358          self.parent.block_next(not self._select_flag) 
 359   
360   
361 -    def select_consist_test(self, event): 
 362          """NOE analysis selection. 
363   
364          @param event:   The wx event. 
365          @type event:    wx event 
366          """ 
367   
368           
369          self.toggle(self.button_consist_test) 
370   
371           
372          self.parent.analysis_type = 'consistency test' 
 373   
374   
375 -    def select_custom(self, event): 
 376          """NOE analysis selection. 
377   
378          @param event:   The wx event. 
379          @type event:    wx event 
380          """ 
381   
382           
383          self.toggle(self.button_custom) 
384   
385           
386          self.parent.analysis_type = 'custom' 
 387   
388   
389 -    def select_disp(self, event): 
 390          """Relaxation dispersion analysis selection. 
391   
392          @param event:   The wx event. 
393          @type event:    wx event 
394          """ 
395   
396           
397          self.toggle(self.button_disp) 
398   
399           
400          self.analysis_name.SetValue(str_to_gui('Relaxation dispersion')) 
401   
402           
403          self.parent.analysis_type = 'relax_disp' 
 404   
405   
406 -    def select_mf(self, event): 
 407          """NOE analysis selection. 
408   
409          @param event:   The wx event. 
410          @type event:    wx event 
411          """ 
412   
413           
414          self.toggle(self.button_mf) 
415   
416           
417          self.analysis_name.SetValue(str_to_gui('Model-free')) 
418   
419           
420          self.parent.analysis_type = 'mf' 
 421   
422   
423 -    def select_noe(self, event): 
 424          """NOE analysis selection. 
425   
426          @param event:   The wx event. 
427          @type event:    wx event 
428          """ 
429   
430           
431          self.toggle(self.button_noe) 
432   
433           
434          self.analysis_name.SetValue(str_to_gui('Steady-state NOE')) 
435   
436           
437          self.parent.analysis_type = 'noe' 
 438   
439   
440 -    def select_r1(self, event): 
 441          """NOE analysis selection. 
442   
443          @param event:   The wx event. 
444          @type event:    wx event 
445          """ 
446   
447           
448          self.toggle(self.button_r1) 
449   
450           
451          self.analysis_name.SetValue(str_to_gui("R1 relaxation")) 
452   
453           
454          self.parent.analysis_type = 'r1' 
 455   
456   
457 -    def select_r2(self, event): 
 458          """NOE analysis selection. 
459   
460          @param event:   The wx event. 
461          @type event:    wx event 
462          """ 
463   
464           
465          self.toggle(self.button_r2) 
466   
467           
468          self.analysis_name.SetValue(str_to_gui("R2 relaxation")) 
469   
470           
471          self.parent.analysis_type = 'r2' 
 472   
473   
474 -    def toggle(self, button): 
 475          """Toggle all buttons off except the selected one. 
476   
477          @param button:  The button of the selected analysis. 
478          @type button:   wx.ToggleButton instance 
479          """ 
480   
481           
482          self.Freeze() 
483   
484           
485          self._select_flag = True 
486   
487           
488          self.button_noe.SetValue(False) 
489          self.button_r1.SetValue(False) 
490          self.button_r2.SetValue(False) 
491          self.button_mf.SetValue(False) 
492          self.button_disp.SetValue(False) 
493          self.button_consist_test.SetValue(False) 
494          self.button_custom.SetValue(False) 
495          self.button_reserved.SetValue(False) 
496   
497           
498          button.SetValue(True) 
499   
500           
501          self.Refresh() 
502   
503           
504          self.Thaw() 
505   
506           
507          self.parent.block_next(not self._select_flag) 
  508