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  """Module containing the classes for GUI components involving spectral data.""" 
 26   
 27   
 28  from os import sep 
 29  from re import search 
 30  import wx 
 31  import wx.lib.buttons 
 32   
 33   
 34  from data import Relax_data_store; ds = Relax_data_store() 
 35  from status import Status; status = Status() 
 36   
 37   
 38  from gui.filedialog import RelaxFileDialog 
 39  from gui.fonts import font 
 40  from gui.message import error_message 
 41  from gui.misc import add_border, str_to_gui 
 42  from gui import paths 
 43   
 44   
 46      """Custom GridCellEditor for the number of delays grid cells. 
 47   
 48      Changing these cells will update the relaxation delay times. 
 49      """ 
 50   
 51 -    def __init__(self, min=None, max=None, parent=None): 
  52          """Initialise the class. 
 53           
 54          @keyword min:       The minimum value for wx.SpinCtrl. 
 55          @type min:          None or int 
 56          @keyword max:       The maximum value for wx.SpinCtrl. 
 57          @type max:          None or int 
 58          @keyword parent:    The parent wx object. 
 59          @type parent:       wx object 
 60          """ 
 61   
 62           
 63          self.min = min 
 64          self.max = max 
 65          self.parent = parent 
 66   
 67           
 68          super(Delay_num_cell_editor, self).__init__() 
 69   
 70           
 71          self.reset = False 
  72   
 73   
 75          """Start the editing. 
 76   
 77          @param row:     The row index. 
 78          @type row:      int 
 79          @param col:     The column index. 
 80          @type col:      int 
 81          @param grid:    The grid GUI element. 
 82          @type grid:     wx.grid.Grid instance. 
 83          """ 
 84   
 85           
 86          self.prev_val = grid.GetTable().GetValue(row, col) 
 87   
 88           
 89          self.cell.SetValueString(str_to_gui(self.prev_val)) 
 90   
 91           
 92          self.cell.SetFocus() 
  93   
 94   
 96          """Create and return a new class instance.""" 
 97   
 98           
 99          return Delay_num_cell_editor(self.min, self.max, self.parent) 
 100   
101   
102 -    def Create(self, parent, id, evtHandler): 
 103          """Create the control for the cell. 
104   
105          @param parent:      The parent wx object. 
106          @type parent:       wx object 
107          @param id:          The ID number. 
108          @type id:           int 
109          @param evtHandler:  The event handler function. 
110          @type evtHandler:   func 
111          """ 
112   
113           
114          self.cell = wx.SpinCtrl(parent, id, "", min=self.min, max=self.max) 
115          self.SetControl(self.cell) 
116   
117           
118          if evtHandler: 
119              self.cell.PushEventHandler(evtHandler) 
 120   
121   
122 -    def EndEdit(self, row, col, grid): 
 123          """End the editing. 
124   
125          @param row:     The row index. 
126          @type row:      int 
127          @param col:     The column index. 
128          @type col:      int 
129          @param grid:    The grid GUI element. 
130          @type grid:     wx.grid.Grid instance. 
131          """ 
132   
133           
134          if self.reset: 
135               
136              self.reset = False 
137   
138               
139              if self.prev_val == '': 
140                  return False 
141   
142           
143          value = self.cell.GetValue() 
144   
145           
146          if value == self.prev_val: 
147              return False 
148   
149           
150          if value == 0: 
151              text = '' 
152          else: 
153              text = str(value) 
154          grid.GetTable().SetValue(row, col, str_to_gui(text)) 
155   
156           
157          time = self.parent.delay_time.GetValue() 
158   
159           
160          if time == '': 
161               
162              return True 
163   
164           
165          delay_time = float(time) * float(value) 
166          grid.GetTable().SetValue(row, col-1, str_to_gui(delay_time)) 
167   
168           
169          return True 
 170   
171   
173          """Reset the cell to the previous value.""" 
174   
175           
176          self.cell.SetValueString(str_to_gui(self.prev_val)) 
177   
178           
179          self.reset = True 
 180   
181   
183          """Catch the starting key stroke to add the value to the cell. 
184   
185          @param event:   The wx event. 
186          @type event:    wx event 
187          """ 
188   
189           
190          key = event.GetKeyCode() 
191   
192           
193          if key >= 49 and key <= 57: 
194               
195              num = int(chr(key)) 
196   
197               
198              self.cell.SetValue(str_to_gui(num)) 
199   
200               
201              self.cell.SetSelection(1, 1) 
202   
203           
204          else: 
205              event.Skip() 
  206   
207   
208   
210      """The peak list selection class.""" 
211   
212       
213      col_label_width = 40 
214      col1_width = 160 
215      col2_width = 140 
216   
217 -    def __init__(self, gui=None, parent=None, subparent=None, data=None, label=None, width=688, height=300, box=None): 
 218          """Build the peak list reading GUI element. 
219   
220          @keyword gui:       The main GUI object. 
221          @type gui:          wx.Frame instance 
222          @keyword parent:    The parent GUI element that this is to be attached to (the panel object). 
223          @type parent:       wx object 
224          @keyword subparent: The subparent GUI element that this is to be attached to (the analysis object). 
225          @type subparent:    wx object 
226          @keyword data:      The data storage container. 
227          @type data:         class instance 
228          @keyword label:     The type of analysis. 
229          @type label:        str 
230          @keyword width:     The initial width of the GUI element. 
231          @type width:        int 
232          @keyword height:    The initial height of the GUI element. 
233          @type height:       int 
234          @keyword box:       The vertical box sizer to pack this GUI component into. 
235          @type box:          wx.BoxSizer instance 
236          """ 
237   
238           
239          self.gui = gui 
240          self.parent = parent 
241          self.subparent = subparent 
242          self.data = data 
243          self.label = label 
244   
245           
246          self.spacing = 5 
247          self.border = 5 
248   
249           
250          self.num_rows = 50 
251   
252           
253          stat_box = wx.StaticBox(self.parent, -1, "Peak lists") 
254          stat_box.SetFont(font.subtitle) 
255          sub_sizer = wx.StaticBoxSizer(stat_box, wx.VERTICAL) 
256   
257           
258          box.Add(sub_sizer, 1, wx.ALL|wx.EXPAND, 0) 
259   
260           
261          box_centre = add_border(sub_sizer, border=self.border) 
262   
263           
264          box_centre.AddSpacer(self.spacing) 
265          self.delay_time = self.subparent.add_text_sel_element(box_centre, self.parent, text="Single delay cycle time [s]") 
266   
267           
268          box_centre.AddSpacer(self.spacing) 
269          self.add_grid(box_centre) 
270          box_centre.AddSpacer(self.spacing) 
271   
272           
273          self.delay_time.Bind(wx.EVT_KEY_DOWN, self.change_delay_down) 
274          self.delay_time.Bind(wx.EVT_KEY_UP, self.change_delay_up) 
 275   
276   
298   
299   
343   
344   
346          """Add the grid for the peak list files and delay times. 
347   
348          @param sizer:   The sizer element to pack the grid into. 
349          @type sizer:    wx.BoxSizer instance 
350          """ 
351   
352           
353          self.grid = wx.grid.Grid(self.parent, -1) 
354   
355           
356          self.grid.CreateGrid(self.num_rows, 3) 
357   
358           
359          self.grid.SetColLabelValue(0, "%s peak list" % self.label) 
360          self.grid.SetColLabelValue(1, "Relaxation delay [s]") 
361          self.grid.SetColLabelValue(2, "No. of cycles") 
362   
363           
364          self.grid.SetDefaultCellFont(font.normal) 
365          self.grid.SetLabelFont(font.normal_bold) 
366   
367           
368          height = self.delay_time.GetSize()[1] 
369   
370           
371          for i in range(self.grid.GetNumberRows()): 
372               
373              self.grid.SetCellEditor(i, 2, Delay_num_cell_editor(0, 200, self)) 
374   
375               
376              self.grid.SetRowSize(i, height) 
377   
378           
379          self.grid.EnableDragColSize(False) 
380          self.grid.EnableDragRowSize(False) 
381   
382           
383          self.grid.GetGridWindow().Bind(wx.EVT_LEFT_DCLICK, self.event_left_dclick) 
384          self.grid.Bind(wx.EVT_KEY_DOWN, self.event_key_down) 
385          self.grid.Bind(wx.EVT_KEY_UP, self.event_key_up) 
386          self.grid.Bind(wx.EVT_SIZE, self.resize) 
387   
388           
389          sizer.Add(self.grid, 1, wx.ALL|wx.EXPAND, 0) 
 390   
391   
393          """Handle changes to the delay time. 
394   
395          @param event:   The wx event. 
396          @type event:    wx event 
397          """ 
398   
399           
400          key = event.GetKeyCode() 
401   
402           
403          text = str(self.delay_time.GetString(0, self.delay_time.GetLastPosition())) 
404   
405           
406          allowed = [] 
407          allowed += [8]     
408          if not search('\.', text): 
409              allowed += [46]     
410          allowed += [48, 49, 50, 51, 52, 53, 54, 55, 56, 57]     
411          allowed += [127]     
412          allowed += [wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_HOME, wx.WXK_END]     
413   
414           
415          if key not in allowed: 
416              return 
417   
418           
419          event.Skip() 
 420   
421   
423          """Handle updates to the delay time. 
424   
425          @param event:   The wx event. 
426          @type event:    wx event 
427          """ 
428   
429           
430          event.Skip() 
431   
432           
433          self.update_grid() 
 434   
435   
437          """Handle the left mouse double click. 
438   
439          @param event:   The wx event. 
440          @type event:    wx event 
441          """ 
442   
443           
444          col = self.grid.GetGridCursorCol() 
445          row = self.grid.GetGridCursorRow() 
446   
447           
448          if col == 0: 
449               
450              dialog = RelaxFileDialog(parent=self, style=wx.FD_OPEN) 
451   
452               
453              if status.show_gui and dialog.ShowModal() != wx.ID_OK: 
454                   
455                  return 
456   
457               
458              filename = dialog.get_file() 
459   
460               
461              self.grid.SetCellValue(row, col, str(filename)) 
462   
463           
464          event.Skip() 
 465   
466   
468          """Control what happens when a key is pressed. 
469   
470          @param event:   The wx event. 
471          @type event:    wx event 
472          """ 
473   
474           
475          if event.GetKeyCode() == wx.WXK_DELETE: 
476               
477              cells = self.get_selection() 
478   
479               
480              if status.debug: 
481                  print(cells) 
482   
483               
484              for cell in cells: 
485                   
486                  self.grid.SetCellValue(cell[0], cell[1], '') 
487   
488               
489              self.update_grid() 
490   
491               
492              return 
493   
494           
495          event.Skip() 
 496   
497   
499          """Control what happens when a key is released. 
500   
501          @param event:   The wx event. 
502          @type event:    wx event 
503          """ 
504   
505           
506          self.update_grid() 
507   
508           
509          event.Skip() 
 510   
511   
513          """Convert the cell range into a coordinate list. 
514   
515          @param top_left:        The top left hand coordinate. 
516          @type top_left:         list or tuple 
517          @param bottom_right:    The bottom right hand coordinate. 
518          @type bottom_right:     list or tuple 
519          @return:                The list of tuples of coordinates of all cells. 
520          @rtype:                 list of tuples 
521          """ 
522   
523           
524          cells = [] 
525   
526           
527          for x in range(top_left[0], bottom_right[0]+1): 
528               
529              for y in range(top_left[1], bottom_right[1]+1): 
530                   
531                  cells.append((x, y)) 
532   
533           
534          return cells 
 535   
536   
538          """Determine which cells are selected. 
539   
540          There are three possibilities for cell selections in a wx.grid.  These are: 
541   
542              - Single cell selection (this is not highlighted). 
543              - Multiple cells are selected. 
544              - Column selection. 
545              - Row selection. 
546   
547          @return:    An array of the cell selection coordinates. 
548          @rtype:     list of tuples of int 
549          """ 
550   
551           
552          top_left = self.grid.GetSelectionBlockTopLeft() 
553          bottom_right = self.grid.GetSelectionBlockBottomRight() 
554   
555           
556          selection = self.grid.GetSelectedCells() 
557          col = self.grid.GetSelectedCols() 
558          row = self.grid.GetSelectedRows() 
559   
560           
561          if status.debug: 
562              print("\nTop left: %s" % top_left) 
563              print("Bottom right: %s" % bottom_right) 
564              print("selection: %s" % selection) 
565              print("col: %s" % col) 
566              print("row: %s" % row) 
567   
568           
569          if col: 
570               
571              if status.debug: 
572                  print("Column selection") 
573   
574               
575              return self.get_all_coordinates([0, col[0]], [self.num_rows-1, col[-1]]) 
576   
577           
578          elif row: 
579               
580              if status.debug: 
581                  print("Row selection") 
582   
583               
584              return self.get_all_coordinates([row[0], 0], [row[-1], 1]) 
585   
586           
587          elif top_left and not selection: 
588               
589              if status.debug: 
590                  print("Multiple block selection.") 
591   
592               
593              cells = [] 
594   
595               
596              for n in range(len(top_left)): 
597                   
598                  cells = cells + self.get_all_coordinates(top_left[n], bottom_right[n]) 
599   
600               
601              return cells 
602   
603           
604          elif not selection and not top_left: 
605               
606              if status.debug: 
607                  print("Single cell.") 
608   
609               
610              pos = self.grid.GetGridCursorRow(), self.grid.GetGridCursorCol() 
611   
612               
613              return [pos] 
614   
615           
616          elif selection: 
617               
618              if status.debug: 
619                  print("Complex selection.") 
620   
621               
622              cells = [] 
623   
624               
625              for n in range(len(top_left)): 
626                   
627                  cells = cells + self.get_all_coordinates(top_left[n], bottom_right[n]) 
628   
629               
630              return cells + selection 
631   
632           
633          else: 
634               
635              if status.debug: 
636                  print("Should not be here.") 
 637   
638   
640          """The variable delay list loading GUI element. 
641   
642          @param event:   The wx event. 
643          @type event:    wx event 
644          """ 
645   
646           
647   
648           
649          if vc: 
650              try: 
651                  vc_factor = float(self.vc_time.GetValue()) 
652              except: 
653                  error_message('VC time is not a number.') 
654                  return 
655   
656           
657          else: 
658              vc_factor = 1 
659   
660           
661          dialog = RelaxFileDialog(parent=self, style=wx.FD_OPEN) 
662   
663           
664          if status.show_gui and dialog.ShowModal() != wx.ID_OK: 
665               
666              return 
667   
668           
669          filename = dialog.get_file() 
670   
671           
672          file = open(filename, 'r') 
673   
674           
675          index = 0 
676          for line in file: 
677               
678              try: 
679                  t = float(line.replace('/n', '')) 
680              except: 
681                  continue 
682   
683               
684              self.grid.SetCellValue(index, 1, str(t*vc_factor)) 
685   
686               
687              index = index + 1 
688   
689               
690              if index == self.num_rows: 
691                  error_message('Too many entries in list.') 
692                  return 
 693   
694   
696          """Function to load peak lists to data grid. 
697   
698          @param event:   The wx event. 
699          @type event:    wx event 
700          """ 
701   
702           
703          dialog = RelaxFileDialog(parent=self, message='Select the %s peak list file'%self.label, style=wx.FD_OPEN|wx.FD_MULTIPLE) 
704   
705           
706          if status.show_gui and dialog.ShowModal() != wx.ID_OK: 
707               
708              return 
709   
710           
711          files = dialog.get_file() 
712   
713           
714          index = 0 
715          for i in range(self.num_rows): 
716               
717              if str(self.grid.GetCellValue(i, 0)) == '': 
718                   
719                  self.grid.SetCellValue(i, 0, str(files[index])) 
720   
721                   
722                  index = index + 1 
723   
724                   
725                  if index == len(files): 
726                      break 
727   
728           
729          if index < (len(files)-1): 
730                  error_message('Not all files could be loaded.') 
 731   
732   
734          """Synchronise the rx analysis frame and the relax data store, both ways. 
735   
736          This method allows the frame information to be uploaded into the relax data store, or for the information in the relax data store to be downloaded by the frame. 
737   
738          @keyword upload:    A flag which if True will cause the frame to send data to the relax data store.  If False, data will be downloaded from the relax data store to update the frame. 
739          @type upload:       bool 
740          """ 
741   
742           
743          if upload: 
744               
745              self.data.delay_time = str(self.delay_time.GetString(0, self.delay_time.GetLastPosition())) 
746   
747               
748              for i in range(self.num_rows): 
749                   
750                  if not hasattr(self.data, 'file_list'): 
751                      self.data.file_list = [] 
752                  if not hasattr(self.data, 'ncyc'): 
753                      self.data.ncyc = [] 
754                  if not hasattr(self.data, 'relax_times'): 
755                      self.data.relax_times = [] 
756   
757                   
758                  file_name = str(self.grid.GetCellValue(i, 0)) 
759                  relax_time = str(self.grid.GetCellValue(i, 1)) 
760                  ncyc = str(self.grid.GetCellValue(i, 2)) 
761   
762                   
763                  if file_name == '' and ncyc == '': 
764                      break 
765   
766                   
767                  if i >= len(self.data.file_list): 
768                      self.data.file_list.append('') 
769                  if i >= len(self.data.ncyc): 
770                      self.data.ncyc.append('') 
771                  if i >= len(self.data.relax_times): 
772                      self.data.relax_times.append('') 
773   
774                   
775                  self.data.file_list[i] = file_name 
776                  self.data.ncyc[i] = ncyc 
777                  self.data.relax_times[i] = relax_time 
778   
779          else: 
780               
781              if hasattr(self.data, 'delay_time'): 
782                  self.delay_time.SetValue(str_to_gui(self.data.delay_time)) 
783   
784               
785              for i in range(len(self.data.file_list)): 
786                   
787                  if hasattr(self.data, 'file_list'): 
788                      self.grid.SetCellValue(i, 0, str_to_gui(self.data.file_list[i])) 
789   
790                   
791                  if hasattr(self.data, 'relax_times'): 
792                      self.grid.SetCellValue(i, 1, str_to_gui(self.data.relax_times[i])) 
793   
794                   
795                  if hasattr(self.data, 'ncyc'): 
796                      self.grid.SetCellValue(i, 2, str_to_gui(self.data.ncyc[i])) 
797   
798               
799              self.update_grid() 
 800   
801   
803          """Update the grid, changing the relaxation delay times as needed.""" 
804   
805           
806          time = self.delay_time.GetString(0, self.delay_time.GetLastPosition()) 
807          try: 
808              time = float(time) 
809          except ValueError: 
810              time = '' 
811   
812           
813          for i in range(self.grid.GetNumberRows()): 
814               
815              ncyc = str(self.grid.GetCellValue(i, 2)) 
816   
817               
818              if time != '' and ncyc not in ['', '0']: 
819                  self.grid.SetCellValue(i, 1, str(int(ncyc) * time)) 
820   
821               
822              relax_time = str(self.grid.GetCellValue(i, 1)) 
823   
824               
825              if relax_time == '0.0': 
826                  self.grid.SetCellValue(i, 1, '') 
  827