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, Selector_file_multiple 
  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'] == 'file sel multi': 
 530                  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']) 
 531   
 532               
 533              elif arg['arg_type'] == 'dir': 
 534                  pass 
 535   
 536               
 537              elif arg['arg_type'] == 'dir sel': 
 538                  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']) 
 539   
 540               
 541              elif arg['arg_type'] == 'free format': 
 542                   
 543                  free_format = True 
 544                  if arg['name'] == 'data_col': 
 545                      free_format_data = True 
 546   
 547               
 548              elif arg['arg_type'] in ['func', 'func args']: 
 549                  pass 
 550   
 551               
 552              elif arg['arg_type'] in ['force flag']: 
 553                  self.uf_args[arg['name']] = Force_true() 
 554   
 555               
 556              elif arg['arg_type'] in ['spin ID']: 
 557                  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']) 
 558   
 559               
 560              elif arg['py_type'] in ['float', 'int', 'num', 'str']: 
 561                  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']) 
 562   
 563               
 564              elif arg['py_type'] == 'bool': 
 565                  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) 
 566   
 567               
 568              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']: 
 569                   
 570                  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']: 
 571                      seq_type = 'list' 
 572                  else: 
 573                      seq_type = 'tuple' 
 574   
 575                   
 576                  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']: 
 577                      value_type = 'float' 
 578                  elif arg['py_type'] in ['int_list', 'int_tuple', 'int_array', 'int_or_int_list', 'int_or_int_tuple']: 
 579                      value_type = 'int' 
 580                  elif arg['py_type'] in ['str_list', 'str_tuple', 'str_array', 'str_or_str_list', 'str_or_str_tuple']: 
 581                      value_type = 'str' 
 582                  else: 
 583                      value_type = None 
 584   
 585                   
 586                  single_value = False 
 587                  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']: 
 588                      single_value = True 
 589   
 590                   
 591                  dim = None 
 592                  if isinstance(arg['dim'], int): 
 593                      dim = arg['dim'] 
 594   
 595                  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']) 
 596   
 597               
 598              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']: 
 599                   
 600                  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']: 
 601                      seq_type = 'list' 
 602                  else: 
 603                      seq_type = 'tuple' 
 604   
 605                   
 606                  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']: 
 607                      value_type = 'float' 
 608                  elif arg['py_type'] in ['int_list_of_lists', 'int_tuple_of_tuples', 'int_matrix']: 
 609                      value_type = 'int' 
 610                  else: 
 611                      value_type = 'str' 
 612   
 613                  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']) 
 614   
 615               
 616              else: 
 617                  raise RelaxError("The Python object type '%s' cannot be handled." % arg['py_type']) 
 618   
 619           
 620          if free_format: 
 621              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) 
  622   
 623   
 624 -    def add_desc(self, sizer, max_y=220): 
  625          """Add the description to the dialog. 
 626   
 627          @param sizer:   A sizer object. 
 628          @type sizer:    wx.Sizer instance 
 629          @keyword max_y: The maximum height, in number of pixels, for the description. 
 630          @type max_y:    int 
 631          """ 
 632   
 633           
 634          spacing = 15 
 635   
 636           
 637          sizer.AddSpacer(5) 
 638          sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 
 639          sizer.AddSpacer(5) 
 640   
 641           
 642          panel = scrolledpanel.ScrolledPanel(self, -1, name="desc") 
 643   
 644           
 645          panel_sizer = wx.BoxSizer(wx.VERTICAL) 
 646   
 647           
 648          tot_y = 0 
 649          text_elements = [] 
 650          text_types = [] 
 651   
 652           
 653          name = "The %s user function" % self.name 
 654          text = wx.StaticText(panel, -1, name, style=wx.TE_MULTILINE) 
 655          text.SetFont(font.subtitle) 
 656          text_elements.append(text) 
 657          text_types.append('title') 
 658   
 659           
 660          x, y = text.GetSizeTuple() 
 661          tot_y += y 
 662          tot_y += spacing 
 663   
 664           
 665          if self.uf_data.title: 
 666               
 667              text = wx.StaticText(panel, -1, self.uf_data.title, style=wx.TE_MULTILINE) 
 668   
 669               
 670              text.SetFont(font.normal_italic) 
 671   
 672               
 673              x, y = text.GetSizeTuple() 
 674              tot_y += y 
 675   
 676               
 677              tot_y += spacing 
 678   
 679               
 680              text_elements.append(text) 
 681              text_types.append('synopsis') 
 682   
 683           
 684          if self.uf_data.desc != None: 
 685               
 686              for i in range(len(self.uf_data.desc)): 
 687                   
 688                  desc = self.uf_data.desc[i] 
 689   
 690                   
 691                  if desc.get_title() == 'Prompt examples': 
 692                      continue 
 693   
 694                   
 695                  for type, element in desc.element_loop(title=True): 
 696                       
 697                      text = '' 
 698                      if isinstance(element, str): 
 699                          text = element 
 700   
 701                       
 702                      if type == 'table': 
 703                          text = format_table(uf_tables.get_table(element)) 
 704   
 705                       
 706                      elif type == 'list': 
 707                           
 708                          for j in range(len(element)): 
 709                              text += "    - %s\n" % element[j] 
 710   
 711                       
 712                      elif type == 'item list': 
 713                           
 714                          for j in range(len(element)): 
 715                               
 716                              if element[j][0] in [None, '']: 
 717                                  text += "    %s\n" % element[j][1] 
 718                              else: 
 719                                  text += "    %s:  %s\n" % (element[j][0], element[j][1]) 
 720   
 721                       
 722                      elif type == 'prompt': 
 723                          for j in range(len(element)): 
 724                              text += "%s\n" % element[j] 
 725   
 726                       
 727                      text_obj = wx.StaticText(panel, -1, text, style=wx.TE_MULTILINE) 
 728   
 729                       
 730                      if type == 'title': 
 731                          text_obj.SetFont(font.subtitle) 
 732                      elif type == 'paragraph': 
 733                          text_obj.SetFont(font.normal) 
 734                      elif type in ['table', 'verbatim', 'prompt']: 
 735                          text_obj.SetFont(font.modern_small) 
 736                      else: 
 737                          text_obj.SetFont(font.normal) 
 738   
 739                       
 740                      if type in ['paragraph', 'list', 'item list']: 
 741                          text_obj.Wrap(self._main_size - 20) 
 742   
 743                       
 744                      x, y = text_obj.GetSizeTuple() 
 745                      tot_y += y 
 746   
 747                       
 748                      tot_y += spacing 
 749   
 750                       
 751                      if i != 0 and type == 'title': 
 752                          tot_y += spacing 
 753   
 754                       
 755                      text_elements.append(text_obj) 
 756                      text_types.append(type) 
 757   
 758           
 759          tot_y -= spacing 
 760          tot_y += 20 
 761   
 762           
 763          if tot_y > max_y: 
 764              panel.SetInitialSize((self._main_size, max_y)) 
 765   
 766           
 767          else: 
 768              panel.SetInitialSize((self._main_size, tot_y)) 
 769   
 770           
 771          n = len(text_elements) 
 772          for i in range(n): 
 773               
 774              if i > 1 and text_types[i] == 'title': 
 775                  panel_sizer.AddSpacer(spacing) 
 776   
 777               
 778              panel_sizer.Add(text_elements[i], 0, wx.ALIGN_LEFT, 0) 
 779   
 780               
 781              if i != n - 1: 
 782                  panel_sizer.AddSpacer(spacing) 
 783   
 784           
 785          panel.SetSizer(panel_sizer) 
 786          panel.SetAutoLayout(1) 
 787          panel.SetupScrolling(scroll_x=False, scroll_y=True) 
 788          sizer.Add(panel, 0, wx.ALL|wx.EXPAND) 
 789   
 790           
 791          sizer.AddSpacer(5) 
 792          sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 
 793          sizer.AddSpacer(5) 
  794   
 795   
 796 -    def execute(self, uf, *args, **kwds): 
  797          """Execute the user function, either asynchronously or synchronously. 
 798   
 799          @param uf:      The user function as a string. 
 800          @type uf:       str 
 801          @param args:    The user function arguments. 
 802          @type args:     any arguments 
 803          @param kwds:    The user function keyword arguments. 
 804          @type kwds:     any keyword arguments 
 805          """ 
 806   
 807           
 808          if self.sync or status.gui_uf_force_sync: 
 809              return_status = interpreter.apply(uf, *args, **kwds) 
 810              return return_status 
 811   
 812           
 813          else: 
 814              interpreter.queue(uf, *args, **kwds) 
 815              return True 
  816   
 817   
 819          """Remove this page from the observers.""" 
 820   
 821           
 822          status.observers.gui_uf.unregister(self.name) 
  823   
 824   
 825 -    def on_display(self): 
  826          """Clear and update the data if needed.""" 
 827   
 828           
 829          status.observers.gui_uf.register(self.name, self.update_args, method_name='update_args') 
 830   
 831           
 832          return self.update_args() 
  833   
 834   
 835 -    def on_execute(self, force_exec=False): 
  836          """Execute the user function. 
 837   
 838          @keyword force_exec:    A flag which if True will cause the execution flag to be ignored and the user function to be executed. 
 839          @type force_exec:       bool 
 840          """ 
 841   
 842           
 843          if not force_exec and not self.execute_flag: 
 844              return 
 845   
 846           
 847          kargs = {} 
 848          for i in range(len(self.uf_data.kargs)): 
 849               
 850              name = self.uf_data.kargs[i]['name'] 
 851   
 852               
 853              kargs[name] = self.GetValue(name) 
 854   
 855               
 856              if self.uf_data.kargs[i]['wiz_combo_list_min'] != None and kargs[name] == None: 
 857                  return True 
 858   
 859           
 860          if 'free_file_format' in self.uf_args: 
 861              kargs.update(self.uf_args['free_file_format'].GetValue()) 
 862   
 863           
 864          if self.uf_data.display: 
 865               
 866              app = wx.GetApp() 
 867   
 868               
 869              app.gui.show_controller(None) 
 870   
 871               
 872              app.gui.controller.log_panel.on_goto_end(None) 
 873   
 874           
 875          if status.uf_intro: 
 876               
 877              keys = [] 
 878              values = [] 
 879              for i in range(len(self.uf_data.kargs)): 
 880                  keys.append(self.uf_data.kargs[i]['name']) 
 881                  values.append(kargs[self.uf_data.kargs[i]['name']]) 
 882   
 883               
 884              print(self._intro_text(keys, values)) 
 885   
 886           
 887          return_status = self.execute(self.name, **kargs) 
 888   
 889           
 890          if status.show_gui and self.uf_data.display: 
 891              wx.CallAfter(app.gui.controller.Raise) 
 892   
 893           
 894          return return_status 
  895   
 896   
 898          """Remove this page from the observers.""" 
 899   
 900           
 901          status.observers.gui_uf.unregister(self.name) 
  902   
 903   
 904 -    def update_args(self): 
  905          """Update all the argument ComboBox choices. 
 906   
 907          @return:    The status of the update - False if a RelaxError occurs, True otherwise. 
 908          @rtype:     bool 
 909          """ 
 910   
 911           
 912          for i in range(len(self.uf_data.kargs)): 
 913               
 914              name = self.uf_data.kargs[i]['name'] 
 915   
 916               
 917              iterator = self.uf_data.kargs[i]['wiz_combo_iter'] 
 918              if iterator == None: 
 919                  continue 
 920   
 921               
 922              try: 
 923                  choices = [] 
 924                  data = [] 
 925                  for vals in iterator(): 
 926                      if lib.arg_check.is_tuple(vals, size=2, raise_error=False) or lib.arg_check.is_list(vals, size=2, raise_error=False): 
 927                          choices.append(vals[0]) 
 928                          data.append(vals[1]) 
 929                      else: 
 930                          choices.append(vals) 
 931                          data.append(vals) 
 932   
 933               
 934              except AllRelaxErrors: 
 935                  instance = sys.exc_info()[1] 
 936   
 937                   
 938                  self.setup_fail = True 
 939   
 940                   
 941                  gui_raise(instance) 
 942   
 943                   
 944                  return False 
 945   
 946               
 947              val = self.uf_args[name].GetValue() 
 948   
 949               
 950              self.UpdateChoices(name, combo_choices=choices, combo_data=data, combo_default=val) 
 951   
 952           
 953          return True 
   954   
 955   
 956   
 958      """A singleton container for holding all the GUI user functions.""" 
 959   
 960       
 961      _instance = None 
 962   
 963 -    def __new__(self, *args, **kargs): 
  986   
 987   
 989          """Return the name of the user function corresponding to the given wx ID. 
 990   
 991          @keyword id:    The unique wx ID number. 
 992          @type id:       int 
 993          @return:        The name of the user function. 
 994          @rtype:         str 
 995          """ 
 996   
 997           
 998          for name in self.keys(): 
 999              if self[name]._uf_id == id: 
1000                  return name 
  1001