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