Changeset 2d50115 in sasview for src/sas/perspectives/calculator/model_editor.py
- Timestamp:
- Apr 6, 2015 4:04:56 AM (10 years ago)
- 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:
- 7023fa5
- Parents:
- 18ac46b
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/perspectives/calculator/model_editor.py
r18ac46b r2d50115 2 2 This module provides three model editor classes: the composite model editor, 3 3 the easy editor which provides a simple interface with tooltip help to enter 4 the parameters of the model and their default value and a panel to input a 5 function of y (usually the intensity). It also provides a drop down of 4 the parameters of the model and their default value and a panel to input a 5 function of y (usually the intensity). It also provides a drop down of 6 6 standard available math functions. Finally a full python editor panel for 7 7 complete customizatin is provided. 8 8 9 ..TODO::the writiong of the file and name checking (and maybe some other9 :TODO the writiong of the file and name checking (and maybe some other 10 10 funtions?) should be moved to a computational module which could be called 11 11 fropm a python script. Basically one just needs to pass the name, 12 description text and function text (or in the case of the composite editor 12 description text and function text (or in the case of the composite editor 13 13 the names of the first and second model and the operator to be used). 14 14 ''' … … 72 72 to choose two existing models (including pre-existing custom models which 73 73 may themselves be composite models) as well as an operation on those models 74 (add or multiply) the resulting model will add a scale parameter for summed 74 (add or multiply) the resulting model will add a scale parameter for summed 75 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 76 77 The user also gives a brief help for the model in a description box and 78 78 must provide a unique name which is verified as unique before the new 79 79 model is saved. 80 80 81 81 This Dialog pops up for the user when they press 'Sum|Multi(p1,p2)' under 82 82 'Edit Custom Model' under 'Fitting' menu. This is currently called as 83 83 a Modal Dialog. 84 85 ..TODO::the build in compiler currently balks at when it tries to import86 a model whose name contains spaces or symbols (such as + ... underscore 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 87 should be fine). Have fixed so the editor cannot save such a file name 88 88 but if a file is dropped in the plugin directory from outside this class … … 121 121 self.desc_sizer = None 122 122 self.desc_tcl = None 123 self._selection_box = None123 self._selection_box = None 124 124 self.model1 = None 125 125 self.model2 = None … … 147 147 148 148 #set up label and input box with tool tip and event handling 149 self.name_txt = wx.StaticText(self, -1, 'Function Name : ')150 self.name_tcl = wx.TextCtrl(self, -1, value ='MySumFunction')149 name_txt = wx.StaticText(self, -1, 'Function Name : ') 150 self.name_tcl = wx.TextCtrl(self, -1, value='MySumFunction') 151 151 self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name) 152 152 hint_name = "Unique Sum/Multiply Model Function Name." 153 153 self.name_tcl.SetToolTipString(hint_name) 154 154 155 self.name_sizer.AddMany([(self.name_txt, 0, wx.LEFT | wx.TOP, 10), 156 (self.name_tcl, -1, 157 wx.EXPAND | wx.RIGHT | wx.TOP | wx.BOTTOM, 10)]) 155 self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10), 156 (self.name_tcl, -1, 157 wx.EXPAND | wx.RIGHT | wx.TOP | wx.BOTTOM, 158 10)]) 158 159 159 160 … … 185 186 #First set up main sizer for the selection 186 187 selection_box_title = wx.StaticBox(self, -1, 'Select', 187 size=(PNL_WIDTH - 30, 70))188 self._selection_box = wx.StaticBoxSizer(selection_box_title, 188 size=(PNL_WIDTH - 30, 70)) 189 self._selection_box = wx.StaticBoxSizer(selection_box_title, 189 190 wx.VERTICAL) 190 191 … … 194 195 select_help_box.Add(wx.StaticText(self, -1, model_string % (1, 1)), 195 196 0, 0) 196 select_help_box.Add((box_width - 25, 10), 0,0)197 select_help_box.Add((box_width - 25, 10), 0, 0) 197 198 select_help_box.Add(wx.StaticText(self, -1, model_string % (2, 2)), 198 199 0, 0) … … 225 226 selection_box_choose.Add(self.model2, 0, 0) 226 227 # add some space between labels and selection 227 self._selection_box.Add((20, 5), 0, 0)228 self._selection_box.Add((20, 5), 0, 0) 228 229 self._selection_box.Add(selection_box_choose, 0, 0) 229 230 … … 231 232 """ 232 233 Build GUI with calls to _layout_name, _layout Description 233 and _layout_model_selection which each build a their portion of the 234 and _layout_model_selection which each build a their portion of the 234 235 GUI. 235 236 """ … … 239 240 # and adding to main sizer 240 241 self._layout_name() 241 mainsizer.Add(self.name_sizer, 0, wx.EXPAND)242 mainsizer.Add(self.name_sizer, 0, wx.EXPAND) 242 243 self._layout_description() 243 mainsizer.Add(self.desc_sizer, 0, wx.EXPAND)244 mainsizer.Add(self.desc_sizer, 0, wx.EXPAND) 244 245 245 246 # Add an explanation of dialog (short help) 246 247 self.explanationctr = wx.StaticText(self, -1, self.explanation) 247 248 self.fill_explanation_helpstring(self._operator) 248 mainsizer.Add(self.explanationctr, 0, wx.LEFT | wx.EXPAND, 15)249 mainsizer.Add(self.explanationctr, 0, wx.LEFT | wx.EXPAND, 15) 249 250 250 251 # Add the selection box stuff with border and labels built … … 264 265 self.msg_sizer.Add(self._msg_box, 0, wx.LEFT, 0) 265 266 mainsizer.Add(self.msg_sizer, 0, 266 wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE | wx.BOTTOM, 10)267 wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE | wx.BOTTOM, 10) 267 268 268 269 # Finally add the buttons (apply and close) on the bottom 269 # TODO: need help addedhere270 # Eventually need to add help here 270 271 self.ok_button = wx.Button(self, wx.ID_OK, 'Apply') 271 272 self.ok_button.Bind(wx.EVT_BUTTON, self.check_name) … … 274 275 sizer_button.AddMany([((20, 20), 1, 0), 275 276 (self.ok_button, 0, 0), 276 (self.close_button, 0, wx.LEFT | wx.RIGHT, 10)]) 277 (self.close_button, 0, wx.LEFT | wx.RIGHT, 10)]) 277 278 mainsizer.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10) 278 279 … … 291 292 def check_name(self, event=None): 292 293 """ 293 Check that proposed new model name is a valid Python module name 294 Check that proposed new model name is a valid Python module name 294 295 and that it does not already exist. If not show error message and 295 296 pink background in text box else call on_apply 296 297 ..TODO::this should be separated out from the GUI code. For that we298 need to pass it the name (or if we want to keep the default name 297 298 :TODO this should be separated out from the GUI code. For that we 299 need to pass it the name (or if we want to keep the default name 299 300 option also need to pass the self._operator attribute) We just need 300 the function to return an error code that the name is good or if 301 not why (not a valid name, name exists already). The rest of the 301 the function to return an error code that the name is good or if 302 not why (not a valid name, name exists already). The rest of the 302 303 error handling should be done in this module. so on_apply would then 303 304 start by checking the name and then either raise errors or do the … … 320 321 321 322 #First check if the name is a valid Python name 322 if re.match('^[A-Za-z0-9_]*$', title):323 if re.match('^[A-Za-z0-9_]*$', title): 323 324 self.good_name = True 324 else: 325 else: 325 326 self.good_name = False 326 327 msg = ("%s is not a valid Python name. Only alphanumeric \n" \ 327 328 "and underscore allowed" % self.name) 328 329 329 330 #Now check if the name already exists 330 331 if not self.overwrite_name and self.good_name: … … 361 362 event. Instead the apply button event goes to check_name which 362 363 then calls this method if the name of the new file is acceptable. 363 364 ..todo::this should be bound to the apply button. The first line364 365 :TODO this should be bound to the apply button. The first line 365 366 should call the check_name method which itself should be in another 366 module separated from the the GUI modules. 367 module separated from the the GUI modules. 367 368 """ 368 369 self.name_tcl.SetBackgroundColour('white') … … 463 464 self.fill_explanation_helpstring(text) 464 465 465 def fill_explanation_helpstring(self, type):466 def fill_explanation_helpstring(self, operator): 466 467 """ 467 468 Choose the equation to use depending on whether we now have … … 471 472 name = '' 472 473 473 if type== '*':474 if operator == '*': 474 475 name = 'Multi' 475 476 factor = 'BackGround' … … 481 482 482 483 self.factor = factor 483 self._operator = type484 self._operator = operator 484 485 self.explanation = " Custom Model = %s %s (model1 %s model2)\n" % \ 485 486 (self.factor, f_oper, self._operator) … … 524 525 try: 525 526 out_f = open(path, 'w') 526 except 527 except: 527 528 raise 528 529 lines = SUM_TEMPLATE.split('\n') … … 600 601 kwds["style"] = wx.FULL_REPAINT_ON_RESIZE 601 602 wx.ScrolledWindow.__init__(self, parent, *args, **kwds) 603 self.SetScrollbars(1,1,1,1) 602 604 self.parent = parent 603 605 self.base = base … … 813 815 """ 814 816 event.Skip() 815 label = self.math_combo.Get Label()817 label = self.math_combo.GetValue() 816 818 self.function_tcl.SetFocus() 817 819 # Put the text at the cursor position 818 820 pos = self.function_tcl.GetCurrentPos() 819 821 self.function_tcl.InsertText(pos, label) 820 # Put the cursor at appropriate pos tion822 # Put the cursor at appropriate position 821 823 length = len(label) 822 if label[-1] == ')': 824 print length 825 if label[length-1] == ')': 823 826 length -= 1 824 827 f_pos = pos + length … … 876 879 """ 877 880 Changes are saved in data object imported to edit. 878 881 879 882 checks firs for valid name, then if it already exists then checks 880 883 that a function was entered and finally that if entered it contains at 881 least a return statement. If all passes writes file then tries to 884 least a return statement. If all passes writes file then tries to 882 885 compile. If compile fails or import module fails or run method fails 883 886 tries to remove any .py and pyc files that may have been created and 884 887 sets error message. 885 886 ..todo::this code still could do with a careful going over to clean888 889 :todo this code still could do with a careful going over to clean 887 890 up and simplify. the non GUI methods such as this one should be removed 888 891 to computational code of SasView. Most of those computational methods … … 896 899 # Sort out the errors if occur 897 900 # First check for valid python name then if the name already exists 898 if not re.match('^[A-Za-z0-9_]*$', name):901 if not re.match('^[A-Za-z0-9_]*$', name): 899 902 msg = "not a valid python name. Name must include only alpha \n" 900 903 msg += "numeric or underline characters and no spaces" … … 914 917 msg.replace(" ", "\n") 915 918 msg += "\nCompiling Failed" 919 try: 920 # try to remove pyc file if exists 921 _delete_file(self.fname) 922 _delete_file(self.fname + "c") 923 except: 924 pass 916 925 else: 917 926 msg = "Error: The func(x) must 'return' a value at least.\n" … … 929 938 except: 930 939 msg = 'new model fails to import in python' 940 try: 941 # try to remove pyc file if exists 942 _delete_file(self.fname + "c") 943 except: 944 pass 931 945 if self.base != None and not msg: 932 946 try: … … 936 950 _, value, _ = sys.exc_info() 937 951 msg += "in %s:\n%s\n" % (name, value) 952 try: 953 # try to remove pyc file if exists 954 _delete_file(self.fname + "c") 955 except: 956 pass 938 957 # Prepare the messagebox 939 958 if msg: 940 959 info = 'Error' 941 960 color = 'red' 942 try:943 # try to remove pyc file if exists944 _delete_file(self.fname)945 _delete_file(self.fname + "c")946 except:947 pass948 961 else: 949 962 msg = "Successful! " … … 1099 1112 path=path, title=title) 1100 1113 self.Show(True) 1101 wx.EVT_CLOSE(self, self. OnClose)1102 1103 def OnClose(self, event):1114 wx.EVT_CLOSE(self, self.on_close) 1115 1116 def on_close(self, event): 1104 1117 """ 1105 1118 On close event … … 1514 1527 if __name__ == "__main__": 1515 1528 # app = wx.PySimpleApp() 1516 app = wx.App()1517 frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"],1529 main_app = wx.App() 1530 main_frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"], 1518 1531 plugin_dir='../fitting/plugin_models') 1519 frame.ShowModal()1520 app.MainLoop()1532 main_frame.ShowModal() 1533 main_app.MainLoop() 1521 1534 1522 1535 #if __name__ == "__main__":
Note: See TracChangeset
for help on using the changeset viewer.