1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """The pipe editor GUI element."""
25
26
27 import wx
28 import wx.grid
29
30
31 from data import Relax_data_store; ds = Relax_data_store()
32 from generic_fns.pipes import cdp_name, delete, get_bundle, get_type, pipe_names, switch
33 from graphics import fetch_icon
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
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
110 - def Show(self, show=True):
129
130
132 """Activate or deactivate certain elements in response to the execution lock."""
133
134
135 if status.exec_lock.locked():
136 wx.CallAfter(self.button_bundle.Enable, False)
137 wx.CallAfter(self.button_create.Enable, False)
138 wx.CallAfter(self.button_copy.Enable, False)
139 wx.CallAfter(self.button_delete.Enable, False)
140 wx.CallAfter(self.button_hybrid.Enable, False)
141 wx.CallAfter(self.button_switch.Enable, False)
142
143
144 else:
145 wx.CallAfter(self.button_bundle.Enable, True)
146 wx.CallAfter(self.button_create.Enable, True)
147 wx.CallAfter(self.button_copy.Enable, True)
148 wx.CallAfter(self.button_delete.Enable, True)
149 wx.CallAfter(self.button_hybrid.Enable, True)
150 wx.CallAfter(self.button_switch.Enable, True)
151
152
154 """The pop up menu.
155
156 @param event: The wx event.
157 @type event: wx event
158 """
159
160
161 row = event.GetRow()
162
163
164 self.selected_pipe = gui_to_str(self.grid.GetCellValue(row, 0))
165
166
167 if not self.selected_pipe:
168 return
169
170
171 pipe_type = get_type(self.selected_pipe)
172 pipe_bundle = get_bundle(self.selected_pipe)
173
174
175 menu = wx.Menu()
176 items = []
177
178
179 if not pipe_bundle:
180 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))
181
182
183 items.append(build_menu_item(menu, parent=self, text="&Delete the pipe", icon=icon_16x16.remove, fn=self.pipe_delete))
184
185
186 items.append(build_menu_item(menu, parent=self, text="&Switch to this pipe", icon=icon_16x16.pipe_switch, fn=self.pipe_switch))
187
188
189 if pipe_bundle and self.gui.analysis.page_index_from_bundle(pipe_bundle) == None and pipe_type in ['noe', 'r1', 'r2', 'mf']:
190 items.append(build_menu_item(menu, parent=self, text="&Associate with a new auto-analysis", icon=icon_16x16.new, fn=self.associate_auto))
191
192
193 for item in items:
194 menu.AppendItem(item)
195 if status.exec_lock.locked():
196 item.Enable(False)
197
198
199 if status.show_gui:
200 self.PopupMenu(menu)
201
202
203 menu.Destroy()
204
205
264
265
267 """Launch the user function GUI wizards.
268
269 @param event: The wx event.
270 @type event: wx event
271 """
272
273
274 if event.GetEventObject() == self.button_bundle:
275 uf_store['pipe.bundle'](event, wx_parent=self)
276 elif event.GetEventObject() == self.button_create:
277 uf_store['pipe.create'](event, wx_parent=self)
278 elif event.GetEventObject() == self.button_copy:
279 uf_store['pipe.copy'](event, wx_parent=self)
280 elif event.GetEventObject() == self.button_delete:
281 uf_store['pipe.delete'](event, wx_parent=self)
282 elif event.GetEventObject() == self.button_hybrid:
283 uf_store['pipe.hybridise'](event, wx_parent=self)
284 elif event.GetEventObject() == self.button_switch:
285 uf_store['pipe.switch'](event, wx_parent=self)
286
287
289 """Add the logo to the sizer.
290
291 @param box: The sizer element to pack the logo into.
292 @type box: wx.Sizer instance
293 """
294
295
296 logo = wx.StaticBitmap(self.main_panel, -1, wx.Bitmap(WIZARD_IMAGE_PATH+'pipe_200x90.png', wx.BITMAP_TYPE_ANY))
297
298
299 box.Add(logo, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
300
301
303 """Add the table to the sizer.
304
305 @param sizer: The sizer element to pack the table into.
306 @type sizer: wx.Sizer instance
307 """
308
309
310 self.grid = wx.grid.Grid(self.main_panel, -1)
311
312
313 self.grid.CreateGrid(1, 5)
314
315
316 self.grid.SetColLabelValue(0, "Data pipe")
317 self.grid.SetColLabelValue(1, "Type")
318 self.grid.SetColLabelValue(2, "Bundle")
319 self.grid.SetColLabelValue(3, "Current")
320 self.grid.SetColLabelValue(4, "Analysis tab")
321
322
323 self.grid.SetDefaultCellFont(font.normal)
324 self.grid.SetLabelFont(font.normal_bold)
325
326
327 self.grid.SetRowLabelSize(self.width_col_label)
328
329
330 self.grid.EnableDragColSize(False)
331 self.grid.EnableDragRowSize(False)
332
333
334 sizer.Add(self.grid, 1, wx.ALL|wx.EXPAND, 0)
335
336
338 """Associate the selected data pipe with a new auto-analysis.
339
340 @param event: The wx event.
341 @type event: wx event
342 """
343
344
345 if not hasattr(ds, 'relax_gui'):
346 self.gui.init_data()
347
348
349 type = get_type(self.selected_pipe)
350 bundle = get_bundle(self.selected_pipe)
351
352
353 names = {
354 'noe': 'Steady-state NOE',
355 'r1': 'R1 relaxation',
356 'r2': 'R2 relaxation',
357 'mf': 'Model-free'
358 }
359
360
361 self.gui.analysis.new_analysis(analysis_type=type, analysis_name=names[type], pipe_name=self.selected_pipe, pipe_bundle=bundle)
362
363
365 """Event handler for the close window action.
366
367 @param event: The wx event.
368 @type event: wx event
369 """
370
371
372 status.observers.pipe_alteration.unregister(self.name)
373 status.observers.gui_analysis.unregister(self.name)
374 status.observers.exec_lock.unregister(self.name)
375
376
377 self.Hide()
378
379
381 """Bundle the date pipe.
382
383 @param event: The wx event.
384 @type event: wx event
385 """
386
387
388 uf_store['pipe.bundle'](event, wx_parent=self, pipe=self.selected_pipe)
389
390
392 """Delete the date pipe.
393
394 @param event: The wx event.
395 @type event: wx event
396 """
397
398
399 msg = "Are you sure you would like to delete the '%s' data pipe? This operation cannot be undone." % self.selected_pipe
400 if status.show_gui and Question(msg, parent=self, default=False).ShowModal() == wx.ID_NO:
401 return
402
403
404 delete(self.selected_pipe)
405
406
408 """Switch to the selected date pipe.
409
410 @param event: The wx event.
411 @type event: wx event
412 """
413
414
415 switch(self.selected_pipe)
416
417
418 wx.CallAfter(self.Raise)
419
420
422 """Catch the resize to allow the grid to be resized.
423
424 @param event: The wx event.
425 @type event: wx event
426 """
427
428
429 self.size_cols()
430
431
432 event.Skip()
433
434
436 """Set the column sizes."""
437
438
439 x, y = self.grid.GetSize()
440
441
442 n = 5
443
444
445 width_col_curr = 80
446
447
448 width = int((x - self.width_col_label - width_col_curr) / (n - 1))
449
450
451 for i in range(n):
452
453 if i == 3:
454 self.grid.SetColSize(i, width_col_curr)
455
456
457 else:
458 self.grid.SetColSize(i, width)
459
460
462 """Update the grid in a thread safe way using wx.CallAfter."""
463
464
465 wx.CallAfter(self.update_grid_safe)
466
467
468 wx.GetApp().Yield(True)
469
470
472 """Update the grid with the pipe data."""
473
474
475 self.grid.Freeze()
476
477
478 status.pipe_lock.acquire('pipe editor window')
479
480
481 self.grid.DeleteRows(numRows=self.grid.GetNumberRows()-1)
482
483
484 for i in range(self.grid.GetNumberCols()):
485 self.grid.SetCellValue(0, i, str_to_gui(""))
486
487
488 pipe_list = pipe_names()
489 n = len(pipe_list)
490
491
492 if n >= 1:
493 self.grid.AppendRows(numRows=n-1)
494
495
496 for i in range(n):
497
498 self.grid.SetCellValue(i, 0, str_to_gui(pipe_list[i]))
499
500
501 self.grid.SetCellValue(i, 1, str_to_gui(get_type(pipe_list[i])))
502
503
504 self.grid.SetCellValue(i, 2, str_to_gui(get_bundle(pipe_list[i])))
505
506
507 if pipe_list[i] == cdp_name():
508 self.grid.SetCellValue(i, 3, str_to_gui("cdp"))
509
510
511 self.grid.SetCellValue(i, 4, str_to_gui(self.gui.analysis.page_name_from_bundle(get_bundle(pipe_list[i]))))
512
513
514 for i in range(self.grid.GetNumberRows()):
515
516 self.grid.SetRowSize(i, 27)
517
518
519 for j in range(self.grid.GetNumberCols()):
520
521 self.grid.SetReadOnly(i, j)
522
523
524 status.pipe_lock.release('pipe editor window')
525
526
527 self.grid.Thaw()
528