1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module containing the special objects for auto-generating the GUI user functions and classes."""
24
25
26 from re import search
27 import wx
28 from wx.lib import scrolledpanel
29 import sys
30
31
32 import arg_check
33 from graphics import fetch_icon
34 from relax_errors import AllRelaxErrors, RelaxError
35 from relax_string import strip_lead
36 from status import Status; status = Status()
37 from user_functions.data import Uf_info; uf_info = Uf_info()
38 from user_functions.data import Uf_tables; uf_tables = Uf_tables()
39
40
41 from gui.components.free_file_format import Free_file_format
42 from gui.components.menu import build_menu_item
43 from gui.errors import gui_raise
44 from gui.fonts import font
45 from gui.input_elements.bool import Selector_bool
46 from gui.input_elements.dir import Selector_dir
47 from gui.input_elements.file import Selector_file
48 from gui.input_elements.sequence import Sequence
49 from gui.input_elements.sequence_2D import Sequence_2D
50 from gui.input_elements.spin_id import Spin_id
51 from gui.input_elements.value import Value
52 from gui.interpreter import Interpreter; interpreter = Interpreter()
53 from gui.misc import format_table
54 from gui.wizard import Wiz_page, Wiz_window
55
56
58 """Auto-generate the user function sub-menu.
59
60 @keyword parent: The parent window to bind the events to.
61 @type parent: wx instance
62 @keyword menubar: The menubar to attach the user function menus to.
63 @type menubar: wx.MenuBar instance
64 @return: The menu ID.
65 @rtype: int
66 """
67
68
69 menu1 = wx.Menu()
70 menu2 = wx.Menu()
71
72
73 pattern = '^[a-m]'
74
75
76 class_list = []
77 uf_store = Uf_storage()
78
79
80 class_item = None
81 menu = menu1
82 menu_index = 0
83 for name, data in uf_info.uf_loop():
84
85 if search('\.', name):
86 class_name, uf_name = name.split('.')
87 else:
88 class_name = None
89
90
91 if class_name:
92 if class_name not in class_list:
93
94 if class_item != None:
95 menu.AppendItem(class_item)
96
97
98 class_data = uf_info.get_class(class_name)
99
100
101 class_id = wx.NewId()
102
103
104 class_item = build_menu_item(menu, id=class_id, text=class_data.menu_text, icon=fetch_icon(class_data.gui_icon, size='16x16'))
105
106
107 sub_menu = wx.Menu()
108 class_item.SetSubMenu(sub_menu)
109
110
111 class_list.append(class_name)
112
113
114 sub_menu.AppendItem(build_menu_item(sub_menu, id=uf_store[name]._uf_id, text=data.menu_text, icon=fetch_icon(data.gui_icon, size='16x16')))
115
116
117 else:
118
119 if class_item != None:
120 menu.AppendItem(class_item)
121 class_item = None
122
123
124 menu.AppendItem(build_menu_item(menu, id=uf_store[name]._uf_id, text=data.menu_text, icon=fetch_icon(data.gui_icon, size='16x16')))
125
126
127 if menu_index == 0 and not search(pattern, name):
128 menu = menu2
129 menu_index = 1
130
131
132 parent.Bind(wx.EVT_MENU, parent.uf_call, id=uf_store[name]._uf_id)
133
134
135 if class_item != None:
136 menu.AppendItem(class_item)
137
138
139 title1 = "&User functions (a-m)"
140 title2 = "&User functions (n-z)"
141 menubar.Append(menu1, title1)
142 menubar.Append(menu2, title2)
143
144
145 return [menubar.FindMenu(title1), menubar.FindMenu(title2)]
146
147
148
150 """A special user function arg element which always returns True."""
151
153 """Initialise the object."""
154
155
156 self._value = True
157
158
160 """Simple method for returning the internal value."""
161
162
163 return self._value
164
165
167 """Internally store the value being set."""
168
169
170 self._value = value
171
172
173
175 """The object for auto-generating the GUI user functions."""
176
177 - def __call__(self, event=None, wx_parent=None, wx_wizard_sync=None, wx_wizard_run=True, wx_wizard_modal=False, **kwds):
178 """Make the GUI user function executable.
179
180 All keyword args, apart from 'event', 'wx_parent' and 'wx_wizard_run' will be assumed to be user function arguments and the Uf_page.SetValue() method of the page will be used to set the GUI arg elements to the values supplied.
181
182
183 @keyword event: The wx event.
184 @type event: wx event or None
185 @keyword wx_parent: The parent wx object to associate the user function wizard to.
186 @type wx_parent: wx object
187 @keyword wx_wizard_sync: A flag which if given will switch between synchronous and asynchronous user function operation.
188 @type wx_wizard_sync: None or bool
189 @keyword wx_wizard_run: A flag which if True will call the wizard run() method.
190 @type wx_wizard_run: bool
191 @keyword wx_wizard_modal: A flag which if True will cause the wizard run() method to have the modal flag set so that the wizard is modal.
192 @type wx_wizard_modal: bool
193 @return: The status of the call. If the call failed, False will be returned.
194 @rtype: bool
195 """
196
197
198 if wx_wizard_sync != None:
199 self._sync = wx_wizard_sync
200
201
202 if self.wizard == None or (wx_parent != None and wx_parent != self.wizard.GetParent()) or self.wizard._pages[0] == None:
203 status = self.create_wizard(wx_parent)
204 if not status:
205 return False
206
207
208 else:
209 self.wizard.reset()
210
211
212 if not self.page.update_args():
213 return False
214
215
216 for key in kwds:
217 self.page.SetValue(key, kwds[key])
218
219
220 if wx_wizard_run:
221 self.wizard.run(modal=wx_wizard_modal)
222
223
224 - def __init__(self, name, title=None, size=None, height_desc=None, apply_button=True, sync=False):
225 """Set up the object.
226
227 @param name: The name of the user function.
228 @type name: str
229 @keyword title: The long title of the user function to set as the window title.
230 @type title: str
231 @keyword size: The window size.
232 @type size: tuple of int
233 @keyword height_desc: The height in pixels of the description part of the wizard.
234 @type height_desc: int or None
235 @keyword apply_button: A flag specifying if the apply button should be shown or not. This defaults to True.
236 @type apply_button: bool
237 @keyword sync: A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
238 @type sync: bool
239 """
240
241
242 self._name = name
243 self._title = title
244 self._size = size
245 self._height_desc = height_desc
246 self._apply_button = apply_button
247 self._sync = sync
248
249
250 self.wizard = None
251
252
253 self._uf_id = wx.NewId()
254
255
256 - def create_page(self, wizard=None, sync=None):
257 """Create the user function wizard page GUI object.
258
259 @keyword wizard: The parent wizard.
260 @type wizard: Wiz_window instance
261 @keyword sync: A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
262 @type sync: None or bool
263 @return: The user function page object.
264 @rtype: Uf_page instance
265 """
266
267
268 if sync != None:
269 self._sync = sync
270
271
272 return Uf_page(self._name, parent=wizard, height_desc=self._height_desc, sync=self._sync)
273
274
276 """Create the user function wizard GUI object, with embedded wizard page.
277
278 @keyword parent: The parent wx window.
279 @type parent: wx.Window instance
280 @return: True if the wizard was created, False if a problem was encountered.
281 @rtype: bool
282 """
283
284
285 if parent == None:
286 app = wx.GetApp()
287 parent = app.gui
288
289
290 self.wizard = Wiz_window(parent=parent, size_x=self._size[0], size_y=self._size[1], title=self._title)
291
292
293 self.page = self.create_page(self.wizard, sync=self._sync)
294
295
296 if not self.page.update_args():
297 return False
298
299
300 self.wizard.add_page(self.page, apply_button=self._apply_button)
301
302
303 return True
304
305
306
307 -class Uf_page(Wiz_page):
308 """User function specific pages for the wizards."""
309
310 - def __init__(self, name, parent=None, height_desc=220, sync=False):
311 """Set up the window.
312
313 @param name: The name of the user function.
314 @type name: str
315 @keyword parent: The parent class containing the GUI.
316 @type parent: class instance
317 @keyword height_desc: The height in pixels of the description part of the wizard.
318 @type height_desc: int or None
319 @keyword sync: A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
320 @type sync: bool
321 """
322
323
324 self.name = name
325 self.sync = sync
326
327
328 self.uf_args = {}
329
330
331 wx.Yield()
332
333
334 wx.BeginBusyCursor()
335
336
337 self.uf_data = uf_info.get_uf(name)
338
339
340 self.image_path = self.uf_data.wizard_image
341
342
343 if self.uf_data.title_short != None:
344 self.title = self.uf_data.title_short
345 else:
346 self.title = self.uf_data.title
347
348
349 super(Uf_page, self).__init__(parent, height_desc=height_desc)
350
351
352 if wx.IsBusy():
353 wx.EndBusyCursor()
354
355
357 """Format the text by stripping whitespace.
358
359 @param text: The text to strip.
360 @type text: str
361 @return: The stripped text.
362 @rtype: str
363 """
364
365
366 stripped_text = strip_lead(text)
367
368
369 while True:
370 if stripped_text[0] == "\n":
371 stripped_text = stripped_text[1:]
372 else:
373 break
374
375
376 while True:
377 if stripped_text[-1] == "\n":
378 stripped_text = stripped_text[:-1]
379 else:
380 break
381
382
383 return stripped_text
384
385
386 - def _intro_text(self, keys, values, prompt=True):
387 """Build and return the user function intro text.
388
389 @param keys: The user function keys.
390 @type keys: list of str
391 @param values: The values corresponding to the keys.
392 @type values: list
393 @keyword prompt: A flag which if True will cause the prompt text to be included.
394 @type prompt: bool
395 @return: The user function intro text.
396 @rtype: str
397 """
398
399
400 text = ""
401
402
403 if prompt:
404 text += status.ps3
405
406
407 text += "%s(" % self.name
408
409
410 for i in range(len(keys)):
411
412 if i >= 1:
413 text += ", "
414
415
416 text += "%s=%s" % (keys[i], repr(values[i]))
417
418
419 text += ")"
420
421
422 return text
423
424
425 - def Clear(self, key):
426 """Special wizard method for clearing the value of the GUI element corresponding to the key.
427
428 @param key: The key corresponding to the desired GUI element.
429 @type key: str
430 """
431
432
433 self.uf_args[key].Clear()
434
435
436 - def GetValue(self, key):
437 """Special wizard method for getting the value of the GUI element corresponding to the key.
438
439 @param key: The key corresponding to the desired GUI element.
440 @type key: str
441 @return: The value that the specific GUI element's GetValue() method returns.
442 @rtype: unknown
443 """
444
445
446 if key not in self.uf_args.keys():
447 return None
448
449
450 return self.uf_args[key].GetValue()
451
452
453 - def SetValue(self, key, value):
454 """Special wizard method for setting the value of the GUI element corresponding to the key.
455
456 @param key: The key corresponding to the desired GUI element.
457 @type key: str
458 @param value: The value that the specific GUI element's SetValue() method expects.
459 @type value: unknown
460 """
461
462
463 arg = None
464 for i in range(len(self.uf_data.kargs)):
465 if self.uf_data.kargs[i]['name'] == key:
466 arg = self.uf_data.kargs[i]
467
468
469 if arg == None:
470 raise RelaxError("The key '%s' is unknown." % key)
471
472
473 if 'free_file_format' in self.uf_args and key in ['spin_id_col', 'mol_name_col', 'res_num_col', 'res_name_col', 'spin_num_col', 'spin_name_col', 'data_col', 'error_col', 'sep']:
474 self.uf_args['free_file_format'].SetValue(key, value)
475
476
477 elif arg['arg_type'] in ['func', 'func args']:
478 pass
479
480
481 else:
482 self.uf_args[key].SetValue(value)
483
484
485 - def UpdateChoices(self, key, combo_choices=None, combo_data=None, combo_default=None):
486 """Special user function page method for updating the list of choices in a ComboBox type element.
487
488 @param key: The key corresponding to the desired GUI element.
489 @type key: str
490 @keyword combo_choices: The list of choices to present to the user. This is only used if the element_type is set to 'combo'.
491 @type combo_choices: list of str
492 @keyword combo_data: The data returned by a call to GetValue(). This is only used if the element_type is set to 'combo'. If supplied, it should be the same length at the combo_choices list. If not supplied, the combo_choices list will be used for the returned data.
493 @type combo_data: list
494 @keyword combo_default: The default value of the ComboBox. This is only used if the element_type is set to 'combo'.
495 @type combo_default: str or None
496 """
497
498
499 self.uf_args[key].UpdateChoices(combo_choices=combo_choices, combo_data=combo_data, combo_default=combo_default)
500
501
502 - def add_contents(self, sizer):
503 """Add the specific GUI elements.
504
505 @param sizer: A sizer object.
506 @type sizer: wx.Sizer instance
507 """
508
509
510 free_format = False
511 free_format_data = False
512
513
514 for i in range(len(self.uf_data.kargs)):
515
516 arg = self.uf_data.kargs[i]
517
518
519 desc = "The %s:" % arg['desc_short']
520
521
522 if arg['arg_type'] == 'file sel':
523 self.uf_args[arg['name']] = Selector_file(name=arg['name'], parent=self, default=arg['default'], sizer=sizer, desc=desc, wildcard=arg['wiz_filesel_wildcard'], style=arg['wiz_filesel_style'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, read_only=arg['wiz_read_only'])
524
525
526 elif arg['arg_type'] == 'dir':
527 pass
528
529
530 elif arg['arg_type'] == 'dir sel':
531 self.uf_args[arg['name']] = Selector_dir(name=arg['name'], parent=self, default=arg['default'], sizer=sizer, desc=desc, style=arg['wiz_dirsel_style'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, read_only=arg['wiz_read_only'])
532
533
534 elif arg['arg_type'] == 'free format':
535
536 free_format = True
537 if arg['name'] == 'data_col':
538 free_format_data = True
539
540
541 elif arg['arg_type'] in ['func', 'func args']:
542 pass
543
544
545 elif arg['arg_type'] in ['force flag']:
546 self.uf_args[arg['name']] = Force_true()
547
548
549 elif arg['arg_type'] in ['spin ID']:
550 self.uf_args[arg['name']] = Spin_id(name=arg['name'], parent=self, default=arg['default'], element_type=arg['wiz_element_type'], sizer=sizer, desc=desc, combo_choices=arg['wiz_combo_choices'], combo_data=arg['wiz_combo_data'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, can_be_none=arg['can_be_none'])
551
552
553 elif arg['py_type'] in ['float', 'int', 'num', 'str']:
554 self.uf_args[arg['name']] = Value(name=arg['name'], parent=self, default=arg['default'], element_type=arg['wiz_element_type'], value_type=arg['py_type'], min=arg['min'], max=arg['max'], sizer=sizer, desc=desc, combo_choices=arg['wiz_combo_choices'], combo_data=arg['wiz_combo_data'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, read_only=arg['wiz_read_only'], can_be_none=arg['can_be_none'])
555
556
557 elif arg['py_type'] == 'bool':
558 self.uf_args[arg['name']] = Selector_bool(name=arg['name'], parent=self, element_type=arg['wiz_element_type'], sizer=sizer, desc=desc, tooltip=arg['desc'], default=arg['default'], divider=self._div_left, height_element=self.height_element)
559
560
561 elif arg['py_type'] in ['float_list', 'int_list', 'num_list', 'str_list', 'float_tuple', 'int_tuple', 'num_tuple', 'str_tuple', 'float_array', 'int_array', 'float_or_float_list', 'int_or_int_list', 'num_or_num_list', 'str_or_str_list', 'float_or_float_tuple', 'int_or_int_tuple', 'num_or_num_tuple', 'str_or_str_tuple', 'val_or_list']:
562
563 if arg['py_type'] in ['float_list', 'int_list', 'num_list', 'str_list', 'float_array', 'int_array', 'float_or_float_list', 'int_or_int_list', 'num_or_num_list', 'str_or_str_list', 'val_or_list']:
564 seq_type = 'list'
565 else:
566 seq_type = 'tuple'
567
568
569 if arg['py_type'] in ['float_list', 'num_list', 'float_tuple', 'num_tuple', 'float_array', 'float_or_float_list', 'num_or_num_list', 'float_or_float_tuple', 'num_or_num_tuple']:
570 value_type = 'float'
571 elif arg['py_type'] in ['int_list', 'int_tuple', 'int_array', 'int_or_int_list', 'int_or_int_tuple']:
572 value_type = 'int'
573 elif arg['py_type'] in ['str_list', 'str_tuple', 'str_array', 'str_or_str_list', 'str_or_str_tuple']:
574 value_type = 'str'
575 else:
576 value_type = None
577
578
579 single_value = False
580 if arg['py_type'] in ['float_or_float_list', 'int_or_int_list', 'num_or_num_list', 'str_or_str_list', 'float_or_float_tuple', 'int_or_int_tuple', 'num_or_num_tuple', 'str_or_str_tuple', 'val_or_list']:
581 single_value = True
582
583
584 dim = None
585 if isinstance(arg['dim'], int):
586 dim = arg['dim']
587
588 self.uf_args[arg['name']] = Sequence(name=arg['name'], parent=self, default=arg['default'], element_type=arg['wiz_element_type'], seq_type=seq_type, value_type=value_type, dim=dim, min=arg['min'], max=arg['max'], sizer=sizer, desc=desc, combo_choices=arg['wiz_combo_choices'], combo_data=arg['wiz_combo_data'], combo_list_min=arg['wiz_combo_list_min'], tooltip=arg['desc'], single_value=single_value, divider=self._div_left, height_element=self.height_element, read_only=arg['wiz_read_only'], can_be_none=arg['can_be_none'])
589
590
591 elif arg['py_type'] in ['float_list_of_lists', 'int_list_of_lists', 'num_list_of_lists', 'str_list_of_lists', 'float_tuple_of_tuples', 'int_tuple_of_tuples', 'num_tuple_of_tuples', 'str_tuple_of_tuples', 'float_matrix', 'int_matrix']:
592
593 if arg['py_type'] in ['float_list_of_lists', 'int_list_of_lists', 'num_list_of_lists', 'str_list_of_lists', 'float_matrix', 'int_matrix']:
594 seq_type = 'list'
595 else:
596 seq_type = 'tuple'
597
598
599 if arg['py_type'] in ['float_list_of_lists', 'float_tuple_of_tuples', 'num_list_of_lists', 'num_tuple_of_tuples', 'float_matrix']:
600 value_type = 'float'
601 elif arg['py_type'] in ['int_list_of_lists', 'int_tuple_of_tuples', 'int_matrix']:
602 value_type = 'int'
603 else:
604 value_type = 'str'
605
606 self.uf_args[arg['name']] = Sequence_2D(name=arg['name'], parent=self, default=arg['default'], sizer=sizer, element_type=arg['wiz_element_type'], seq_type=seq_type, value_type=value_type, dim=arg['dim'], min=arg['min'], max=arg['max'], titles=arg['list_titles'], desc=desc, combo_choices=arg['wiz_combo_choices'], combo_data=arg['wiz_combo_data'], combo_list_min=arg['wiz_combo_list_min'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, read_only=arg['wiz_read_only'], can_be_none=arg['can_be_none'])
607
608
609 else:
610 raise RelaxError("The Python object type '%s' cannot be handled." % arg['py_type'])
611
612
613 if free_format:
614 self.uf_args['free_file_format'] = Free_file_format(sizer, parent=self, data_cols=free_format_data, padding=3, spacer=0)
615
616
617 - def add_desc(self, sizer, max_y=220):
618 """Add the description to the dialog.
619
620 @param sizer: A sizer object.
621 @type sizer: wx.Sizer instance
622 @keyword max_y: The maximum height, in number of pixels, for the description.
623 @type max_y: int
624 """
625
626
627 spacing = 15
628
629
630 sizer.AddSpacer(5)
631 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0)
632 sizer.AddSpacer(5)
633
634
635 panel = scrolledpanel.ScrolledPanel(self, -1, name="desc")
636
637
638 panel_sizer = wx.BoxSizer(wx.VERTICAL)
639
640
641 tot_y = 0
642 text_elements = []
643 text_types = []
644
645
646 name = "The %s user function" % self.name
647 text = wx.StaticText(panel, -1, name, style=wx.TE_MULTILINE)
648 text.SetFont(font.subtitle)
649 text_elements.append(text)
650 text_types.append('title')
651
652
653 x, y = text.GetSizeTuple()
654 tot_y += y
655 tot_y += spacing
656
657
658 if self.uf_data.title:
659
660 text = wx.StaticText(panel, -1, self.uf_data.title, style=wx.TE_MULTILINE)
661
662
663 text.SetFont(font.normal_italic)
664
665
666 x, y = text.GetSizeTuple()
667 tot_y += y
668
669
670 tot_y += spacing
671
672
673 text_elements.append(text)
674 text_types.append('synopsis')
675
676
677 if self.uf_data.desc != None:
678
679 for i in range(len(self.uf_data.desc)):
680
681 desc = self.uf_data.desc[i]
682
683
684 if desc.get_title() == 'Prompt examples':
685 continue
686
687
688 for type, element in desc.element_loop(title=True):
689
690 text = ''
691 if isinstance(element, str):
692 text = element
693
694
695 if type == 'table':
696 text = format_table(uf_tables.get_table(element))
697
698
699 elif type == 'list':
700
701 for j in range(len(element)):
702 text += " - %s\n" % element[j]
703
704
705 elif type == 'item list':
706
707 for j in range(len(element)):
708
709 if element[j][0] in [None, '']:
710 text += " %s\n" % element[j][1]
711 else:
712 text += " %s: %s\n" % (element[j][0], element[j][1])
713
714
715 text_obj = wx.StaticText(panel, -1, text, style=wx.TE_MULTILINE)
716
717
718 if type == 'title':
719 text_obj.SetFont(font.subtitle)
720 elif type == 'paragraph':
721 text_obj.SetFont(font.normal)
722 elif type in ['table', 'verbatim']:
723 text_obj.SetFont(font.modern_small)
724 else:
725 text_obj.SetFont(font.normal)
726
727
728 if type in ['paragraph', 'list', 'item list']:
729 text_obj.Wrap(self._main_size - 20)
730
731
732 x, y = text_obj.GetSizeTuple()
733 tot_y += y
734
735
736 tot_y += spacing
737
738
739 if i != 0 and type == 'title':
740 tot_y += spacing
741
742
743 text_elements.append(text_obj)
744 text_types.append(type)
745
746
747 tot_y -= spacing
748 tot_y += 20
749
750
751 if tot_y > max_y:
752 panel.SetInitialSize((self._main_size, max_y))
753
754
755 else:
756 panel.SetInitialSize((self._main_size, tot_y))
757
758
759 n = len(text_elements)
760 for i in range(n):
761
762 if i > 1 and text_types[i] == 'title':
763 panel_sizer.AddSpacer(spacing)
764
765
766 panel_sizer.Add(text_elements[i], 0, wx.ALIGN_LEFT, 0)
767
768
769 if i != n - 1:
770 panel_sizer.AddSpacer(spacing)
771
772
773 panel.SetSizer(panel_sizer)
774 panel.SetAutoLayout(1)
775 panel.SetupScrolling(scroll_x=False, scroll_y=True)
776 sizer.Add(panel, 0, wx.ALL|wx.EXPAND)
777
778
779 sizer.AddSpacer(5)
780 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0)
781 sizer.AddSpacer(5)
782
783
784 - def execute(self, uf, *args, **kwds):
785 """Execute the user function, either asynchronously or synchronously.
786
787 @param uf: The user function as a string.
788 @type uf: str
789 @param args: The user function arguments.
790 @type args: any arguments
791 @param kwds: The user function keyword arguments.
792 @type kwds: any keyword arguments
793 """
794
795
796 if self.sync or status.gui_uf_force_sync:
797 return_status = interpreter.apply(uf, *args, **kwds)
798 return return_status
799
800
801 else:
802 interpreter.queue(uf, *args, **kwds)
803 return True
804
805
807 """Remove this page from the observers."""
808
809
810 status.observers.gui_uf.unregister(self.name)
811
812
813 - def on_display(self):
814 """Clear and update the data if needed."""
815
816
817 status.observers.gui_uf.register(self.name, self.update_args, method_name='update_args')
818
819
820 return self.update_args()
821
822
823 - def on_execute(self):
824 """Execute the user function."""
825
826
827 kargs = {}
828 for i in range(len(self.uf_data.kargs)):
829
830 name = self.uf_data.kargs[i]['name']
831
832
833 kargs[name] = self.GetValue(name)
834
835
836 if self.uf_data.kargs[i]['wiz_combo_list_min'] != None and kargs[name] == None:
837 return True
838
839
840 if 'free_file_format' in self.uf_args:
841 kargs.update(self.uf_args['free_file_format'].GetValue())
842
843
844 if self.uf_data.display:
845
846 app = wx.GetApp()
847
848
849 app.gui.show_controller(None)
850
851
852 app.gui.controller.log_panel.on_goto_end(None)
853
854
855 if status.uf_intro:
856
857 keys = []
858 values = []
859 for i in range(len(self.uf_data.kargs)):
860 keys.append(self.uf_data.kargs[i]['name'])
861 values.append(kargs[self.uf_data.kargs[i]['name']])
862
863
864 print(self._intro_text(keys, values))
865
866
867 return_status = self.execute(self.name, **kargs)
868
869
870 if status.show_gui and self.uf_data.display:
871 wx.CallAfter(app.gui.controller.Raise)
872
873
874 return return_status
875
876
878 """Remove this page from the observers."""
879
880
881 status.observers.gui_uf.unregister(self.name)
882
883
884 - def update_args(self):
885 """Update all the argument ComboBox choices.
886
887 @return: The status of the update - False if a RelaxError occurs, True otherwise.
888 @rtype: bool
889 """
890
891
892 for i in range(len(self.uf_data.kargs)):
893
894 name = self.uf_data.kargs[i]['name']
895
896
897 iterator = self.uf_data.kargs[i]['wiz_combo_iter']
898 if iterator == None:
899 continue
900
901
902 try:
903 choices = []
904 data = []
905 for vals in iterator():
906 if arg_check.is_tuple(vals, size=2, raise_error=False):
907 choices.append(vals[0])
908 data.append(vals[1])
909 else:
910 choices.append(vals)
911 data.append(vals)
912
913
914 except AllRelaxErrors:
915 instance = sys.exc_info()[1]
916
917
918 self.setup_fail = True
919
920
921 gui_raise(instance)
922
923
924 return False
925
926
927 val = self.uf_args[name].GetValue()
928
929
930 self.UpdateChoices(name, combo_choices=choices, combo_data=data, combo_default=val)
931
932
933 return True
934
935
936
938 """A singleton container for holding all the GUI user functions."""
939
940
941 _instance = None
942
943 - def __new__(self, *args, **kargs):
966
967
969 """Return the name of the user function corresponding to the given wx ID.
970
971 @keyword id: The unique wx ID number.
972 @type id: int
973 @return: The name of the user function.
974 @rtype: str
975 """
976
977
978 for name in self.keys():
979 if self[name]._uf_id == id:
980 return name
981