Ignore:
Timestamp:
Apr 5, 2015 1:15:33 PM (9 years ago)
Author:
butler
Branches:
master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, release_4.0.1, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
Children:
439420f9
Parents:
0fa825c
Message:

Major Refactoring and clean up of the TextDiaolg? in model_editor.py.
This fixes the completely broken custom composite model editor (ticket
#401), significantly simplifies and improves readability of the code and
adds a lot of documentation in the form of both doc strings and in line
comments. Still could use more cleanup.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/sas/perspectives/calculator/model_editor.py

    r49ab5d7 r7b1f4e3  
     1''' 
     2This module provides three model editor classes: the composite model editor, 
     3the easy editor which provides a simple interface with tooltip help to enter 
     4the parameters of the model and their default value and a panel to input a  
     5function of y (usually the intensity).  It also provides a drop down of  
     6standard available math functions.  Finally a full python editor panel for 
     7complete customizatin is provided. 
     8 
     9:TODO the writiong of the file and name checking (and maybe some other 
     10funtions?) should be moved to a computational module which could be called 
     11fropm a python script.  Basically one just needs to pass the name, 
     12description text and function text (or in the case of the composite editor  
     13the names of the first and second model and the operator to be used). 
     14''' 
     15 
    116################################################################################ 
    217#This software was developed by the University of Tennessee as part of the 
     
    1227import os 
    1328import math 
     29import re 
    1430from wx.py.editwindow import EditWindow 
    1531 
     
    5369class TextDialog(wx.Dialog): 
    5470    """ 
    55     Dialog for easy custom sum models 
     71    Dialog for easy custom composite models.  Provides a wx.Dialog panel 
     72    to choose two existing models (including pre-existing custom models which 
     73    may themselves be sum models) as well as an operation on those models (add  
     74    or multiply) the resulting model will add a scale parameter for summed  
     75    models and a background parameter for a multiplied model. 
     76     
     77    The user also gives a brief help for the model in a description box and  
     78    must provide a unique name which is verified as unique before the new 
     79    model is saved. 
     80     
     81    This Dialog pops up for the user when they press 'Sum|Multi(p1,p2)' under 
     82    'Edit Custom Model' under 'Fitting' menu.  This is currently called as 
     83    a Modal Dialog. 
     84     
     85    :TODO the build in compiler currently balks at when it tries to import 
     86    a model whose name contains spaces or symbols (such as + ... underscore  
     87    should be fine) need to either alter how the model file is written on add 
     88    checking method to look for non-approved characters.  - PDB:April 5, 2015 
    5689    """ 
    5790    def __init__(self, parent=None, base=None, id=None, title='', 
    5891                 model_list=[], plugin_dir=None): 
    5992        """ 
    60         Dialog window popup when selecting 'Easy Custom Sum/Multiply' 
    61         on the menu 
     93        This class is run when instatiated.  The __init__ intializes and 
     94        calls the internal methods necessary.  On exiting the wx.Dialog 
     95        window should be destroyed. 
     96 
    6297        """ 
    6398        wx.Dialog.__init__(self, parent=parent, id=id, 
     
    67102        self.SetWindowVariant(variant=FONT_VARIANT) 
    68103        # default 
    69         self.font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT) 
    70         self.font.SetPointSize(10) 
    71104        self.overwrite_name = False 
    72105        self.plugin_dir = plugin_dir 
     
    77110        self.factor = 'scale_factor' 
    78111        self._notes = '' 
    79         self.operator = '+' 
    80         self.operator_cbox = None 
     112        self._operator = '+' 
     113        self._operator_choice = None 
    81114        self.explanation = '' 
    82115        self.explanationctr = None 
    83         self.sizer = None 
     116        self.type = None 
    84117        self.name_sizer = None 
    85         self.name_hsizer = None 
     118        self.name_tcl = None 
    86119        self.desc_sizer = None 
    87120        self.desc_tcl = None 
     121        self._selection_box= None 
    88122        self.model1 = None 
    89123        self.model2 = None 
     
    107141        Do the layout for file/function name related widgets 
    108142        """ 
    109         self.name_sizer = wx.BoxSizer(wx.VERTICAL) 
    110         self.name_hsizer = wx.BoxSizer(wx.HORIZONTAL) 
    111         #title name [string] 
    112         name_txt = wx.StaticText(self, -1, 'Function Name : ') 
    113         self.name_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1)) 
     143        #container for new model name input 
     144        self.name_sizer = wx.BoxSizer(wx.HORIZONTAL) 
     145 
     146        #set up label and input box with tool tip and event handling 
     147        self.name_txt = wx.StaticText(self, -1, 'Function Name : ') 
     148        self.name_tcl = wx.TextCtrl(self, -1, value = 'MySumFunction') 
    114149        self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name) 
    115         self.name_tcl.SetValue('') 
    116         self.name_tcl.SetFont(self.font) 
    117150        hint_name = "Unique Sum/Multiply Model Function Name." 
    118151        self.name_tcl.SetToolTipString(hint_name) 
    119         self.name_hsizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10), 
     152 
     153        self.name_sizer.AddMany([(self.name_txt, 0, wx.LEFT | wx.TOP, 10), 
    120154                            (self.name_tcl, -1, 
    121155                             wx.EXPAND | wx.RIGHT | wx.TOP | wx.BOTTOM, 10)]) 
    122         self.name_sizer.AddMany([(self.name_hsizer, -1, 
    123                                         wx.LEFT | wx.TOP, 10)]) 
    124156 
    125157 
     
    128160        Do the layout for description related widgets 
    129161        """ 
     162        #container for new model description input 
    130163        self.desc_sizer = wx.BoxSizer(wx.HORIZONTAL) 
    131         #title name [string] 
     164 
     165        #set up description label and input box with tool tip and event handling 
    132166        desc_txt = wx.StaticText(self, -1, 'Description (optional) : ') 
    133         self.desc_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1)) 
    134         self.desc_tcl.SetValue('') 
    135         #self.name_tcl.SetFont(self.font) 
     167        self.desc_tcl = wx.TextCtrl(self, -1) 
    136168        hint_desc = "Write a short description of this model function." 
    137169        self.desc_tcl.SetToolTipString(hint_desc) 
     170 
    138171        self.desc_sizer.AddMany([(desc_txt, 0, wx.LEFT | wx.TOP, 10), 
    139172                                (self.desc_tcl, -1, 
    140173                                wx.EXPAND | wx.RIGHT | wx.TOP | wx.BOTTOM, 10)]) 
    141174 
    142     def _build_sizer(self): 
    143         """ 
    144         Build gui 
     175 
     176    def _layout_model_selection(self): 
     177        """ 
     178        Do the layout for model selection related widgets 
    145179        """ 
    146180        box_width = 195 # combobox width 
    147         vbox = wx.BoxSizer(wx.VERTICAL) 
    148         self.sizer = wx.GridBagSizer(1, 3) 
    149         self._layout_name() 
    150         self._layout_description() 
    151  
    152  
    153         sum_description = wx.StaticBox(self, -1, 'Select', 
     181 
     182        #First set up main sizer for the selection 
     183        selection_box_title = wx.StaticBox(self, -1, 'Select', 
    154184                                       size=(PNL_WIDTH - 30, 70)) 
    155         sum_box = wx.StaticBoxSizer(sum_description, wx.VERTICAL) 
    156         model1_box = wx.BoxSizer(wx.HORIZONTAL) 
    157         model2_box = wx.BoxSizer(wx.HORIZONTAL) 
    158         model_vbox = wx.BoxSizer(wx.VERTICAL) 
     185        self._selection_box = wx.StaticBoxSizer(selection_box_title, wx.VERTICAL) 
     186 
     187        #Next create the help labels for the model selection 
     188        select_help_box = wx.BoxSizer(wx.HORIZONTAL) 
     189        model_string = " Model%s (p%s):" 
     190        select_help_box.Add(wx.StaticText(self, -1, model_string % (1, 1)), 0, 0) 
     191        select_help_box.Add((box_width - 25, 10),0,0) 
     192        select_help_box.Add(wx.StaticText(self, -1, model_string % (2, 2)), 0, 0) 
     193        self._selection_box.Add(select_help_box, 0, 0) 
     194 
     195        #Next create the actual selection box with 3 combo boxes 
     196        selection_box_choose = wx.BoxSizer(wx.HORIZONTAL) 
     197 
    159198        self.model1 = wx.ComboBox(self, -1, style=wx.CB_READONLY) 
    160199        wx.EVT_COMBOBOX(self.model1, -1, self.on_model1) 
     
    162201        self.model1.SetToolTipString("model1") 
    163202 
    164         self.operator_cbox = wx.ComboBox(self, -1, size=(50, -1), 
    165                                          style=wx.CB_READONLY) 
    166         wx.EVT_COMBOBOX(self.operator_cbox, -1, self.on_select_operator) 
     203        self._operator_choice = wx.ComboBox(self, -1, size=(50, -1), style=wx.CB_READONLY) 
     204        wx.EVT_COMBOBOX(self._operator_choice, -1, self.on_select_operator) 
    167205        operation_tip = "Add: +, Multiply: * " 
    168         self.operator_cbox.SetToolTipString(operation_tip) 
     206        self._operator_choice.SetToolTipString(operation_tip) 
    169207 
    170208        self.model2 = wx.ComboBox(self, -1, style=wx.CB_READONLY) 
     
    174212        self._set_model_list() 
    175213 
    176          # Buttons on the bottom 
     214        selection_box_choose.Add(self.model1, 0, 0) 
     215        selection_box_choose.Add((15, 10)) 
     216        selection_box_choose.Add(self._operator_choice, 0, 0) 
     217        selection_box_choose.Add((15, 10)) 
     218        selection_box_choose.Add(self.model2, 0, 0) 
     219        self._selection_box.Add((20,5), 0, 0) # add some space between labels and selection 
     220        self._selection_box.Add(selection_box_choose, 0, 0) 
     221 
     222    def _build_sizer(self): 
     223        """ 
     224        Build GUI with calls to _layout_name, _layout Description 
     225        and _layout_model_selection which each build a their portion of the  
     226        GUI. 
     227        """ 
     228        mainsizer = wx.BoxSizer(wx.VERTICAL) # create main sizer for dialog 
     229 
     230        # build fromm top by calling _layout_name and _layout_description 
     231        # and adding to main sizer 
     232        self._layout_name() 
     233        mainsizer.Add(self.name_sizer,0, wx.EXPAND) 
     234        self._layout_description() 
     235        mainsizer.Add(self.desc_sizer,0, wx.EXPAND) 
     236 
     237        # Add an explanation of dialog (short help) 
     238        self.explanationctr = wx.StaticText(self, -1, self.explanation) 
     239        self.fill_explanation_helpstring(self._operator) 
     240        mainsizer.Add(self.explanationctr,0, wx.LEFT | wx.EXPAND, 15) 
     241 
     242        # Add the selection box stuff with border and labels built 
     243        # by _layout_model_selection 
     244        self._layout_model_selection() 
     245        mainsizer.Add(self._selection_box, 0, wx.LEFT, 15) 
     246 
     247        # Add a space and horizontal line before the notification 
     248        #messages and the buttons at the bottom 
     249        mainsizer.Add((10, 10)) 
    177250        self.static_line_1 = wx.StaticLine(self, -1) 
    178         self.okButton = wx.Button(self, wx.ID_OK, 'Apply', size=(box_width / 2, 25)) 
    179         self.okButton.Bind(wx.EVT_BUTTON, self.check_name) 
    180         self.closeButton = wx.Button(self, wx.ID_CANCEL, 'Close', 
    181                                      size=(box_width / 2, 25)) 
    182         # Intro 
    183         self.explanation = "  custom model = %s %s " % (self.factor, '*') 
    184         self.explanation += "(model1 %s model2)\n" % self.operator 
    185         #explanation  += "  Note: This will overwrite the previous sum model.\n" 
    186         model_string = " Model%s (p%s):" 
    187         # msg 
     251        mainsizer.Add(self.static_line_1, 0, wx.EXPAND, 10) 
     252 
     253        # Add action status notification line (null at startup) 
    188254        self._msg_box = wx.StaticText(self, -1, self._notes) 
    189255        self.msg_sizer = wx.BoxSizer(wx.HORIZONTAL) 
    190256        self.msg_sizer.Add(self._msg_box, 0, wx.LEFT, 0) 
    191         vbox.Add(self.name_hsizer) 
    192         vbox.Add(self.desc_sizer) 
    193         vbox.Add(self.sizer) 
    194         ix = 0 
    195         iy = 1 
    196         self.explanationctr = wx.StaticText(self, -1, self.explanation) 
    197         self.sizer.Add(self.explanationctr , (iy, ix), 
    198                  (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 
    199         model1_box.Add(wx.StaticText(self, -1, model_string % (1, 1)), -1, 0) 
    200         model1_box.Add((box_width - 15, 10)) 
    201         model1_box.Add(wx.StaticText(self, -1, model_string % (2, 2)), -1, 0) 
    202         model2_box.Add(self.model1, -1, 0) 
    203         model2_box.Add((15, 10)) 
    204         model2_box.Add(self.operator_cbox, 0, 0) 
    205         model2_box.Add((15, 10)) 
    206         model2_box.Add(self.model2, -1, 0) 
    207         model_vbox.Add(model1_box, -1, 0) 
    208         model_vbox.Add(model2_box, -1, 0) 
    209         sum_box.Add(model_vbox, -1, 10) 
    210         iy += 1 
    211         ix = 0 
    212         self.sizer.Add(sum_box, (iy, ix), 
    213                   (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 
    214         vbox.Add((10, 10)) 
    215         vbox.Add(self.static_line_1, 0, wx.EXPAND, 10) 
    216         vbox.Add(self.msg_sizer, 0, 
     257        mainsizer.Add(self.msg_sizer, 0, 
    217258                 wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE | wx.BOTTOM, 10) 
     259 
     260        # Finally add the buttons (apply and close) on the bottom 
     261        # TODO: need help added here 
     262        self.okButton = wx.Button(self, wx.ID_OK, 'Apply') 
     263        self.okButton.Bind(wx.EVT_BUTTON, self.check_name) 
     264        self.closeButton = wx.Button(self, wx.ID_CANCEL, 'Close') 
    218265        sizer_button = wx.BoxSizer(wx.HORIZONTAL) 
    219         sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0) 
    220         sizer_button.Add(self.okButton, 0, 
    221                          wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 0) 
    222         sizer_button.Add(self.closeButton, 0, 
    223                           wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 
    224         vbox.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10) 
    225  
    226         self.SetSizer(vbox) 
     266        sizer_button.AddMany([((20, 20), 1, 0), 
     267                              (self.okButton, 0, 0), 
     268                              (self.closeButton, 0, wx.LEFT | wx.RIGHT, 10)])         
     269        mainsizer.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10) 
     270 
     271        self.SetSizer(mainsizer) 
    227272        self.Centre() 
    228273 
     
    249294        title = self.name_tcl.GetValue().lstrip().rstrip() 
    250295        if title == '': 
    251             text = self.operator 
     296            text = self._operator 
    252297            if text.count('+') > 0: 
    253298                mname = 'Sum' 
     
    283328        On Apply 
    284329        """ 
     330        self.name_tcl.SetBackgroundColour('white') 
    285331        try: 
    286332            label = self.getText() 
     
    379425        if event != None: 
    380426            event.Skip() 
    381         name = '' 
    382427        item = event.GetEventObject() 
    383428        text = item.GetValue() 
    384         if text.count('*') > 0: 
     429        self.fill_explanation_helpstring(text) 
     430 
     431    def fill_explanation_helpstring(self, type): 
     432        """ 
     433        Choose the equation to use depending on whether we now have 
     434        a sum or multiply model then create the appropriate string 
     435        """ 
     436 
     437        self._type = type 
     438        name = '' 
     439 
     440        if self._type == '*': 
    385441            name = 'Multi' 
    386442            factor = 'BackGround' 
     
    392448 
    393449        self.factor = factor 
    394         self.operator = text 
     450        self._operator = self._type 
    395451        self.explanation = "  Custom Model = %s %s (model1 %s model2)\n" % \ 
    396                     (self.factor, f_oper, self.operator) 
     452                    (self.factor, f_oper, self._operator) 
    397453        self.explanationctr.SetLabel(self.explanation) 
    398454        self.name = name + M_NAME 
    399         self.sizer.Layout() 
     455 
    400456 
    401457    def fill_oprator_combox(self): 
     
    405461        operator_list = [' +', ' *'] 
    406462        for oper in operator_list: 
    407             pos = self.operator_cbox.Append(str(oper)) 
    408             self.operator_cbox.SetClientData(pos, str(oper.strip())) 
    409         self.operator_cbox.SetSelection(0) 
     463            pos = self._operator_choice.Append(str(oper)) 
     464            self._operator_choice.SetClientData(pos, str(oper.strip())) 
     465        self._operator_choice.SetSelection(0) 
    410466 
    411467    def getText(self): 
     
    422478        description = self.desc_tcl.GetValue().lstrip().rstrip() 
    423479        if description == '': 
    424             description = name1 + self.operator + name2 
     480            description = name1 + self._operator + name2 
    425481        name = self.name_tcl.GetValue().lstrip().rstrip() 
    426         text = self.operator_cbox.GetValue() 
     482        text = self._operator_choice.GetValue() 
    427483        if text.count('+') > 0: 
    428484            factor = 'scale_factor' 
     
    473529                    out_f.write(line % description + "\n") 
    474530                #elif line.count("run") and line.count("%s"): 
    475                 #    out_f.write(line % self.operator + "\n") 
     531                #    out_f.write(line % self._operator + "\n") 
    476532                #elif line.count("evalDistribution") and line.count("%s"): 
    477                 #    out_f.write(line % self.operator + "\n") 
     533                #    out_f.write(line % self._operator + "\n") 
    478534                elif line.count("return") and line.count("%s") == 2: 
    479535                    #print "line return", line 
    480                     out_f.write(line % (f_oper, self.operator) + "\n") 
     536                    out_f.write(line % (f_oper, self._operator) + "\n") 
    481537                elif line.count("out2")and line.count("%s"): 
    482                     out_f.write(line % self.operator + "\n") 
     538                    out_f.write(line % self._operator + "\n") 
    483539                else: 
    484540                    out_f.write(line + "\n") 
     
    523579        self.is_2d = False 
    524580        self.fname = None 
     581        self.main_sizer = None 
     582        self.name_sizer = None 
     583        self.name_hsizer = None 
     584        self.desc_sizer = None 
     585        self.param_sizer = None 
     586        self.function_sizer = None 
     587        self.func_horizon_sizer = None 
     588        self.button_sizer = None 
    525589        self.param_strings = '' 
    526590        self.function_strings = '' 
     
    14021466""" 
    14031467 
    1404 #if __name__ == "__main__":  
     1468if __name__ == "__main__":  
    14051469#    app = wx.PySimpleApp() 
    1406 #    frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"])    
     1470    app = wx.App() 
     1471    frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"],plugin_dir='../fitting/plugin_models')    
     1472#    frame = wx.Dialog() 
     1473    frame.ShowModal() 
    14071474#    frame.Show(True) 
    1408 #    app.MainLoop()              
    1409  
    1410 if __name__ == "__main__": 
    1411     from sas.perspectives.fitting import models 
    1412     dir_path = models.find_plugins_dir() 
    1413     app = wx.App() 
    1414     window = EditorWindow(parent=None, base=None, path=dir_path, title="Editor") 
    1415     app.MainLoop() 
     1475    app.MainLoop()              
     1476 
     1477#if __name__ == "__main__": 
     1478#    from sas.perspectives.fitting import models 
     1479#    dir_path = models.find_plugins_dir() 
     1480#    app = wx.App() 
     1481#    window = EditorWindow(parent=None, base=None, path=dir_path, title="Editor") 
     1482#    app.MainLoop() 
Note: See TracChangeset for help on using the changeset viewer.