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