1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21   
 22   
 23  """The pipe editor GUI element.""" 
 24   
 25   
 26  import wx 
 27  import wx.grid 
 28   
 29   
 30  from data_store import Relax_data_store; ds = Relax_data_store() 
 31  from graphics import WIZARD_IMAGE_PATH, fetch_icon 
 32  from gui.components.menu import build_menu_item 
 33  from gui.fonts import font 
 34  from gui.icons import relax_icons 
 35  from gui.message import Question 
 36  from gui.misc import add_border, bitmap_setup 
 37  from gui.string_conv import gui_to_str, str_to_gui 
 38  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 39  from lib.errors import RelaxError 
 40  from pipe_control.pipes import cdp_name, delete, get_bundle, get_type, pipe_names, switch 
 41  from status import Status; status = Status() 
 42   
 43   
 45      """The pipe editor window object.""" 
 46   
 47 -    def __init__(self, gui=None, size_x=1000, size_y=600, border=10): 
  48          """Set up the relax controller frame. 
 49           
 50          @keyword gui:       The main GUI object. 
 51          @type gui:          wx.Frame instance 
 52          @keyword size_x:    The initial and minimum width of the window. 
 53          @type size_x:       int 
 54          @keyword size_y:    The initial and minimum height of the window. 
 55          @type size_y:       int 
 56          @keyword border:    The size of the internal border of the window. 
 57          @type border:       int 
 58          """ 
 59   
 60           
 61          self.gui = gui 
 62          self.border = border 
 63   
 64           
 65          wx.Frame.__init__(self, None, id=-1, title="Data pipe editor") 
 66   
 67           
 68          self.SetIcons(relax_icons) 
 69   
 70           
 71          self.width_col_label = 40 
 72   
 73           
 74          self.SetMinSize((size_x, size_y)) 
 75          self.SetSize((size_x, size_y)) 
 76   
 77           
 78          self.main_panel = wx.Panel(self, -1) 
 79   
 80           
 81          main_sizer = wx.BoxSizer(wx.VERTICAL) 
 82          self.main_panel.SetSizer(main_sizer) 
 83   
 84           
 85          sizer = add_border(main_sizer, border=border, packing=wx.VERTICAL) 
 86   
 87           
 88          sizer.AddSpacer(10) 
 89          self.add_logo(sizer) 
 90          sizer.AddSpacer(20) 
 91          self.add_buttons(sizer) 
 92          sizer.AddSpacer(10) 
 93          self.add_table(sizer) 
 94   
 95           
 96          self.grid.Bind(wx.EVT_SIZE, self.resize) 
 97          self.Bind(wx.EVT_CLOSE, self.handler_close) 
 98          self.grid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.menu) 
 99   
100           
101          self.name = 'pipe editor' 
102   
103           
104          self.update_grid() 
 105   
106   
108          """Activate or deactivate certain elements in response to the execution lock.""" 
109   
110           
111          if status.exec_lock.locked(): 
112              wx.CallAfter(self.button_bundle.Enable, False) 
113              wx.CallAfter(self.button_create.Enable, False) 
114              wx.CallAfter(self.button_copy.Enable, False) 
115              wx.CallAfter(self.button_delete.Enable, False) 
116              wx.CallAfter(self.button_hybrid.Enable, False) 
117              wx.CallAfter(self.button_switch.Enable, False) 
118   
119           
120          else: 
121              wx.CallAfter(self.button_bundle.Enable, True) 
122              wx.CallAfter(self.button_create.Enable, True) 
123              wx.CallAfter(self.button_copy.Enable, True) 
124              wx.CallAfter(self.button_delete.Enable, True) 
125              wx.CallAfter(self.button_hybrid.Enable, True) 
126              wx.CallAfter(self.button_switch.Enable, True) 
 127   
128   
130          """The pop up menu. 
131   
132          @param event:   The wx event. 
133          @type event:    wx event 
134          """ 
135   
136           
137          row = event.GetRow() 
138   
139           
140          self.selected_pipe = gui_to_str(self.grid.GetCellValue(row, 0)) 
141   
142           
143          if not self.selected_pipe: 
144              return 
145   
146           
147          pipe_type = get_type(self.selected_pipe) 
148          pipe_bundle = get_bundle(self.selected_pipe) 
149   
150           
151          menu = wx.Menu() 
152          items = [] 
153   
154           
155          if not pipe_bundle: 
156              items.append(build_menu_item(menu, parent=self, text="&Add the pipe to a bundle", icon=fetch_icon("relax.pipe_bundle"), fn=self.pipe_bundle)) 
157   
158           
159          items.append(build_menu_item(menu, parent=self, text="&Delete the pipe", icon=fetch_icon('oxygen.actions.list-remove', "16x16"), fn=self.pipe_delete)) 
160    
161           
162          items.append(build_menu_item(menu, parent=self, text="&Switch to this pipe", icon=fetch_icon('oxygen.actions.system-switch-user', "16x16"), fn=self.pipe_switch)) 
163    
164           
165          if pipe_bundle and self.gui.analysis.page_index_from_bundle(pipe_bundle) == None and pipe_type in ['noe', 'r1', 'r2', 'mf', 'relax_disp']: 
166              items.append(build_menu_item(menu, parent=self, text="&Associate with a new auto-analysis", icon=fetch_icon('oxygen.actions.document-new', "16x16"), fn=self.associate_auto)) 
167    
168           
169          for item in items: 
170              menu.AppendItem(item) 
171              if status.exec_lock.locked(): 
172                  item.Enable(False) 
173   
174           
175          if status.show_gui: 
176              self.PopupMenu(menu) 
177   
178           
179          menu.Destroy() 
 180   
181   
240   
241   
243          """Launch the user function GUI wizards. 
244   
245          @param event:   The wx event. 
246          @type event:    wx event 
247          """ 
248   
249           
250          if event.GetEventObject() == self.button_bundle: 
251              uf_store['pipe.bundle'](event, wx_parent=self, wx_wizard_sync=True, wx_wizard_modal=True) 
252          elif event.GetEventObject() == self.button_create: 
253              uf_store['pipe.create'](event, wx_parent=self, wx_wizard_sync=True, wx_wizard_modal=True) 
254          elif event.GetEventObject() == self.button_copy: 
255              uf_store['pipe.copy'](event, wx_parent=self, wx_wizard_sync=True, wx_wizard_modal=True) 
256          elif event.GetEventObject() == self.button_delete: 
257              uf_store['pipe.delete'](event, wx_parent=self, wx_wizard_sync=True, wx_wizard_modal=True) 
258          elif event.GetEventObject() == self.button_hybrid: 
259              uf_store['pipe.hybridise'](event, wx_parent=self, wx_wizard_sync=True, wx_wizard_modal=True) 
260          elif event.GetEventObject() == self.button_switch: 
261              uf_store['pipe.switch'](event, wx_parent=self, wx_wizard_sync=True, wx_wizard_modal=True) 
 262   
263   
265          """Add the logo to the sizer. 
266   
267          @param box:     The sizer element to pack the logo into. 
268          @type box:      wx.Sizer instance 
269          """ 
270   
271           
272          logo = wx.StaticBitmap(self.main_panel, -1, bitmap_setup(WIZARD_IMAGE_PATH+'pipe_200x90.png')) 
273   
274           
275          box.Add(logo, 0, wx.ALIGN_CENTER_HORIZONTAL, 0) 
 276   
277   
279          """Add the table to the sizer. 
280   
281          @param sizer:   The sizer element to pack the table into. 
282          @type sizer:    wx.Sizer instance 
283          """ 
284   
285           
286          self.grid = wx.grid.Grid(self.main_panel, -1) 
287   
288           
289          self.grid.CreateGrid(1, 5) 
290   
291           
292          self.grid.SetColLabelValue(0, "Data pipe") 
293          self.grid.SetColLabelValue(1, "Type") 
294          self.grid.SetColLabelValue(2, "Bundle") 
295          self.grid.SetColLabelValue(3, "Current") 
296          self.grid.SetColLabelValue(4, "Analysis tab") 
297   
298           
299          self.grid.SetDefaultCellFont(font.normal) 
300          self.grid.SetLabelFont(font.normal_bold) 
301   
302           
303          self.grid.SetRowLabelSize(self.width_col_label) 
304   
305           
306          self.grid.EnableDragColSize(False) 
307          self.grid.EnableDragRowSize(False) 
308   
309           
310          sizer.Add(self.grid, 1, wx.ALL|wx.EXPAND, 0) 
 311   
312   
314          """Associate the selected data pipe with a new auto-analysis. 
315   
316          @param event:   The wx event. 
317          @type event:    wx event 
318          """ 
319   
320           
321          if not hasattr(ds, 'relax_gui'): 
322              self.gui.init_data() 
323   
324           
325          type = get_type(self.selected_pipe) 
326          bundle = get_bundle(self.selected_pipe) 
327   
328           
329          if self.selected_pipe == None: 
330              raise RelaxError("No data pipe has been selected - this is not possible.") 
331          if bundle == None: 
332              raise RelaxError("The selected data pipe is not associated with a data pipe bundle.") 
333   
334           
335          names = { 
336              'noe': 'Steady-state NOE', 
337              'r1': 'R1 relaxation', 
338              'r2': 'R2 relaxation', 
339              'mf': 'Model-free', 
340              'relax_disp': 'Relaxation dispersion' 
341          } 
342   
343           
344          self.gui.analysis.new_analysis(analysis_type=type, analysis_name=names[type], pipe_name=self.selected_pipe, pipe_bundle=bundle) 
 345   
346   
348          """Event handler for the close window action. 
349   
350          @param event:   The wx event. 
351          @type event:    wx event 
352          """ 
353   
354           
355          self.observer_setup(register=False) 
356   
357           
358          self.Hide() 
 359   
360   
379   
380   
382          """Bundle the date pipe. 
383   
384          @param event:   The wx event. 
385          @type event:    wx event 
386          """ 
387   
388           
389          uf_store['pipe.bundle'](event, wx_parent=self, pipe=self.selected_pipe) 
 390   
391   
393          """Delete the date pipe. 
394   
395          @param event:   The wx event. 
396          @type event:    wx event 
397          """ 
398   
399           
400          msg = "Are you sure you would like to delete the '%s' data pipe?  This operation cannot be undone." % self.selected_pipe 
401          if status.show_gui and Question(msg, parent=self, default=False).ShowModal() == wx.ID_NO: 
402              return 
403   
404           
405          delete(self.selected_pipe) 
 406   
407   
409          """Switch to the selected date pipe. 
410   
411          @param event:   The wx event. 
412          @type event:    wx event 
413          """ 
414   
415           
416          switch(self.selected_pipe) 
417   
418           
419          wx.CallAfter(self.Raise) 
 420   
421   
423          """Catch the resize to allow the grid to be resized. 
424   
425          @param event:   The wx event. 
426          @type event:    wx event 
427          """ 
428   
429           
430          self.size_cols() 
431   
432           
433          event.Skip() 
 434   
435   
437          """Set the column sizes.""" 
438   
439           
440          x, y = self.grid.GetSize() 
441   
442           
443          n = 5 
444   
445           
446          width_col_curr = 80 
447   
448           
449          width = int((x - self.width_col_label - width_col_curr) / (n - 1)) 
450   
451           
452          for i in range(n): 
453               
454              if i == 3: 
455                  self.grid.SetColSize(i, width_col_curr) 
456   
457               
458              else: 
459                  self.grid.SetColSize(i, width) 
 460   
461   
463          """Update the grid in a thread safe way using wx.CallAfter.""" 
464   
465           
466          wx.CallAfter(self.update_grid_safe) 
467   
468           
469          wx.GetApp().Yield(True) 
 470   
471   
473          """Update the grid with the pipe data.""" 
474   
475           
476          self.grid.Freeze() 
477   
478           
479          status.pipe_lock.acquire('pipe editor window') 
480   
481           
482          self.grid.DeleteRows(numRows=self.grid.GetNumberRows()-1) 
483   
484           
485          for i in range(self.grid.GetNumberCols()): 
486              self.grid.SetCellValue(0, i, str_to_gui("")) 
487   
488           
489          pipe_list = pipe_names() 
490          n = len(pipe_list) 
491   
492           
493          if n >= 1: 
494              self.grid.AppendRows(numRows=n-1) 
495   
496           
497          for i in range(n): 
498               
499              self.grid.SetCellValue(i, 0, str_to_gui(pipe_list[i])) 
500   
501               
502              self.grid.SetCellValue(i, 1, str_to_gui(get_type(pipe_list[i]))) 
503   
504               
505              self.grid.SetCellValue(i, 2, str_to_gui(get_bundle(pipe_list[i]))) 
506   
507               
508              if pipe_list[i] == cdp_name(): 
509                  self.grid.SetCellValue(i, 3, str_to_gui("cdp")) 
510   
511               
512              self.grid.SetCellValue(i, 4, str_to_gui(self.gui.analysis.page_name_from_bundle(get_bundle(pipe_list[i])))) 
513   
514           
515          for i in range(self.grid.GetNumberRows()): 
516               
517              self.grid.SetRowSize(i, 27) 
518   
519               
520              for j in range(self.grid.GetNumberCols()): 
521                   
522                  self.grid.SetReadOnly(i, j) 
523   
524           
525          status.pipe_lock.release('pipe editor window') 
526   
527           
528          self.grid.Thaw() 
  529