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