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