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