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