source: sasview/theoryview/perspectives/theory/old_model_panel.py @ 6f59a98

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 6f59a98 was 0277d084, checked in by Gervaise Alina <gervyh@…>, 15 years ago

add theory view

  • Property mode set to 100644
File size: 117.9 KB
Line 
1
2
3import wx
4import wx.lib.newevent
5import numpy
6import copy
7import math
8
9import sys, os
10import wx
11import numpy
12import time
13import copy 
14import math
15import string
16from sans.models.dispersion_models import ArrayDispersion, GaussianDispersion
17
18from sans.guicomm.events import StatusEvent   
19from sans.guiframe.utils import format_number
20## event to post model to fit to fitting plugins
21(ModelEventbox, EVT_MODEL_BOX) = wx.lib.newevent.NewEvent()
22
23_BOX_WIDTH = 76
24
25#import basepage
26#from basepage import BasicPage
27#from basepage import PageInfoEvent
28import wx
29import numpy
30import time
31import copy 
32import math
33import string
34from sans.guiframe.utils import format_number,check_float#,check_value
35from sans.guicomm.events import StatusEvent
36import pagestate
37from pagestate import PageState
38(PageInfoEvent, EVT_PAGE_INFO)   = wx.lib.newevent.NewEvent()
39(PreviousStateEvent, EVT_PREVIOUS_STATE)   = wx.lib.newevent.NewEvent()
40(NextStateEvent, EVT_NEXT_STATE)   = wx.lib.newevent.NewEvent()
41_BOX_WIDTH = 76
42_QMIN_DEFAULT = 0.001
43_QMAX_DEFAULT = 0.13
44_NPTS_DEFAULT = 50
45#Control panel width
46if sys.platform.count("darwin")==0:
47    PANEL_WIDTH = 450
48    FONT_VARIANT = 0
49    ON_MAC = False
50else:
51    PANEL_WIDTH = 500
52    FONT_VARIANT = 1
53    ON_MAC = True
54class ModelPanel(wx.ScrolledWindow):
55    """
56        FitPanel class contains fields allowing to display results when
57        fitting  a model and one data
58        @note: For Fit to be performed the user should check at least one parameter
59        on fit Panel window.
60 
61    """
62    # Internal name for the AUI manager
63    window_name = "Model Page"
64    ## Title to appear on top of the window
65    window_caption = "Model page "
66    ## Flag to tell the AUI manager to put this panel in the center pane
67    CENTER_PANE = True
68    def __init__(self, parent, page_info=None, model_list_box=None):
69        """
70            Initialization of the Panel
71        """
72        wx.ScrolledWindow.__init__(self, parent, style=wx.FULL_REPAINT_ON_RESIZE)
73        #Set window's font size
74        self.SetWindowVariant(variant=FONT_VARIANT)
75        self.model  = None
76        self.data = None 
77        ## parent of the page
78        self.parent = parent
79        ## Data member to store the dispersion object created
80        self._disp_obj_dict = {}
81        ## selected parameters to apply dispersion
82        self.disp_cb_dict ={}
83        self.model_list_box = model_list_box
84        ## smearer object
85        self.smearer = None
86       
87        ##list of model parameters. each item must have same length
88        ## each item related to a given parameters
89        ##[cb state, name, value, "+/-", error of fit, min, max , units]
90        self.parameters=[]
91        ## list of parameters to fit , must be like self.parameters
92        self.param_toFit=[]
93        ## list of looking like parameters but with non fittable parameters info
94        self.fixed_param=[]
95        ## list of looking like parameters but with  fittable parameters info
96        self.fittable_param=[]
97        ##list of dispersion parameters
98        self.disp_list=[]
99        self.disp_name=""
100        ## list of orientation parameters
101        self.orientation_params=[]
102        self.orientation_params_disp=[]
103        if self.model !=None:
104            self.disp_list= self.model.getDispParamList()
105       
106        ##enable model 2D draw
107        self.enable2D= False
108        ## check that the fit range is correct to plot the model again
109        self.fitrange= True
110
111        ## Q range
112        self.qmin_x= _QMIN_DEFAULT
113        self.qmax_x= _QMAX_DEFAULT
114        self.num_points= _NPTS_DEFAULT
115       
116        ## Create memento to save the current state
117        self.state= PageState(parent= self.parent,model=self.model, data=self.data)
118        ## flag to determine if state has change
119        self.state_change= False
120        ## save customized array
121        self.values=[]
122        self.weights=[]
123        ## retrieve saved state
124        self.number_saved_state= 0
125        ## dictionary of saved state
126        self.saved_states={} 
127       
128        ## Create context menu for page
129        self.popUpMenu = wx.Menu()
130        #id = wx.NewId()
131        #self._undo = wx.MenuItem(self.popUpMenu,id, "Undo","cancel the previous action")
132        #self.popUpMenu.AppendItem(self._undo)
133        #self._undo.Enable(False)
134        #wx.EVT_MENU(self, id, self.onUndo)
135       
136        #id = wx.NewId()
137        #self._redo = wx.MenuItem(self.popUpMenu,id,"Redo"," Restore the previous action")
138        #self.popUpMenu.AppendItem(self._redo)
139        #self._redo.Enable(False)
140        #wx.EVT_MENU(self, id, self.onRedo)       
141        #self.popUpMenu.AppendSeparator()
142        #if sys.platform.count("win32")>0:       
143        id = wx.NewId()
144        self._keep = wx.MenuItem(self.popUpMenu,id,"BookMark"," Keep the panel status to recall it later")
145        self.popUpMenu.AppendItem(self._keep)
146        self._keep.Enable(True)
147        #wx.EVT_MENU(self, id, self.onSave)
148        self.popUpMenu.AppendSeparator()
149   
150        ## Default locations
151        self._default_save_location = os.getcwd()     
152     
153       
154     
155        ## create the basic structure of the panel with empty sizer
156        self.define_page_structure()
157        self._fill_model_sizer(self.sizer1) 
158        ## drawing Initial dispersion parameters sizer
159        self.set_dispers_sizer()
160        self._fill_save_sizer()
161        self.engine_type = None 
162        self._fill_range_sizer()
163       
164       
165          ## save initial state on context menu
166        #self.onSave(event=None)
167        self.Bind(wx.EVT_CONTEXT_MENU, self.onContextMenu)
168        description=""
169        if self.model != None:
170            description = self.model.description
171            self.select_model(self.model)
172            self.set_model_description(description, self.sizer2)
173         ## layout
174        self.set_layout()
175       
176    def onContextMenu(self, event): 
177        """
178            Retrieve the state selected state
179        """
180        # Skipping the save state functionality for release 0.9.0
181        #return
182        pos = event.GetPosition()
183        pos = self.ScreenToClient(pos)
184        self.PopupMenu(self.popUpMenu, pos) 
185     
186    def onSave(self, event):
187        """
188            save history of the data and model
189        """
190        if self.model==None:
191            return 
192        if hasattr(self,"enable_disp"):
193            self.state.enable_disp = copy.deepcopy(self.enable_disp.GetValue())
194        if hasattr(self, "disp_box"):
195            self.state.disp_box = copy.deepcopy(self.disp_box.GetSelection())
196
197        self.state.model.name= self.model.name
198       
199        #Remember fit engine_type for fit panel
200        if self.engine_type == None: 
201            self.engine_type = "scipy"
202        if self.manager !=None:
203            self.manager._on_change_engine(engine=self.engine_type)
204       
205            self.state.engine_type = self.engine_type
206
207        new_state = self.state.clone()
208        new_state.model.name = self.state.model.name
209       
210        new_state.enable2D = copy.deepcopy(self.enable2D)
211        ##Add model state on context menu
212        self.number_saved_state += 1
213        #name= self.model.name+"[%g]"%self.number_saved_state
214        name= self.model.__class__.__name__+"[%g]"%self.number_saved_state
215        self.saved_states[name]= new_state
216       
217        ## Add item in the context menu
218       
219        year, month, day,hour,minute,second,tda,ty,tm_isdst= time.localtime()
220        my_time= str(hour)+" : "+str(minute)+" : "+str(second)+" "
221        date= str( month)+"|"+str(day)+"|"+str(year)
222        msg=  "Model saved at %s on %s"%(my_time, date)
223         ## post help message for the selected model
224        msg +=" Saved! right click on this page to retrieve this model"
225        wx.PostEvent(self.parent, StatusEvent(status = msg ))
226       
227        id = wx.NewId()
228        self.popUpMenu.Append(id,name,str(msg))
229        wx.EVT_MENU(self, id, self.onResetModel) 
230       
231    def define_page_structure(self):
232        """
233            Create empty sizer for a panel
234        """
235        self.vbox  = wx.BoxSizer(wx.VERTICAL)
236        self.sizer0 = wx.BoxSizer(wx.VERTICAL)
237        self.sizer1 = wx.BoxSizer(wx.VERTICAL)
238        self.sizer2 = wx.BoxSizer(wx.VERTICAL)
239        self.sizer3 = wx.BoxSizer(wx.VERTICAL)
240        self.sizer4 = wx.BoxSizer(wx.VERTICAL)
241        self.sizer5 = wx.BoxSizer(wx.VERTICAL)
242        self.sizer6 = wx.BoxSizer(wx.VERTICAL)
243       
244        self.sizer0.SetMinSize((PANEL_WIDTH,-1))
245        self.sizer1.SetMinSize((PANEL_WIDTH,-1))
246        self.sizer2.SetMinSize((PANEL_WIDTH,-1))
247        self.sizer3.SetMinSize((PANEL_WIDTH,-1))
248        self.sizer4.SetMinSize((PANEL_WIDTH,-1))
249        self.sizer5.SetMinSize((PANEL_WIDTH,-1))
250        #self.sizer6.SetMinSize((375,-1))
251       
252        self.vbox.Add(self.sizer0)
253        self.vbox.Add(self.sizer1)
254        self.vbox.Add(self.sizer2)
255        self.vbox.Add(self.sizer3)
256        self.vbox.Add(self.sizer4)
257        self.vbox.Add(self.sizer5)
258        #self.vbox.Add(self.sizer6)
259       
260       
261    def set_layout(self):
262        """
263             layout
264        """
265        self.vbox.Layout()
266        self.vbox.Fit(self) 
267        self.SetSizer(self.vbox)
268       
269        self.set_scroll()
270        self.Centre()
271       
272       
273    def set_scroll(self):
274        self.SetScrollbars(20,20,25,65)
275        self.Layout()   
276        self.SetAutoLayout(True)
277         
278               
279               
280    def reset_page(self, state):
281        """
282            reset the state
283        """
284        self.reset_page_helper(state)
285       
286       
287    def old_select_model(self, model):
288        """
289            Select a new model
290            @param model: model object
291        """
292        self.model = model
293        if self.model !=None:
294            self.disp_list= self.model.getDispParamList()
295        self.set_model_param_sizer(self.model)
296        ## keep the sizer view consistent with the model menu selecting
297        self._set_model_sizer_selection( self.model )
298        self.enable_disp.SetValue(False)
299        self.disable_disp.SetValue(True)
300        self.set_dispers_sizer()
301       
302        self.model_view.SetFocus()
303        if self.model !=None:
304            self._draw_model()
305        self.state.structurecombobox = self.structurebox.GetCurrentSelection()
306        self.state.formfactorcombobox = self.formfactorbox.GetCurrentSelection()
307       
308        ## post state to fit panel
309        #self._undo.Enable(True)
310        event = PageInfoEvent(page = self)
311        wx.PostEvent(self.parent, event)               
312   
313   
314    def set_model_description(self,description,sizer):
315        """
316            fill a sizer with description
317            @param description: of type string
318            @param sizer: wx.BoxSizer()
319        """
320   
321        sizer.Clear(True)
322        box_description= wx.StaticBox(self, -1, 'Model Description')
323        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
324
325        sizer_selection=wx.BoxSizer(wx.HORIZONTAL)
326        self.description_hide = wx.RadioButton(self, -1, 'Hide', style=wx.RB_GROUP)
327        self.description_show = wx.RadioButton(self, -1, 'Show')
328       
329       
330        if description=="":
331            self.description_hide.SetValue(True)
332            description=" Description unavailable. Click for details"
333           
334        self.description = wx.StaticText( self,-1,str(description) )
335       
336        self.Bind( wx.EVT_RADIOBUTTON, self._on_display_description,
337                   id=self.description_hide.GetId() )
338       
339        self.Bind( wx.EVT_RADIOBUTTON, self._on_display_description,
340                   id=self.description_show.GetId() )
341        #MAC needs SetValue
342        self.description_hide.SetValue(True)
343       
344        self.model_description = wx.Button(self,-1, label="Details", size=(80,23))
345       
346        self.model_description.Bind(wx.EVT_BUTTON,self.on_button_clicked)
347        self.model_description.SetToolTipString("Click Model Functions in HelpWindow...")
348        self.model_description.SetFocus()
349        sizer_selection.Add( self.description_show )
350        sizer_selection.Add( (20,20)) 
351        sizer_selection.Add( self.description_hide )
352        sizer_selection.Add((20,20),0, wx.LEFT|wx.RIGHT|wx.EXPAND,75)
353        sizer_selection.Add( self.model_description )
354                     
355         
356        self.sizer_description=wx.BoxSizer(wx.HORIZONTAL)
357        self.sizer_description.Add( self.description, 1, wx.EXPAND | wx.ALL, 10 )
358        boxsizer1.Add( sizer_selection) 
359        boxsizer1.Add( (20,20)) 
360        boxsizer1.Add( self.sizer_description) 
361   
362        self._on_display_description(event=None)
363        sizer.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
364        sizer.Layout()
365   
366    def on_button_clicked(self,event):
367        """
368        #On 'More details' button
369        """
370        from helpPanel import  HelpWindow
371       
372        if self.model == None:
373            name = 'FuncHelp'
374        else:
375            name = self.model.name
376        frame = HelpWindow(None, -1,  pageToOpen="doc/model_functions.html")   
377        frame.Show(True)
378        if frame.rhelp.HasAnchor(name):
379            frame.rhelp.ScrollToAnchor(name)
380        else:
381           msg= "Model does not contains an available description "
382           msg +="Please.Search in the Help window"
383           wx.PostEvent(self.parent, StatusEvent(status = msg ))
384                     
385           
386           
387    def set_range(self, qmin_x, qmax_x, npts):
388        """
389            Set the range for the plotted models
390            @param qmin: minimum Q
391            @param qmax: maximum Q
392            @param npts: number of Q bins
393        """
394        # Set the data members
395        self.qmin_x = qmin_x
396        self.qmax_x = qmax_x
397        self.num_points = npts
398       
399        # Set the controls
400        #For qmin and qmax, do not use format_number.(If do, qmin and max could be different from what is in the data.)
401       
402        self.qmin.SetValue(str(self.qmin_x))
403        self.qmax.SetValue(str(self.qmax_x))
404        self.npts.SetValue(format_number(self.num_points))
405       
406       
407    def set_model_param_sizer(self, model):
408        """
409            Build the panel from the model content
410            @param model: the model selected in combo box for fitting purpose
411        """
412        self.sizer3.Clear(True)
413        self.parameters = []
414        self.param_toFit=[]
415        self.fixed_param=[]
416        self.orientation_params=[]
417        self.orientation_params_disp=[]
418        #self.temp=[]
419        if model ==None:
420            ##no model avaiable to draw sizer
421            self.sizer3.Layout()
422            self.SetScrollbars(20,20,25,65)
423            return
424        box_description= wx.StaticBox(self, -1,str("Model Parameters"))
425        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
426        sizer = wx.GridBagSizer(5,5)
427       
428        self.model = model
429        self.set_model_description(self.model.description,self.sizer2)
430       
431        keys = self.model.getParamList()
432        ##list of dispersion parameters
433        self.disp_list=self.model.getDispParamList()
434       
435        keys.sort()
436   
437        iy = 0
438        ix = 0
439        self.text1_2 = wx.StaticText(self, -1, 'Names')
440        sizer.Add(self.text1_2,(iy, ix),(1,1),\
441                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
442        ix +=1
443        self.text2_2 = wx.StaticText(self, -1, 'Values')
444        sizer.Add(self.text2_2,(iy, ix),(1,1),\
445                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
446        ix +=1
447        self.text2_4 = wx.StaticText(self, -1, '[Units]')
448        sizer.Add(self.text2_4,(iy, ix),(1,1),\
449                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
450        self.text2_4.Hide()
451       
452        for item in keys:
453            if not item in self.disp_list and not item in self.model.orientation_params:
454                iy += 1
455                ix = 0
456                name = wx.StaticText(self, -1,item)
457                sizer.Add( name,( iy, ix),(1,1),
458                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
459
460                ix += 1
461                value= self.model.getParam(item)
462                ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
463                    style=wx.TE_PROCESS_ENTER)
464               
465                ctl1.SetValue(str (format_number(value)))
466               
467                sizer.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
468                ix +=1
469                # Units
470                if self.model.details.has_key(item):
471                    units = wx.StaticText(self, -1, self.model.details[item][0], style=wx.ALIGN_LEFT)
472                else:
473                    units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
474                sizer.Add(units, (iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
475                ##[cb state, name, value, "+/-", error of fit, min, max , units]
476                self.parameters.append([None,item, ctl1,
477                                        None,None, None, None,None])
478        iy+=1
479        sizer.Add((10,10),(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
480        iy += 1
481        ix = 0
482       
483        #Add tile for orientational angle parameters
484        for item in keys:
485            if item in self.model.orientation_params:       
486                orient_angle = wx.StaticText(self, -1, '[For 2D only]:')
487                sizer.Add(orient_angle,(iy, ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15) 
488                if not self.enable2D:
489                    orient_angle.Hide()
490                else:
491                    orient_angle.Show(True)
492                break
493                                         
494        for item  in self.model.orientation_params:
495            if not item in self.disp_list and item in keys:
496                iy += 1
497                ix = 0
498                name = wx.StaticText(self, -1,item)
499                sizer.Add( name,( iy, ix),(1,1),
500                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
501                if not self.enable2D:
502                    name.Hide()
503                else:
504                    name.Show(True)
505
506                ix += 1
507                value= self.model.getParam(item)
508                ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
509                    style=wx.TE_PROCESS_ENTER)
510               
511                ctl1.SetValue(str (format_number(value)))
512                if not self.enable2D:
513                    ctl1.Hide()
514                    ctl1.Disable()
515                else:
516                    ctl1.Show(True)
517                    ctl1.Enable()
518               
519                sizer.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
520                ix +=1
521                # Units
522                if self.model.details.has_key(item):
523                    units = wx.StaticText(self, -1, self.model.details[item][0], style=wx.ALIGN_LEFT)
524                else:
525                    units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
526                if not self.enable2D:
527                    units.Hide()
528                else:
529                    units.Show(True)
530   
531                sizer.Add(units, (iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
532                #Save 2D orient. params
533                #self.temp.append([name,ctl1,units,orient_angle])
534               
535                               
536                ##[cb state, name, value, "+/-", error of fit, min, max , units]
537                self.parameters.append([None,item, ctl1,
538                                        None,None, None, None,None])
539                self.orientation_params.append([None,item, ctl1,
540                                        None,None, None, None,None])
541                   
542        iy+=1
543       
544        #Display units text on panel
545        for item in keys:   
546            self.text2_4.Show()
547
548     
549        boxsizer1.Add(sizer)
550        self.sizer3.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
551        self.sizer3.Layout()
552        self.SetScrollbars(20,20,25,65)
553   
554    class ModelTextCtrl(wx.TextCtrl):
555        """
556            Text control for model and fit parameters.
557            Binds the appropriate events for user interactions.
558            Default callback methods can be overwritten on initialization
559           
560            @param kill_focus_callback: callback method for EVT_KILL_FOCUS event
561            @param set_focus_callback:  callback method for EVT_SET_FOCUS event
562            @param mouse_up_callback:   callback method for EVT_LEFT_UP event
563            @param text_enter_callback: callback method for EVT_TEXT_ENTER event
564        """
565        ## Set to True when the mouse is clicked while the whole string is selected
566        full_selection = False
567        ## Call back for EVT_SET_FOCUS events
568        _on_set_focus_callback = None
569       
570        def __init__(self, parent, id=-1, value=wx.EmptyString, pos=wx.DefaultPosition, 
571                     size=wx.DefaultSize, style=0, validator=wx.DefaultValidator, name=wx.TextCtrlNameStr,
572                     kill_focus_callback = None, set_focus_callback  = None,
573                     mouse_up_callback   = None, text_enter_callback = None):
574             
575            wx.TextCtrl.__init__(self, parent, id, value, pos, size, style, validator, name)
576           
577            # Bind appropriate events
578            self._on_set_focus_callback = parent.onSetFocus \
579                      if set_focus_callback is None else set_focus_callback
580            self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
581            self.Bind(wx.EVT_KILL_FOCUS, parent._onparamEnter \
582                      if kill_focus_callback is None else kill_focus_callback)               
583            self.Bind(wx.EVT_TEXT_ENTER, parent._onparamEnter \
584                      if text_enter_callback is None else text_enter_callback)
585            if not ON_MAC :
586                self.Bind(wx.EVT_LEFT_UP,    self._highlight_text \
587                          if mouse_up_callback is None else mouse_up_callback)
588           
589        def _on_set_focus(self, event):
590            """
591                Catch when the text control is set in focus to highlight the whole
592                text if necessary
593                @param event: mouse event
594            """
595           
596            event.Skip()
597            self.full_selection = True
598            return self._on_set_focus_callback(event)
599       
600 
601           
602        def _highlight_text(self, event):
603            """
604                Highlight text of a TextCtrl only of no text has be selected
605                @param event: mouse event
606            """
607            # Make sure the mouse event is available to other listeners
608            event.Skip()
609            control  = event.GetEventObject()
610            if self.full_selection:
611                self.full_selection = False
612                # Check that we have a TextCtrl
613                if issubclass(control.__class__, wx.TextCtrl):
614                    # Check whether text has been selected,
615                    # if not, select the whole string
616                    (start, end) = control.GetSelection()
617                    if start==end:
618                        control.SetSelection(-1,-1)
619                 
620       
621    def onContextMenu(self, event): 
622        """
623            Retrieve the state selected state
624        """
625        # Skipping the save state functionality for release 0.9.0
626        #return
627   
628        pos = event.GetPosition()
629        pos = self.ScreenToClient(pos)
630       
631        self.PopupMenu(self.popUpMenu, pos) 
632     
633       
634    def onUndo(self, event):
635        """
636            Cancel the previous action
637        """
638        #print "enable undo"
639        event = PreviousStateEvent(page = self)
640        wx.PostEvent(self.parent, event)
641       
642       
643    def onRedo(self, event):
644        """
645            Restore the previous action cancelled
646        """
647        #print "enable redo"
648        event = NextStateEvent(page= self)
649        wx.PostEvent(self.parent, event)
650       
651       
652    def define_page_structure(self):
653        """
654            Create empty sizer for a panel
655        """
656        self.vbox  = wx.BoxSizer(wx.VERTICAL)
657        self.sizer0 = wx.BoxSizer(wx.VERTICAL)
658        self.sizer1 = wx.BoxSizer(wx.VERTICAL)
659        self.sizer2 = wx.BoxSizer(wx.VERTICAL)
660        self.sizer3 = wx.BoxSizer(wx.VERTICAL)
661        self.sizer4 = wx.BoxSizer(wx.VERTICAL)
662        self.sizer5 = wx.BoxSizer(wx.VERTICAL)
663        self.sizer6 = wx.BoxSizer(wx.VERTICAL)
664       
665        self.sizer0.SetMinSize((PANEL_WIDTH,-1))
666        self.sizer1.SetMinSize((PANEL_WIDTH,-1))
667        self.sizer2.SetMinSize((PANEL_WIDTH,-1))
668        self.sizer3.SetMinSize((PANEL_WIDTH,-1))
669        self.sizer4.SetMinSize((PANEL_WIDTH,-1))
670        self.sizer5.SetMinSize((PANEL_WIDTH,-1))
671        #self.sizer6.SetMinSize((375,-1))
672       
673        self.vbox.Add(self.sizer0)
674        self.vbox.Add(self.sizer1)
675        self.vbox.Add(self.sizer2)
676        self.vbox.Add(self.sizer3)
677        self.vbox.Add(self.sizer4)
678        self.vbox.Add(self.sizer5)
679        #self.vbox.Add(self.sizer6)
680       
681    def set_layout(self):
682        """
683             layout
684        """
685        self.vbox.Layout()
686        self.vbox.Fit(self) 
687        self.SetSizer(self.vbox)
688       
689        self.set_scroll()
690        self.Centre()
691       
692       
693    def set_scroll(self):
694        self.SetScrollbars(20,20,25,65)
695        self.Layout()   
696        self.SetAutoLayout(True)
697         
698         
699    def set_owner(self,owner):
700        """
701            set owner of fitpage
702            @param owner: the class responsible of plotting
703        """
704        self.event_owner = owner   
705        self.state.event_owner = owner
706 
707    def set_manager(self, manager):
708        """
709             set panel manager
710             @param manager: instance of plugin fitting
711        """
712        self.manager = manager 
713        self.state.manager = manager
714       
715    def populate_box(self, dict):
716        """
717             Store list of model
718             @param dict: dictionary containing list of models
719        """
720        self.model_list_box = dict
721        self.state.model_list_box = self.model_list_box
722           
723   
724       
725    def set_dispers_sizer(self):
726        """
727            fill sizer containing dispersity info
728        """
729        self.sizer4.Clear(True)
730        name="Polydispersity and Orientational Distribution"
731        box_description= wx.StaticBox(self, -1,name)
732        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
733        #----------------------------------------------------
734        self.disable_disp = wx.RadioButton(self, -1, 'Off', (10, 10), style=wx.RB_GROUP)
735        self.enable_disp = wx.RadioButton(self, -1, 'On', (10, 30))
736       
737       
738        self.Bind(wx.EVT_RADIOBUTTON, self._set_dipers_Param, id=self.disable_disp.GetId())
739        self.Bind(wx.EVT_RADIOBUTTON, self._set_dipers_Param, id=self.enable_disp.GetId())
740        #MAC needs SetValue
741        self.disable_disp.SetValue(True)
742        sizer_dispersion = wx.BoxSizer(wx.HORIZONTAL)
743        sizer_dispersion.Add((20,20))
744        name=""#Polydispersity and \nOrientational Distribution "
745        sizer_dispersion.Add(wx.StaticText(self,-1,name))
746        sizer_dispersion.Add(self.enable_disp )
747        sizer_dispersion.Add((20,20))
748        sizer_dispersion.Add(self.disable_disp )
749        sizer_dispersion.Add((10,10))
750       
751        ## fill a sizer with the combobox to select dispersion type
752        sizer_select_dispers = wx.BoxSizer(wx.HORIZONTAL) 
753        self.model_disp = wx.StaticText(self, -1, 'Distribution Function ')
754           
755        import sans.models.dispersion_models 
756        self.polydisp= sans.models.dispersion_models.models
757        self.disp_box = wx.ComboBox(self, -1)
758
759        for key, value in self.polydisp.iteritems():
760            name = str(key)
761            self.disp_box.Append(name,value)
762        self.disp_box.SetStringSelection("gaussian") 
763        wx.EVT_COMBOBOX(self.disp_box,-1, self._on_select_Disp) 
764             
765        sizer_select_dispers.Add((10,10)) 
766        sizer_select_dispers.Add(self.model_disp) 
767        sizer_select_dispers.Add(self.disp_box,0,
768                wx.TOP|wx.BOTTOM|wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE,border=5)
769     
770        self.model_disp.Hide()
771        self.disp_box.Hide()
772       
773        boxsizer1.Add( sizer_dispersion,0,
774                wx.TOP|wx.BOTTOM|wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE,border=5)
775        #boxsizer1.Add( (10,10) )
776        boxsizer1.Add( sizer_select_dispers )
777        self.sizer4_4 = wx.GridBagSizer(5,5)
778        boxsizer1.Add( self.sizer4_4  )
779        #-----------------------------------------------------
780        self.sizer4.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
781        self.sizer4_4.Layout()
782        self.sizer4.Layout()
783        self.Layout()
784        self.SetScrollbars(20,20,25,65)
785        self.Refresh()
786        ## saving the state of enable dispersity button
787        self.state.enable_disp= self.enable_disp.GetValue()
788        self.state.disable_disp= self.disable_disp.GetValue()
789   
790   
791    def select_disp_angle(self, event): 
792        """
793            Event for when a user select a parameter to average over.
794            @param event: radiobutton event
795        """
796        self.values=[]
797        self.weights=[]
798        if event.GetEventObject()==self.noDisper_rbox:
799            if self.noDisper_rbox.GetValue():
800                #No array dispersity apply yet
801                self._reset_dispersity()
802                ## Redraw the model ???
803                self._draw_model()
804        # Go through the list of dispersion check boxes to identify which one has changed
805        for p in self.disp_cb_dict:
806            self.state.disp_cb_dict[p]=  self.disp_cb_dict[p].GetValue()
807            # Catch which one of the box was just checked or unchecked.
808            if event.GetEventObject() == self.disp_cb_dict[p]:             
809                if self.disp_cb_dict[p].GetValue() == True:
810                   
811                    ##Temp. FIX for V1.0 regarding changing checkbox to radiobutton.
812                    ##This (self._reset_dispersity) should be removed when the array dispersion is fixed.               
813                    self._reset_dispersity()
814
815                    # The user wants this parameter to be averaged.
816                    # Pop up the file selection dialog.
817                    path = self._selectDlg()
818                   
819                    # If nothing was selected, just return
820                    if path is None:
821                        self.disp_cb_dict[p].SetValue(False)
822                        return
823                    try:
824                        self._default_save_location = os.path.dirname(path)
825                    except:
826                        pass 
827                    try:
828                        self.values, self.weights = self.read_file(path)
829                    except:
830                        msg = "Could not read input file"
831                        wx.PostEvent(self.parent, StatusEvent(status=msg))
832                        return
833                   
834                    # If any of the two arrays is empty, notify the user that we won't
835                    # proceed
836                    if self.values is None or self.weights is None or \
837                         self.values ==[] or self.weights ==[]:
838                        msg ="The loaded %s distribution is corrupted or empty"%p
839                        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
840                        return
841                       
842                    # Tell the user that we are about to apply the distribution
843                    msg = "Applying loaded %s distribution: %s"%(p, path)
844                    wx.PostEvent(self.parent, StatusEvent(status=msg)) 
845                   
846                    # Create the dispersion objects
847                    from sans.models.dispersion_models import ArrayDispersion
848                    disp_model = ArrayDispersion()
849                    disp_model.set_weights(self.values, self.weights)
850                   
851                    # Store the object to make it persist outside the scope of
852                    # this method
853                    # TODO: refactor model to clean this up?
854                    self._disp_obj_dict[p] = disp_model
855                    self.state._disp_obj_dict [p]= disp_model
856                    self.state.values=[]
857                    self.state.weights=[]
858                    self.state.values = copy.deepcopy(self.values)
859                    self.state.weights = copy.deepcopy(self.weights)
860                    # Set the new model as the dispersion object for the selected parameter
861                    self.model.set_dispersion(p, disp_model)
862                    # Store a reference to the weights in the model object so that
863                    # it's not lost when we use the model within another thread.
864                    #TODO: total hack - fix this
865                    self.state.model= self.model.clone()
866
867                    self.model._persistency_dict = {}
868                    self.model._persistency_dict[p] = [self.values, self.weights]
869                    self.state.model._persistency_dict[p] = [self.values, self.weights]
870                else:
871                    self._reset_dispersity()
872             
873                ## Redraw the model
874                self._draw_model()
875       
876        ## post state to fit panel
877        event = PageInfoEvent(page = self)
878        wx.PostEvent(self.parent, event)
879       
880   
881    def onResetModel(self, event):
882        """
883            Reset model state
884        """
885        ## post help message for the selected model
886        msg = self.popUpMenu.GetHelpString(event.GetId())
887        msg +=" reloaded"
888        wx.PostEvent(self.parent, StatusEvent(status = msg ))
889       
890        name= self.popUpMenu.GetLabel(event.GetId())
891        self._on_select_model_helper()
892       
893        if name in self.saved_states.keys():
894            previous_state = self.saved_states[name]
895            ## reset state of checkbox,textcrtl  and  regular parameters value
896            self.reset_page(previous_state)     
897                 
898    def onSave(self, event):
899        """
900            save history of the data and model
901        """
902        if self.model==None:
903            return 
904        if hasattr(self,"enable_disp"):
905            self.state.enable_disp = copy.deepcopy(self.enable_disp.GetValue())
906        if hasattr(self, "disp_box"):
907            self.state.disp_box = copy.deepcopy(self.disp_box.GetSelection())
908
909        self.state.model.name= self.model.name
910       
911        #Remember fit engine_type for fit panel
912        if self.engine_type == None: 
913            self.engine_type = "scipy"
914        if self.manager !=None:
915            self.manager._on_change_engine(engine=self.engine_type)
916       
917            self.state.engine_type = self.engine_type
918
919        new_state = self.state.clone()
920        new_state.model.name = self.state.model.name
921       
922        new_state.enable2D = copy.deepcopy(self.enable2D)
923        ##Add model state on context menu
924        self.number_saved_state += 1
925        #name= self.model.name+"[%g]"%self.number_saved_state
926        name= self.model.__class__.__name__+"[%g]"%self.number_saved_state
927        self.saved_states[name]= new_state
928       
929        ## Add item in the context menu
930       
931        year, month, day,hour,minute,second,tda,ty,tm_isdst= time.localtime()
932        my_time= str(hour)+" : "+str(minute)+" : "+str(second)+" "
933        date= str( month)+"|"+str(day)+"|"+str(year)
934        msg=  "Model saved at %s on %s"%(my_time, date)
935         ## post help message for the selected model
936        msg +=" Saved! right click on this page to retrieve this model"
937        wx.PostEvent(self.parent, StatusEvent(status = msg ))
938       
939        id = wx.NewId()
940        self.popUpMenu.Append(id,name,str(msg))
941        wx.EVT_MENU(self, id, self.onResetModel)
942       
943    def onSetFocus(self, evt):
944        """
945            highlight the current textcrtl and hide the error text control shown
946            after fitting
947            :Not implemented.
948        """
949        return
950   
951    def read_file(self, path):
952        """
953            Read two columns file
954            @param path: the path to the file to read
955        """
956        try:
957            if path==None:
958                wx.PostEvent(self.parent, StatusEvent(status=\
959                            " Selected Distribution was not loaded: %s"%path))
960                return None, None
961            input_f = open(path, 'r')
962            buff = input_f.read()
963            lines = buff.split('\n')
964           
965            angles = []
966            weights=[]
967            for line in lines:
968                toks = line.split()
969                try:
970                    angle = float(toks[0])
971                    weight = float(toks[1])
972                except:
973                    # Skip non-data lines
974                    pass
975                angles.append(angle)
976                weights.append(weight)
977            return numpy.array(angles), numpy.array(weights)
978        except:
979            raise 
980   
981   
982    def createMemento(self):
983        """
984            return the current state of the page
985        """
986        return self.state.clone()
987   
988   
989    def save_current_state(self):
990        """
991            Store current state
992        """
993        ## save model option
994        if self.model!= None:
995            self.disp_list= self.model.getDispParamList()
996            self.state.disp_list= copy.deepcopy(self.disp_list)
997            self.state.model = self.model.clone()
998
999        self.state.enable2D = copy.deepcopy(self.enable2D)
1000        self.state.values= copy.deepcopy(self.values)
1001        self.state.weights = copy.deepcopy( self.weights)
1002        ## save data   
1003        self.state.data= copy.deepcopy(self.data)
1004        try:
1005            n = self.disp_box.GetCurrentSelection()
1006            dispersity= self.disp_box.GetClientData(n)
1007            name= dispersity.__name__
1008            self.disp_name = name
1009            if name == "GaussianDispersion" :
1010               if hasattr(self,"cb1"):
1011                   self.state.cb1= self.cb1.GetValue()
1012        except:
1013            pass
1014       
1015        if hasattr(self,"enable_disp"):
1016            self.state.enable_disp= self.enable_disp.GetValue()
1017            self.state.disable_disp = self.disable_disp.GetValue()
1018           
1019        self.state.smearer = copy.deepcopy(self.smearer)
1020        if hasattr(self,"enable_smearer"):
1021            self.state.enable_smearer = copy.deepcopy(self.enable_smearer.GetValue())
1022            self.state.disable_smearer = copy.deepcopy(self.disable_smearer.GetValue())
1023           
1024        if hasattr(self,"disp_box"):
1025            self.state.disp_box = self.disp_box.GetCurrentSelection()
1026
1027            if len(self.disp_cb_dict)>0:
1028                for k , v in self.disp_cb_dict.iteritems():
1029         
1030                    if v ==None :
1031                        self.state.disp_cb_dict[k]= v
1032                    else:
1033                        try:
1034                            self.state.disp_cb_dict[k]=v.GetValue()
1035                        except:
1036                            self.state.disp_cb_dict[k]= None
1037           
1038            if len(self._disp_obj_dict)>0:
1039                for k , v in self._disp_obj_dict.iteritems():
1040     
1041                    self.state._disp_obj_dict[k]= v
1042                       
1043           
1044            self.state.values = copy.deepcopy(self.values)
1045            self.state.weights = copy.deepcopy(self.weights)
1046        ## save plotting range
1047        self._save_plotting_range()
1048       
1049        self.state.orientation_params =[]
1050        self.state.orientation_params_disp =[]
1051        self.state.parameters =[]
1052        self.state.fittable_param =[]
1053        self.state.fixed_param =[]
1054
1055       
1056        ## save checkbutton state and txtcrtl values
1057        self._copy_parameters_state(self.orientation_params,
1058                                     self.state.orientation_params)
1059        self._copy_parameters_state(self.orientation_params_disp,
1060                                     self.state.orientation_params_disp)
1061       
1062        self._copy_parameters_state(self.parameters, self.state.parameters)
1063        self._copy_parameters_state(self.fittable_param, self.state.fittable_param)
1064        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
1065   
1066
1067    def save_current_state_fit(self):
1068        """
1069            Store current state for fit_page
1070        """
1071        ## save model option
1072        if self.model!= None:
1073            self.disp_list= self.model.getDispParamList()
1074            self.state.disp_list= copy.deepcopy(self.disp_list)
1075            self.state.model = self.model.clone()
1076        #if hasattr(self,self.engine_type)> 0:
1077            #self.state.engine_type = self.engine_type.clone()
1078        self.state.enable2D = copy.deepcopy(self.enable2D)
1079        self.state.values = copy.deepcopy(self.values)
1080        self.state.weights = copy.deepcopy( self.weights)
1081        ## save data   
1082        self.state.data= copy.deepcopy(self.data)
1083        try:
1084            n = self.disp_box.GetCurrentSelection()
1085            dispersity= self.disp_box.GetClientData(n)
1086            name= dispersity.__name__
1087            self.disp_name = name
1088            if name == "GaussianDispersion":
1089               if hasattr(self, "cb1"):
1090                   self.state.cb1 = self.cb1.GetValue()
1091        except:
1092            pass
1093       
1094        if hasattr(self, "enable_disp"):
1095            self.state.enable_disp= self.enable_disp.GetValue()
1096            self.state.disable_disp = self.disable_disp.GetValue()
1097           
1098        self.state.smearer = copy.deepcopy(self.smearer)
1099        if hasattr(self,"enable_smearer"):
1100            self.state.enable_smearer = copy.deepcopy(self.enable_smearer.GetValue())
1101            self.state.disable_smearer = copy.deepcopy(self.disable_smearer.GetValue())
1102           
1103        if hasattr(self,"disp_box"):
1104            self.state.disp_box = self.disp_box.GetCurrentSelection()
1105
1106            if len(self.disp_cb_dict)>0:
1107                for k , v in self.disp_cb_dict.iteritems():
1108         
1109                    if v ==None :
1110                        self.state.disp_cb_dict[k]= v
1111                    else:
1112                        try:
1113                            self.state.disp_cb_dict[k]=v.GetValue()
1114                        except:
1115                            self.state.disp_cb_dict[k]= None
1116           
1117            if len(self._disp_obj_dict)>0:
1118                for k, v in self._disp_obj_dict.iteritems():
1119                    self.state._disp_obj_dict[k]= v
1120                       
1121            self.state.values = copy.deepcopy(self.values)
1122            self.state.weights = copy.deepcopy(self.weights)
1123           
1124        ## save plotting range
1125        self._save_plotting_range()
1126        ## save checkbutton state and txtcrtl values
1127        self._copy_parameters_state(self.orientation_params,
1128                                     self.state.orientation_params)
1129        self._copy_parameters_state(self.orientation_params_disp,
1130                                     self.state.orientation_params_disp)
1131        self._copy_parameters_state(self.parameters, self.state.parameters)
1132        self._copy_parameters_state(self.fittable_param, self.state.fittable_param)
1133        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
1134   
1135    def reset_page_helper(self, state):
1136        """
1137            Use page_state and change the state of existing page
1138            @precondition: the page is already drawn or created
1139            @postcondition: the state of the underlying data change as well as the
1140            state of the graphic interface
1141        """
1142        if state ==None:
1143            #self._undo.Enable(False)
1144            return 
1145       
1146        self.model= state.model
1147        self.data = state.data
1148        if self.data !=None:
1149            from DataLoader.qsmearing import smear_selection
1150            self.smearer= smear_selection( self.data )
1151        self.enable2D= state.enable2D
1152        self.engine_type = state.engine_type
1153
1154        self.disp_cb_dict = state.disp_cb_dict
1155        self.disp_list = state.disp_list
1156
1157        ## set the state of the radio box
1158        self.shape_rbutton.SetValue(state.shape_rbutton )
1159        self.shape_indep_rbutton.SetValue(state.shape_indep_rbutton)
1160        self.struct_rbutton.SetValue(state.struct_rbutton )
1161        self.plugin_rbutton.SetValue(state.plugin_rbutton)
1162        ##draw sizer containing model parameters value for the current model
1163        self._set_model_sizer_selection( self.model )
1164        self.set_model_param_sizer(self.model)
1165
1166        ## reset value of combox box
1167        self.structurebox.SetSelection(state.structurecombobox )
1168        self.formfactorbox.SetSelection(state.formfactorcombobox)
1169       
1170        ## enable the view 2d button if this is a modelpage type
1171        if hasattr(self,"model_view"):
1172            if self.enable2D:
1173                self.model_view.Disable()
1174            else:
1175                self.model_view.Enable()
1176        ## set the select all check box to the a given state
1177        if hasattr(self, "cb1"):   
1178            self.cb1.SetValue(state.cb1)
1179     
1180        ## reset state of checkbox,textcrtl  and  regular parameters value
1181        self._reset_parameters_state(self.orientation_params_disp,
1182                                     state.orientation_params_disp)
1183        self._reset_parameters_state(self.orientation_params,
1184                                     state.orientation_params)
1185        self._reset_parameters_state(self.parameters,state.parameters)   
1186         ## display dispersion info layer       
1187        self.enable_disp.SetValue(state.enable_disp)
1188        self.disable_disp.SetValue(state.disable_disp)
1189       
1190        if hasattr(self, "disp_box"):
1191           
1192            self.disp_box.SetSelection(state.disp_box) 
1193            n= self.disp_box.GetCurrentSelection()
1194            dispersity= self.disp_box.GetClientData(n)
1195            name= dispersity.__name__     
1196
1197            self._set_dipers_Param(event=None)
1198       
1199            if name=="ArrayDispersion":
1200               
1201                for item in self.disp_cb_dict.keys():
1202                   
1203                    if hasattr(self.disp_cb_dict[item],"SetValue") :
1204                        self.disp_cb_dict[item].SetValue(state.disp_cb_dict[item])
1205                        # Create the dispersion objects
1206                        from sans.models.dispersion_models import ArrayDispersion
1207                        disp_model = ArrayDispersion()
1208                        if hasattr(state,"values")and self.disp_cb_dict[item].GetValue()==True:
1209                            if len(state.values)>0:
1210                                self.values=state.values
1211                                self.weights=state.weights
1212                                disp_model.set_weights(self.values, state.weights)
1213                            else:
1214                                self._reset_dispersity()
1215                       
1216                        self._disp_obj_dict[item] = disp_model
1217                        # Set the new model as the dispersion object for the selected parameter
1218                        self.model.set_dispersion(item, disp_model)
1219                   
1220                        self.model._persistency_dict[item] = [state.values, state.weights]
1221                   
1222            else:
1223                keys = self.model.getParamList()
1224                for item in keys:
1225                    if item in self.disp_list and not self.model.details.has_key(item):
1226                        self.model.details[item]=["",None,None]
1227                for k,v in self.state.disp_cb_dict.iteritems():
1228                    self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict) 
1229                    self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
1230
1231        ##plotting range restore   
1232        self._reset_plotting_range(state)
1233
1234        ## smearing info  restore
1235        if hasattr(self,"enable_smearer"):
1236            ## set smearing value whether or not the data contain the smearing info
1237            self.enable_smearer.SetValue(state.enable_smearer)
1238            self.disable_smearer.SetValue(state.disable_smearer)
1239            self.onSmear(event=None)           
1240       
1241        ## reset state of checkbox,textcrtl  and dispersity parameters value
1242        self._reset_parameters_state(self.fittable_param,state.fittable_param)
1243        self._reset_parameters_state(self.fixed_param,state.fixed_param)
1244       
1245        ## draw the model with previous parameters value
1246        self._onparamEnter_helper()
1247
1248        ## reset context menu items
1249        self._reset_context_menu()
1250   
1251        ## set the value of the current state to the state given as parameter
1252        self.state = state.clone() 
1253        self._draw_model()
1254
1255    def on_reset_clicked(self,event):
1256        """
1257        #On 'Reset' button  for Q range clicked
1258        """
1259        ##For 3 different cases: Data2D, Data1D, and theory
1260        if self.data.__class__.__name__ == "Data2D":
1261            data_min= 0
1262            x= max(math.fabs(self.data.xmin), math.fabs(self.data.xmax)) 
1263            y= max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
1264            self.qmin_x = data_min
1265            self.qmax_x = math.sqrt(x*x + y*y)
1266        elif self.data.__class__.__name__ == "Data1D":
1267            self.qmin_x = min(self.data.x)
1268            self.qmax_x = max(self.data.x)
1269        else:
1270            self.qmin_x = _QMIN_DEFAULT
1271            self.qmax_x = _QMAX_DEFAULT
1272            self.num_points = _NPTS_DEFAULT           
1273            self.state.npts = self.num_points
1274           
1275
1276        self.state.qmin = self.qmin_x
1277        self.state.qmax = self.qmax_x
1278       
1279        #reset the q range values
1280        self._reset_plotting_range(self.state)
1281        #Re draw plot
1282        self._draw_model()
1283
1284    def on_model_help_clicked(self,event):
1285        """
1286        #On 'More details' button
1287        """
1288        from helpPanel import  HelpWindow
1289       
1290        if self.model == None:
1291            name = 'FuncHelp'
1292        else:
1293            name = self.model.origin_name
1294
1295        frame = HelpWindow(None, -1,  pageToOpen="doc/model_functions.html")   
1296        frame.Show(True)
1297        if frame.rhelp.HasAnchor(name):
1298            frame.rhelp.ScrollToAnchor(name)
1299        else:
1300           msg= "Model does not contains an available description "
1301           msg +="Please try searching in the Help window"
1302           wx.PostEvent(self.parent, StatusEvent(status = msg ))                   
1303   
1304    def _onQrangeEnter(self, event):
1305        """
1306            Check validity of value enter in the Q range field
1307        """
1308       
1309        tcrtl= event.GetEventObject()
1310        #Clear msg if previously shown.
1311        msg= ""
1312        wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1313        # Flag to register when a parameter has changed.
1314        is_modified = False
1315        if tcrtl.GetValue().lstrip().rstrip()!="":
1316            try:
1317                value = float(tcrtl.GetValue())
1318                tcrtl.SetBackgroundColour(wx.WHITE)
1319
1320                # If qmin and qmax have been modified, update qmin and qmax
1321                if self._validate_qrange( self.qmin, self.qmax):
1322                    tempmin = float(self.qmin.GetValue())
1323                    if tempmin != self.qmin_x:
1324                        self.qmin_x = tempmin
1325                    tempmax = float(self.qmax.GetValue())
1326                    if tempmax != self.qmax_x:
1327                        self.qmax_x = tempmax
1328                else:
1329                    tcrtl.SetBackgroundColour("pink")
1330                    msg= "Model Error:wrong value entered : %s"% sys.exc_value
1331                    wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1332                    return 
1333               
1334            except:
1335                tcrtl.SetBackgroundColour("pink")
1336                msg= "Model Error:wrong value entered : %s"% sys.exc_value
1337                wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1338                return 
1339            #Check if # of points for theory model are valid(>0).
1340            if self.npts != None:
1341                if check_float(self.npts):
1342                    temp_npts = float(self.npts.GetValue())
1343                    if temp_npts !=  self.num_points:
1344                        self.num_points = temp_npts
1345                        is_modified = True
1346                else:
1347                    msg= "Cannot Plot :No npts in that Qrange!!!  "
1348                    wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1349           
1350        else:
1351           tcrtl.SetBackgroundColour("pink")
1352           msg= "Model Error:wrong value entered!!!"
1353           wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1354           
1355        #self._undo.Enable(True)
1356        self.save_current_state()
1357        event = PageInfoEvent(page = self)
1358        wx.PostEvent(self.parent, event)
1359        self.state_change= False
1360        #Draw the model for a different range
1361        self._draw_model()
1362                         
1363    def _validate_qrange(self, qmin_ctrl, qmax_ctrl):
1364        """
1365            Verify that the Q range controls have valid values
1366            and that Qmin < Qmax.
1367           
1368            @param qmin_ctrl: text control for Qmin
1369            @param qmax_ctrl: text control for Qmax
1370            @return: True is the Q range is value, False otherwise
1371        """
1372        qmin_validity = check_float(qmin_ctrl)
1373        qmax_validity = check_float(qmax_ctrl)
1374        if not (qmin_validity and qmax_validity):
1375            return False
1376        else:
1377            qmin = float(qmin_ctrl.GetValue())
1378            qmax = float(qmax_ctrl.GetValue())
1379            if qmin < qmax:
1380                #Make sure to set both colours white. 
1381                qmin_ctrl.SetBackgroundColour(wx.WHITE)
1382                qmin_ctrl.Refresh()
1383                qmax_ctrl.SetBackgroundColour(wx.WHITE)
1384                qmax_ctrl.Refresh()
1385            else:
1386                qmin_ctrl.SetBackgroundColour("pink")
1387                qmin_ctrl.Refresh()
1388                qmax_ctrl.SetBackgroundColour("pink")
1389                qmax_ctrl.Refresh()
1390                msg= "Invalid Q range: Q min must be smaller than Q max"
1391                wx.PostEvent(self.parent.parent, StatusEvent(status = msg))
1392                return False
1393        return True
1394     
1395    def _on_display_description(self, event):
1396        """
1397            Show or Hide description
1398            @param event: wx.EVT_RADIOBUTTON
1399        """
1400        self._on_display_description_helper()
1401       
1402        self.SetScrollbars(20,20,25,65)
1403        self.Refresh()
1404
1405       
1406       
1407    def _on_display_description_helper(self):
1408        """
1409            Show or Hide description
1410            @param event: wx.EVT_RADIOBUTTON
1411        """
1412       
1413        ## Show description
1414        if self.description_hide.GetValue():
1415            self.sizer_description.Clear(True)
1416           
1417        else:
1418            description="Model contains no description"
1419            if self.model!=None:
1420                description = self.model.description
1421            if description.lstrip().rstrip() =="": 
1422                description="Model contains no description"
1423            self.description = wx.StaticText( self,-1,str(description) )
1424            self.sizer_description.Add( self.description, 1, wx.EXPAND | wx.ALL, 10 )
1425           
1426        self.Layout()
1427   
1428   
1429    def _fill_range_sizer(self):
1430        """
1431            Fill the sizer containing the plotting range
1432            add  access to npts
1433        """
1434        ##The following 3 lines are for Mac. Let JHC know before modifying..
1435        title = "Plotted Q Range"
1436        box_description= wx.StaticBox(self, -1,str(title))
1437        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
1438
1439        sizer_npts= wx.GridSizer(1, 1,5, 5)   
1440        self.npts    = self.ModelTextCtrl(self, -1,size=(_BOX_WIDTH,20), style=wx.TE_PROCESS_ENTER)
1441        self.npts.SetValue(format_number(self.num_points))
1442        self.npts.SetToolTipString("Number of point to plot.")
1443       
1444        sizer_npts.Add(wx.StaticText(self, -1, 'Npts'),1, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 13)       
1445
1446        sizer_npts.Add(self.npts,1,wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10) 
1447        self._set_range_sizer( title=title, box_sizer=boxsizer1, object= sizer_npts)
1448       
1449       
1450    def _on_select_model(self, event): 
1451        """
1452             call back for model selection
1453        """   
1454        self._on_select_model_helper() 
1455     
1456        self.set_model_param_sizer(self.model)                   
1457       
1458        #Reset dispersity that was not done in _on_select_model_helper()
1459        self._reset_dispersity()
1460        #self.select_model(self.model)
1461        qmin = float(self.qmin_x)
1462        qmax = float(self.qmax_x)
1463        qstep = float(self.num_points)
1464        evt = ModelEventbox(model=self.model, qmin=qmin, qmax=qmax, qstep=qstep)
1465        wx.PostEvent(self.parent, evt) 
1466       
1467    def _fill_model_sizer(self, sizer):
1468        """
1469            fill sizer containing model info
1470        """
1471        ##The following 3 lines are for Mac. Let JHC know before modifying..
1472        title = "Model"
1473        box_description= wx.StaticBox(self, -1,str(title))
1474        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
1475       
1476        id = wx.NewId()
1477        self.model_view =wx.Button(self,id,'View 2D', size=(80,23))
1478        self.model_view.Bind(wx.EVT_BUTTON, self._onModel2D,id=id)
1479        self.model_view.SetToolTipString("View model in 2D")
1480       
1481        ## class base method  to add view 2d button   
1482        self._set_model_sizer(sizer=sizer,box_sizer=boxsizer1, title=title,object= self.model_view )   
1483   
1484 
1485           
1486    def _set_sizer_dispersion(self, dispersity):
1487        """
1488            draw sizer with gaussian, log or schulz dispersity parameters
1489        """
1490        self.fittable_param=[]
1491        self.fixed_param=[]
1492        self.orientation_params_disp=[]
1493        #self.temp=[]
1494       
1495        self.sizer4_4.Clear(True)
1496        if self.model==None:
1497            ##no model is selected
1498            return
1499        if not self.enable_disp.GetValue():
1500            ## the user didn't select dispersity display
1501            return 
1502        self._reset_dispersity()
1503        # Create the dispersion objects
1504        for item in self.model.dispersion.keys():
1505            #disp_model =  GaussianDispersion()
1506            disp_model = dispersity()
1507            self._disp_obj_dict[item] = disp_model
1508            self.model.set_dispersion(item, disp_model)
1509            self.state._disp_obj_dict[item]= disp_model
1510           
1511           
1512        ix=0
1513        iy=1
1514        disp = wx.StaticText(self, -1, 'Names')
1515        self.sizer4_4.Add(disp,( iy, ix),(1,1), 
1516                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1517        ix += 1 
1518        values = wx.StaticText(self, -1, 'Sigmas (STD)')
1519        self.sizer4_4.Add(values,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1520       
1521        ix += 1 
1522        npts = wx.StaticText(self, -1, 'Npts')
1523        self.sizer4_4.Add(npts,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1524        ix += 1 
1525        nsigmas = wx.StaticText(self, -1, 'Nsigmas')
1526        self.sizer4_4.Add(nsigmas,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1527       
1528        for item in self.model.dispersion.keys():
1529            if not item in self.model.orientation_params:
1530                self.disp_cb_dict[item]= None
1531                name1=item+".width"
1532                name2=item+".npts"
1533                name3=item+".nsigmas"
1534                iy += 1
1535                for p in self.model.dispersion[item].keys():
1536                    if p=="width":
1537                        ix = 0
1538                        name = wx.StaticText(self, -1,  name1)
1539                        self.sizer4_4.Add( name,( iy, ix),(1,1), 
1540                                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1541                        ix = 1
1542                        value= self.model.getParam(name1)
1543                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
1544                                            style=wx.TE_PROCESS_ENTER)
1545                        ctl1.SetValue(str (format_number(value)))
1546                        self.sizer4_4.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
1547                        self.fittable_param.append([None,name1,ctl1,None,
1548                                                    None, None, None,None])
1549                    elif p=="npts":
1550                            ix =2
1551                            value= self.model.getParam(name2)
1552                            Tctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
1553                                                style=wx.TE_PROCESS_ENTER)
1554                            Tctl1.SetValue(str (format_number(value)))
1555                            self.sizer4_4.Add(Tctl1, (iy,ix),(1,1),
1556                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1557                            self.fixed_param.append([None,name2, Tctl1,None,None,
1558                                                      None, None,None])
1559                    elif p=="nsigmas":
1560                            ix =3 
1561                            value= self.model.getParam(name3)
1562                            Tctl2 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
1563                                                style=wx.TE_PROCESS_ENTER)
1564                            Tctl2.SetValue(str (format_number(value)))
1565                            self.sizer4_4.Add(Tctl2, (iy,ix),(1,1),
1566                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1567                            ix +=1
1568                            self.sizer4_4.Add((20,20), (iy,ix),(1,1),
1569                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1570                            self.fixed_param.append([None,name3, Tctl2,
1571                                                     None,None, None, None,None])
1572        for item in self.model.dispersion.keys():
1573            if item in self.model.orientation_params:
1574                self.disp_cb_dict[item]= None
1575                name1=item+".width"
1576                name2=item+".npts"
1577                name3=item+".nsigmas"
1578                iy += 1
1579                for p in self.model.dispersion[item].keys():
1580                    if p=="width":
1581                        ix = 0
1582                        name = wx.StaticText(self, -1,  name1)
1583                        self.sizer4_4.Add( name,( iy, ix),(1,1), 
1584                                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1585                        if not self.enable2D:
1586                            name.Hide()
1587                        else:
1588                            name.Show(True)
1589                        ix = 1
1590                        value= self.model.getParam(name1)
1591                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
1592                                            style=wx.TE_PROCESS_ENTER)
1593                        ctl1.SetValue(str (format_number(value)))
1594                        if not self.enable2D:
1595                            ctl1.Hide()
1596                            ctl1.Disable()
1597                        else:
1598                            ctl1.Show(True)
1599                            ctl1.Enable()
1600                        self.sizer4_4.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
1601                        self.fittable_param.append([None,name1,ctl1,None,
1602                                                    None, None, None,None])
1603                        self.orientation_params_disp.append([None,name1,ctl1,None,
1604                                                    None, None, None,None])
1605                    elif p=="npts":
1606                            ix =2
1607                            value= self.model.getParam(name2)
1608                            Tctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
1609                                                style=wx.TE_PROCESS_ENTER)
1610                            Tctl1.SetValue(str (format_number(value)))
1611                            if not self.enable2D:
1612                                Tctl1.Hide()
1613                                Tctl1.Disable()
1614                            else:
1615                                Tctl1.Show(True)
1616                                Tctl1.Enable()
1617                            self.sizer4_4.Add(Tctl1, (iy,ix),(1,1),
1618                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1619                            self.fixed_param.append([None,name2, Tctl1,None,None,
1620                                                      None, None,None])
1621                            self.orientation_params_disp.append([None,name2, Tctl1,None,None,
1622                                                      None, None,None])
1623                    elif p=="nsigmas":
1624                            ix =3 
1625                            value= self.model.getParam(name3)
1626                            Tctl2 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
1627                                                style=wx.TE_PROCESS_ENTER)
1628                            Tctl2.SetValue(str (format_number(value)))
1629                            if not self.enable2D:
1630                                Tctl2.Hide()
1631                                Tctl2.Disable()
1632                            else:
1633                                Tctl2.Show(True)
1634                                Tctl2.Enable()
1635                            self.sizer4_4.Add(Tctl2, (iy,ix),(1,1),
1636                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1637                            ix +=1
1638                            #self.sizer4_4.Add((20,20), (iy,ix),(1,1),
1639                                               #wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1640                            self.fixed_param.append([None,name3, Tctl2,
1641                                                     None,None, None, None,None])
1642                            self.orientation_params_disp.append([None,name3, Tctl2,
1643                                                     None,None, None, None,None])
1644           
1645        msg = " Selected Distribution: Gaussian"       
1646        wx.PostEvent(self.parent, StatusEvent( status= msg )) 
1647        self.state.disp_cb_dict = copy.deepcopy(self.disp_cb_dict)   
1648        ix =0
1649        iy +=1 
1650        #self.sizer4_4.Add((20,20),(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)   
1651        self.sizer4_4.Layout()
1652        self.sizer4.Layout()
1653        self.SetScrollbars(20,20,25,65)
1654             
1655    def _set_model_sizer(self,sizer, box_sizer, title="", object=None):
1656        """
1657            Use lists to fill a sizer for model info
1658        """
1659        sizer.Clear(True)
1660        ##For MAC, this should defined here.
1661        if box_sizer == None:
1662            box_description= wx.StaticBox(self, -1,str(title))
1663            boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
1664        else:
1665            boxsizer1 = box_sizer
1666           
1667        #--------------------------------------------------------
1668        self.shape_rbutton = wx.RadioButton(self, -1, 'Shapes', style=wx.RB_GROUP)
1669        self.shape_indep_rbutton = wx.RadioButton(self, -1, "Shape-Independent")
1670        self.struct_rbutton = wx.RadioButton(self, -1, "Structure Factor ")
1671        self.plugin_rbutton = wx.RadioButton(self, -1, "Customized Models")
1672               
1673        self.Bind( wx.EVT_RADIOBUTTON, self._show_combox,
1674                            id= self.shape_rbutton.GetId() ) 
1675        self.Bind( wx.EVT_RADIOBUTTON, self._show_combox,
1676                            id= self.shape_indep_rbutton.GetId() ) 
1677        self.Bind( wx.EVT_RADIOBUTTON, self._show_combox,
1678                            id= self.struct_rbutton.GetId() ) 
1679        self.Bind( wx.EVT_RADIOBUTTON, self._show_combox,
1680                            id= self.plugin_rbutton.GetId() ) 
1681        #MAC needs SetValue
1682        self.shape_rbutton.SetValue(True)
1683     
1684        sizer_radiobutton = wx.GridSizer(2, 2,5, 5)
1685        sizer_radiobutton.Add(self.shape_rbutton)
1686        sizer_radiobutton.Add(self.shape_indep_rbutton)
1687        sizer_radiobutton.Add(self.plugin_rbutton)
1688        sizer_radiobutton.Add(self.struct_rbutton)
1689       
1690        sizer_selection = wx.BoxSizer(wx.HORIZONTAL)
1691       
1692        self.text1 = wx.StaticText( self,-1,"" )
1693        self.text2 = wx.StaticText( self,-1,"P(Q)*S(Q)" )
1694       
1695       
1696        self.formfactorbox = wx.ComboBox(self, -1,style=wx.CB_READONLY)
1697        if self.model!=None:
1698            self.formfactorbox.SetValue(self.model.name)
1699           
1700           
1701        self.structurebox = wx.ComboBox(self, -1,style=wx.CB_READONLY)
1702        wx.EVT_COMBOBOX(self.formfactorbox,-1, self._on_select_model)
1703        wx.EVT_COMBOBOX(self.structurebox,-1, self._on_select_model)
1704       
1705        ## fill combox box
1706        if len(self.model_list_box)>0:
1707           
1708            self._populate_box( self.formfactorbox,self.model_list_box["Shapes"])
1709       
1710        if len(self.model_list_box)>0:
1711            self._populate_box( self.structurebox,
1712                                self.model_list_box["Structure Factors"])
1713            self.structurebox.Insert("None", 0,None)
1714            self.structurebox.SetSelection(0)
1715            self.structurebox.Hide()
1716            self.text2.Hide()
1717            self.structurebox.Disable()
1718            self.text2.Disable()
1719             
1720            if self.model.__class__ in self.model_list_box["P(Q)*S(Q)"]:
1721                self.structurebox.Show()
1722                self.text2.Show()
1723                self.structurebox.Enable()
1724                self.text2.Enable()           
1725       
1726        ## check model type to show sizer
1727        if self.model !=None:
1728            self._set_model_sizer_selection( self.model )
1729       
1730        sizer_selection.Add(self.text1)
1731        sizer_selection.Add((5,5))
1732        sizer_selection.Add(self.formfactorbox)
1733        sizer_selection.Add((5,5))
1734        sizer_selection.Add(self.text2)
1735        sizer_selection.Add((5,5))
1736        sizer_selection.Add(self.structurebox)
1737        sizer_selection.Add((5,5))
1738       
1739        boxsizer1.Add( sizer_radiobutton )
1740        boxsizer1.Add( (20,20))
1741        boxsizer1.Add( sizer_selection )
1742        if object !=None:
1743            boxsizer1.Add( (-72,-72))
1744            boxsizer1.Add( object,  0, wx.ALIGN_RIGHT| wx.RIGHT, 35)
1745            boxsizer1.Add( (60,60))
1746        #--------------------------------------------------------
1747        sizer.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
1748        sizer.Layout()
1749        self.SetScrollbars(20,20,25,65)
1750    def _onModel2D(self, event):
1751        """
1752         call manager to plot model in 2D
1753        """
1754        # If the 2D display is not currently enabled, plot the model in 2D
1755        # and set the enable2D flag.
1756
1757        if self.fitrange:
1758            self.enable2D = True
1759 
1760        if self.enable2D:
1761            self._draw_model()
1762            self.model_view.Disable()
1763           
1764            n = self.disp_box.GetCurrentSelection()
1765            dispersity= self.disp_box.GetClientData(n)
1766            #TODO:Find a better way to reinitialize the parameters containers
1767            # when resetting the page and 2D view is enable
1768            #self.set_model_param_sizer(self.model): called here is using a lot
1769            #of for loops and redraw the sizer again .How to avoid it?
1770            self.set_model_param_sizer(self.model)
1771           
1772            if len(self.orientation_params)>0:
1773                for item in self.orientation_params:
1774                    if item[2]!=None:     
1775                        item[2].Enable()
1776            # same as above why do we have to redraw the sizer of dispersity to get
1777            # the appropriate value of parameters containers on reset page?
1778            # Reset containers of dispersity parameters for the appropriate dispersity
1779            #and model
1780            if  self.disp_name.lower()in ["array","arraydispersion"]:               
1781                self._set_sizer_arraydispersion() 
1782            else:
1783                self._set_sizer_dispersion(dispersity)
1784                if len(self.orientation_params_disp)>0:
1785                   
1786                    for item in self.orientation_params_disp:
1787                        if item[2]!=None:
1788                            item[2].Enable()
1789                           
1790        self.state.enable2D =  copy.deepcopy(self.enable2D)
1791        self.Layout()
1792        ## post state to fit panel
1793        #self._undo.Enable(True)
1794        event = PageInfoEvent(page = self)
1795        wx.PostEvent(self.parent, event)
1796     
1797    def _selectDlg(self):
1798        """
1799            open a dialog file to selected the customized dispersity
1800        """
1801        import os
1802        dlg = wx.FileDialog(self, "Choose a weight file",
1803                                self._default_save_location , "", "*.*", wx.OPEN)
1804        path = None
1805        if dlg.ShowModal() == wx.ID_OK:
1806            path = dlg.GetPath()
1807        dlg.Destroy()
1808        return path
1809   
1810   
1811    def _reset_context_menu(self):
1812        """
1813            reset the context menu
1814        """
1815        for name, state in self.state.saved_states.iteritems():
1816            self.number_saved_state += 1
1817            ## Add item in the context menu
1818            id = wx.NewId()
1819            self.popUpMenu.Append(id,name, 'Save model and state %g'%self.number_saved_state)
1820            wx.EVT_MENU(self, id, self.onResetModel)
1821   
1822   
1823    def _reset_plotting_range(self, state):
1824        """
1825            Reset the plotting range to a given state
1826        """
1827        self.qmin.SetValue(str(state.qmin))
1828        self.qmax.SetValue(str(state.qmax)) 
1829        if self.state.npts!=None:
1830            self.npts.SetValue(str(state.npts)) 
1831           
1832           
1833    def _save_typeOfmodel(self):
1834        """
1835            save radiobutton containing the type model that can be selected
1836        """
1837        self.state.shape_rbutton = self.shape_rbutton.GetValue()
1838        self.state.shape_indep_rbutton = self.shape_indep_rbutton.GetValue()
1839        self.state.struct_rbutton = self.struct_rbutton.GetValue()
1840        self.state.plugin_rbutton = self.plugin_rbutton.GetValue()
1841        self.state.structurebox= self.structurebox.GetCurrentSelection()
1842        self.state.formfactorbox = self.formfactorbox.GetCurrentSelection()
1843       
1844        #self._undo.Enable(True)
1845        ## post state to fit panel
1846        event = PageInfoEvent(page = self)
1847        wx.PostEvent(self.parent, event)
1848       
1849       
1850    def _save_plotting_range(self ):
1851        """
1852            save the state of plotting range
1853        """
1854        self.state.qmin = self.qmin_x
1855        self.state.qmax = self.qmax_x
1856        if self.npts!=None:
1857            self.state.npts= self.num_points
1858           
1859           
1860    def _onparamEnter_helper(self):
1861        """
1862             check if values entered by the user are changed and valid to replot
1863             model
1864             use : _check_value_enter
1865        """
1866        # Flag to register when a parameter has changed.     
1867        is_modified = False
1868        #self._undo.Enable(True)
1869        if self.model !=None:
1870            try:
1871                is_modified =self._check_value_enter( self.fittable_param ,is_modified)
1872                is_modified =self._check_value_enter( self.fixed_param ,is_modified)
1873                is_modified =self._check_value_enter( self.parameters ,is_modified) 
1874            except:
1875                pass
1876            #if is_modified:
1877
1878            # Here we should check whether the boundaries have been modified.
1879            # If qmin and qmax have been modified, update qmin and qmax and
1880            # set the is_modified flag to True
1881            if self._validate_qrange( self.qmin, self.qmax):
1882                tempmin = float(self.qmin.GetValue())
1883                if tempmin != self.qmin_x:
1884                    self.qmin_x = tempmin
1885                    is_modified = True
1886                tempmax = float(self.qmax.GetValue())
1887                if tempmax != self.qmax_x:
1888                    self.qmax_x = tempmax
1889                    is_modified = True
1890                self.fitrange = True
1891            else:
1892                self.fitrange = False
1893            if self.npts != None:
1894                if check_float(self.npts):
1895                    temp_npts = float(self.npts.GetValue())
1896                    if temp_npts !=  self.num_points:
1897                        self.num_points = temp_npts
1898                        is_modified = True
1899                else:
1900                    msg= "Cannot Plot :Must enter a number!!!  "
1901                    wx.PostEvent(self.parent, StatusEvent(status = msg ))
1902               
1903           
1904            ## if any value is modify draw model with new value
1905            if is_modified:
1906                self.state_change= True
1907                self._draw_model() 
1908                self.Refresh()
1909        return is_modified
1910   
1911    def _update_paramv_on_fit(self):
1912        """
1913             make sure that update param values just before the fitting
1914        """
1915        #flag for qmin qmax check values
1916        flag =False
1917        is_modified = False
1918        ##So make sure that update param values on_Fit.
1919        #self._undo.Enable(True)
1920        if self.model !=None:           
1921            ##Check the values
1922            self._check_value_enter( self.fittable_param ,is_modified)
1923            self._check_value_enter( self.fixed_param ,is_modified)
1924            self._check_value_enter( self.parameters ,is_modified)
1925
1926            # If qmin and qmax have been modified, update qmin and qmax and
1927             # Here we should check whether the boundaries have been modified.
1928            # If qmin and qmax have been modified, update qmin and qmax and
1929            # set the is_modified flag to True
1930            if self._validate_qrange( self.qmin, self.qmax):
1931                tempmin = float(self.qmin.GetValue())
1932                if tempmin != self.qmin_x:
1933                    self.qmin_x = tempmin
1934                tempmax = float(self.qmax.GetValue())
1935                if tempmax != self.qmax_x:
1936                    self.qmax_x = tempmax
1937                flag = True
1938            else:
1939                flag = False
1940        else:
1941            flag = False
1942            msg= "Cannot Fit :Must select a model!!!  "
1943            wx.PostEvent(self.parent, StatusEvent(status = msg ))
1944       
1945        return flag                           
1946               
1947    def _is_modified(self, is_modified):
1948        """
1949            return to self._is_modified
1950        """
1951        return is_modified
1952                       
1953    def _reset_parameters_state(self, listtorestore,statelist):
1954        """
1955            Reset the parameters at the given state
1956        """
1957        if len(statelist)==0 or  len(listtorestore)==0 :
1958            return
1959        if len(statelist)!=  len(listtorestore) :
1960            return
1961
1962        for j in range(len(listtorestore)):
1963            item_page = listtorestore[j]
1964            item_page_info = statelist[j]
1965            ##change the state of the check box for simple parameters
1966            if item_page[0]!=None:               
1967                item_page[0].SetValue(item_page_info[0])
1968               
1969            if item_page[2]!=None:
1970                item_page[2].SetValue(item_page_info[2])
1971               
1972            if item_page[3]!=None:
1973                ## show or hide text +/-
1974                if item_page_info[2]:
1975                    item_page[3].Show(True)
1976                else:
1977                    item_page[3].Hide()
1978            if item_page[4]!=None:
1979                ## show of hide the text crtl for fitting error
1980                if item_page_info[4][0]:
1981                    item_page[4].Show(True)
1982                    item_page[4].SetValue(item_page_info[4][1])
1983                else:
1984                    item_page[3].Hide()
1985            if item_page[5]!=None:
1986                ## show of hide the text crtl for fitting error
1987                if item_page_info[5][0]:
1988                    item_page[5].Show(True)
1989                    item_page[5].SetValue(item_page_info[5][1])
1990                else:
1991                    item_page[5].Hide()
1992                   
1993            if item_page[6]!=None:
1994                ## show of hide the text crtl for fitting error
1995                if item_page_info[6][0]:
1996                    item_page[6].Show(True)
1997                    item_page[6].SetValue(item_page_info[6][1])
1998                else:
1999                    item_page[6].Hide()
2000                           
2001                           
2002    def _copy_parameters_state(self, listtocopy, statelist):
2003        """
2004            copy the state of button
2005            @param listtocopy: the list of check button to copy
2006            @param statelist: list of state object to store the current state
2007        """
2008        if len(listtocopy)==0:
2009            return
2010       
2011        for item in listtocopy:
2012 
2013            checkbox_state = None
2014            if item[0]!= None:
2015                checkbox_state= item[0].GetValue()
2016            parameter_name = item[1]
2017            parameter_value = None
2018            if item[2]!=None:
2019                parameter_value = item[2].GetValue()
2020            static_text = None
2021            if item[3]!=None:
2022                static_text = item[3].IsShown()
2023            error_value = None
2024            error_state = None
2025            if item[4]!= None:
2026                error_value = item[4].GetValue()
2027                error_state = item[4].IsShown()
2028               
2029            min_value = None
2030            min_state = None
2031            if item[5]!= None:
2032                min_value = item[5].GetValue()
2033                min_state = item[5].IsShown()
2034               
2035            max_value = None
2036            max_state = None
2037            if item[6]!= None:
2038                max_value = item[6].GetValue()
2039                max_state = item[6].IsShown()
2040            unit=None
2041            if item[7]!=None:
2042                unit = item[7].GetLabel()
2043               
2044            statelist.append([checkbox_state, parameter_name, parameter_value,
2045                              static_text ,[error_state,error_value],
2046                                [min_state,min_value],[max_state , max_value],unit])
2047           
2048    def _set_model_sizer_selection(self, model):
2049        """
2050            Display the sizer according to the type of the current model
2051        """
2052        if model ==None:
2053            self.formfactorbox.SetValue("")
2054        if hasattr(model ,"s_model"):
2055           
2056            class_name= model.s_model.__class__
2057            name= model.s_model.name
2058            flag= name != "NoStructure"
2059            if flag and (class_name in self.model_list_box["Structure Factors"]):
2060                self.structurebox.Show()
2061                self.text2.Show()               
2062                self.structurebox.Enable()
2063                self.text2.Enable()
2064                items = self.structurebox.GetItems()
2065                self.sizer1.Layout()
2066                self.SetScrollbars(20,20,25,65)
2067                for i in range(len(items)):
2068                    if items[i]== str(name):
2069                        self.structurebox.SetSelection(i)
2070                        break
2071                   
2072        if hasattr(model ,"p_model"):
2073            class_name = model.p_model.__class__
2074            name = model.p_model.name
2075            self.formfactorbox.Clear()
2076           
2077            for k, list in self.model_list_box.iteritems():
2078                if k in["P(Q)*S(Q)","Shapes" ] and class_name in self.model_list_box["Shapes"]:
2079                    self.shape_rbutton.SetValue(True)
2080                    ## fill the form factor list with new model
2081                    self._populate_box(self.formfactorbox,self.model_list_box["Shapes"])
2082                    items = self.formfactorbox.GetItems()
2083                    ## set comboxbox to the selected item
2084                    for i in range(len(items)):
2085                        if items[i]== str(name):
2086                            self.formfactorbox.SetSelection(i)
2087                            break
2088                    return
2089                elif k == "Shape-Independent":
2090                    self.shape_indep_rbutton.SetValue(True)
2091                elif k == "Structure Factors":
2092                     self.struct_rbutton.SetValue(True)
2093                else:
2094                    self.plugin_rbutton.SetValue(True)
2095               
2096                if class_name in list:
2097                    ## fill the form factor list with new model
2098                    self._populate_box(self.formfactorbox, list)
2099                    items = self.formfactorbox.GetItems()
2100                    ## set comboxbox to the selected item
2101                    for i in range(len(items)):
2102                        if items[i]== str(name):
2103                            self.formfactorbox.SetSelection(i)
2104                            break
2105                    break
2106        else:
2107
2108            ## Select the model from the menu
2109            class_name = model.__class__
2110            name = model.name
2111            self.formfactorbox.Clear()
2112            items = self.formfactorbox.GetItems()
2113   
2114            for k, list in self.model_list_box.iteritems():         
2115                if k in["P(Q)*S(Q)","Shapes" ] and class_name in self.model_list_box["Shapes"]:
2116                    if class_name in self.model_list_box["P(Q)*S(Q)"]:
2117                        self.structurebox.Show()
2118                        self.text2.Show()
2119                        self.structurebox.Enable()
2120                        self.structurebox.SetSelection(0)
2121                        self.text2.Enable()
2122                    else:
2123                        self.structurebox.Hide()
2124                        self.text2.Hide()
2125                        self.structurebox.Disable()
2126                        self.structurebox.SetSelection(0)
2127                        self.text2.Disable()
2128                       
2129                    self.shape_rbutton.SetValue(True)
2130                    ## fill the form factor list with new model
2131                    self._populate_box(self.formfactorbox,self.model_list_box["Shapes"])
2132                    items = self.formfactorbox.GetItems()
2133                    ## set comboxbox to the selected item
2134                    for i in range(len(items)):
2135                        if items[i]== str(name):
2136                            self.formfactorbox.SetSelection(i)
2137                            break
2138                    return
2139                elif k == "Shape-Independent":
2140                    self.shape_indep_rbutton.SetValue(True)
2141                elif k == "Structure Factors":
2142                    self.struct_rbutton.SetValue(True)
2143                else:
2144                    self.plugin_rbutton.SetValue(True)
2145                if class_name in list:
2146                    self.structurebox.SetSelection(0)
2147                    self.structurebox.Disable()
2148                    self.text2.Disable()                   
2149                    ## fill the form factor list with new model
2150                    self._populate_box(self.formfactorbox, list)
2151                    items = self.formfactorbox.GetItems()
2152                    ## set comboxbox to the selected item
2153                    for i in range(len(items)):
2154                        if items[i]== str(name):
2155                            self.formfactorbox.SetSelection(i)
2156                            break
2157                    break
2158   
2159    def _draw_model(self):
2160        """
2161            Method to draw or refresh a plotted model.
2162            The method will use the data member from the model page
2163            to build a call to the fitting perspective manager.
2164           
2165            [Note to coder: This way future changes will be done in only one place.]
2166        """
2167        if self.model !=None:
2168            temp_smear=None
2169            if hasattr(self, "enable_smearer"):
2170                if self.enable_smearer.GetValue():
2171                    temp_smear= self.smearer
2172            self.manager.draw_model(self.model, data=self.data,
2173                                    smearer= temp_smear,
2174                                    qmin=float(self.qmin_x), qmax=float(self.qmax_x),
2175                                    qstep= float(self.num_points),
2176                                    enable2D=self.enable2D) 
2177       
2178    def _set_model_sizer(self,sizer, box_sizer, title="", object=None):
2179        """
2180            Use lists to fill a sizer for model info
2181        """
2182       
2183        sizer.Clear(True)
2184        ##For MAC, this should defined here.
2185        if box_sizer == None:
2186            box_description= wx.StaticBox(self, -1,str(title))
2187            boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
2188        else:
2189            boxsizer1 = box_sizer
2190           
2191        #--------------------------------------------------------
2192        self.shape_rbutton = wx.RadioButton(self, -1, 'Shapes', style=wx.RB_GROUP)
2193        self.shape_indep_rbutton = wx.RadioButton(self, -1, "Shape-Independent")
2194        self.struct_rbutton = wx.RadioButton(self, -1, "Structure Factor ")
2195        self.plugin_rbutton = wx.RadioButton(self, -1, "Customized Models")
2196               
2197        self.Bind( wx.EVT_RADIOBUTTON, self._show_combox,
2198                            id= self.shape_rbutton.GetId() ) 
2199        self.Bind( wx.EVT_RADIOBUTTON, self._show_combox,
2200                            id= self.shape_indep_rbutton.GetId() ) 
2201        self.Bind( wx.EVT_RADIOBUTTON, self._show_combox,
2202                            id= self.struct_rbutton.GetId() ) 
2203        self.Bind( wx.EVT_RADIOBUTTON, self._show_combox,
2204                            id= self.plugin_rbutton.GetId() ) 
2205        #MAC needs SetValue
2206        self.shape_rbutton.SetValue(True)
2207     
2208        sizer_radiobutton = wx.GridSizer(2, 2,5, 5)
2209        sizer_radiobutton.Add(self.shape_rbutton)
2210        sizer_radiobutton.Add(self.shape_indep_rbutton)
2211        sizer_radiobutton.Add(self.plugin_rbutton)
2212        sizer_radiobutton.Add(self.struct_rbutton)
2213       
2214        sizer_selection = wx.BoxSizer(wx.HORIZONTAL)
2215       
2216        self.text1 = wx.StaticText( self,-1,"" )
2217        self.text2 = wx.StaticText( self,-1,"P(Q)*S(Q)" )
2218       
2219       
2220        self.formfactorbox = wx.ComboBox(self, -1,style=wx.CB_READONLY)
2221        if self.model!=None:
2222            self.formfactorbox.SetValue(self.model.name)
2223           
2224           
2225        self.structurebox = wx.ComboBox(self, -1,style=wx.CB_READONLY)
2226        wx.EVT_COMBOBOX(self.formfactorbox,-1, self._on_select_model)
2227        wx.EVT_COMBOBOX(self.structurebox,-1, self._on_select_model)
2228       
2229        ## fill combox box
2230        if len(self.model_list_box)>0:
2231            self._populate_box( self.formfactorbox,self.model_list_box["Shapes"])
2232       
2233        if len(self.model_list_box)>0:
2234            self._populate_box( self.structurebox,
2235                                self.model_list_box["Structure Factors"])
2236            self.structurebox.Insert("None", 0,None)
2237            self.structurebox.SetSelection(0)
2238            self.structurebox.Hide()
2239            self.text2.Hide()
2240            self.structurebox.Disable()
2241            self.text2.Disable()
2242             
2243            if self.model.__class__ in self.model_list_box["P(Q)*S(Q)"]:
2244                self.structurebox.Show()
2245                self.text2.Show()
2246                self.structurebox.Enable()
2247                self.text2.Enable()           
2248       
2249        ## check model type to show sizer
2250        if self.model !=None:
2251            self._set_model_sizer_selection( self.model )
2252       
2253        sizer_selection.Add(self.text1)
2254        sizer_selection.Add((5,5))
2255        sizer_selection.Add(self.formfactorbox)
2256        sizer_selection.Add((5,5))
2257        sizer_selection.Add(self.text2)
2258        sizer_selection.Add((5,5))
2259        sizer_selection.Add(self.structurebox)
2260        sizer_selection.Add((5,5))
2261       
2262        boxsizer1.Add( sizer_radiobutton )
2263        boxsizer1.Add( (20,20))
2264        boxsizer1.Add( sizer_selection )
2265        if object !=None:
2266            boxsizer1.Add( (-72,-72))
2267            boxsizer1.Add( object,  0, wx.ALIGN_RIGHT| wx.RIGHT, 35)
2268            boxsizer1.Add( (60,60))
2269        #--------------------------------------------------------
2270        sizer.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
2271        sizer.Layout()
2272        self.SetScrollbars(20,20,25,65)
2273       
2274    def _show_combox(self, event):
2275        """
2276            Show combox box associate with type of model selected
2277        """
2278        ## Don't want to populate combo box again if the event comes from check box
2279        if self.shape_rbutton.GetValue()and\
2280             event.GetEventObject()==self.shape_rbutton:
2281            ##fill the combobox with form factor list
2282            self.structurebox.SetSelection(0)
2283            self.structurebox.Disable()
2284            self.formfactorbox.Clear()
2285            self._populate_box( self.formfactorbox,self.model_list_box["Shapes"])
2286           
2287        if self.shape_indep_rbutton.GetValue()and\
2288             event.GetEventObject()==self.shape_indep_rbutton:
2289            ##fill the combobox with shape independent  factor list
2290            self.structurebox.SetSelection(0)
2291            self.structurebox.Disable()
2292            self.formfactorbox.Clear()
2293            self._populate_box( self.formfactorbox,
2294                                self.model_list_box["Shape-Independent"])
2295           
2296        if self.struct_rbutton.GetValue() and\
2297             event.GetEventObject()==self.struct_rbutton:
2298            ##fill the combobox with structure factor list
2299            self.structurebox.SetSelection(0)
2300            self.structurebox.Disable()
2301            self.formfactorbox.Clear()
2302            self._populate_box( self.formfactorbox,
2303                                self.model_list_box["Structure Factors"])
2304           
2305        if self.plugin_rbutton.GetValue()and\
2306             event.GetEventObject()==self.plugin_rbutton:
2307           
2308            ##fill the combobox with form factor list
2309            self.structurebox.Disable()
2310            self.formfactorbox.Clear()
2311            self._populate_box( self.formfactorbox,
2312                                self.model_list_box["Customized Models"])
2313       
2314        self._on_select_model(event=None)
2315        self._save_typeOfmodel()
2316        self.sizer4_4.Layout()
2317        self.sizer4.Layout()
2318        self.Layout()
2319        self.Refresh()
2320        self.SetScrollbars(20,20,25,65)
2321           
2322    def _populate_box(self, combobox, list):
2323        """
2324            fill combox box with dict item
2325            @param list: contains item to fill the combox
2326            item must model class
2327        """
2328        for models in list:
2329            model= models()
2330            name = model.__class__.__name__
2331            if models.__name__!="NoStructure":
2332                if hasattr(model, "name"):
2333                    name = model.name
2334                combobox.Append(name,models)
2335     
2336        return 0
2337   
2338    def _onparamEnter(self,event):
2339        """
2340            when enter value on panel redraw model according to changed
2341        """
2342        tcrtl= event.GetEventObject()
2343       
2344        #Clear msg if previously shown.
2345        msg= ""
2346        wx.PostEvent(self.parent, StatusEvent(status = msg ))
2347        ## save current state
2348        self.save_current_state()
2349        if event !=None:
2350            #self._undo.Enable(True)
2351            event = PageInfoEvent(page = self)
2352            wx.PostEvent(self.parent, event)
2353             
2354        if check_float(tcrtl):
2355           
2356            self._onparamEnter_helper()
2357            #event.Skip()
2358        else:
2359            msg= "Cannot Plot :Must enter a number!!!  "
2360            wx.PostEvent(self.parent, StatusEvent(status = msg ))
2361            #event.Skip()
2362            return 
2363   
2364    def _onQrangeEnter(self, event):
2365        """
2366            Check validity of value enter in the Q range field
2367        """
2368       
2369        tcrtl= event.GetEventObject()
2370        #Clear msg if previously shown.
2371        msg= ""
2372        wx.PostEvent(self.parent, StatusEvent(status = msg ))
2373        # Flag to register when a parameter has changed.
2374        is_modified = False
2375        if tcrtl.GetValue().lstrip().rstrip()!="":
2376            try:
2377                value = float(tcrtl.GetValue())
2378                tcrtl.SetBackgroundColour(wx.WHITE)
2379
2380                # If qmin and qmax have been modified, update qmin and qmax
2381                if self._validate_qrange( self.qmin, self.qmax):
2382                    tempmin = float(self.qmin.GetValue())
2383                    if tempmin != self.qmin_x:
2384                        self.qmin_x = tempmin
2385                    tempmax = float(self.qmax.GetValue())
2386                    if tempmax != self.qmax_x:
2387                        self.qmax_x = tempmax
2388                else:
2389                    tcrtl.SetBackgroundColour("pink")
2390                    msg= "Model Error:wrong value entered : %s"% sys.exc_value
2391                    wx.PostEvent(self.parent, StatusEvent(status = msg ))
2392                    return 
2393               
2394            except:
2395                tcrtl.SetBackgroundColour("pink")
2396                msg= "Model Error:wrong value entered : %s"% sys.exc_value
2397                wx.PostEvent(self.parent, StatusEvent(status = msg ))
2398                return 
2399            #Check if # of points for theory model are valid(>0).
2400            if self.npts != None:
2401                if check_float(self.npts):
2402                    temp_npts = float(self.npts.GetValue())
2403                    if temp_npts !=  self.num_points:
2404                        self.num_points = temp_npts
2405                        is_modified = True
2406                else:
2407                    msg= "Cannot Plot :No npts in that Qrange!!!  "
2408                    wx.PostEvent(self.parent, StatusEvent(status = msg ))
2409           
2410        else:
2411           tcrtl.SetBackgroundColour("pink")
2412           msg= "Model Error:wrong value entered!!!"
2413           wx.PostEvent(self.parent, StatusEvent(status = msg ))
2414           
2415        #self._undo.Enable(True)
2416        self.save_current_state()
2417        event = PageInfoEvent(page = self)
2418        wx.PostEvent(self.parent, event)
2419        self.state_change= False
2420     
2421    def _on_select_model_helper(self): 
2422        """
2423             call back for model selection
2424        """
2425        ## reset dictionary containing reference to dispersion
2426        self._disp_obj_dict = {}
2427        self.disp_cb_dict ={}
2428       
2429        f_id = self.formfactorbox.GetCurrentSelection()
2430        #For MAC
2431        form_factor = None
2432        if f_id >= 0:
2433            form_factor = self.formfactorbox.GetClientData( f_id )
2434
2435        if not form_factor in  self.model_list_box["multiplication"]:
2436            self.structurebox.Hide()
2437            self.text2.Hide()           
2438            self.structurebox.Disable()
2439            self.structurebox.SetSelection(0)
2440            self.text2.Disable()
2441        else:
2442            self.structurebox.Show()
2443            self.text2.Show()
2444            self.structurebox.Enable()
2445            self.text2.Enable()
2446           
2447        s_id = self.structurebox.GetCurrentSelection()
2448        struct_factor = self.structurebox.GetClientData( s_id )
2449       
2450        if  struct_factor !=None:
2451            from sans.models.MultiplicationModel import MultiplicationModel
2452            self.model= MultiplicationModel(form_factor(),struct_factor())
2453           
2454        else:
2455            if form_factor != None:
2456                self.model= form_factor()
2457            else:
2458                self.model = None
2459                return self.model
2460       
2461        ## post state to fit panel
2462        self.state.parameters =[]
2463        self.state.model =self.model
2464        self.disp_list =self.model.getDispParamList()
2465        self.state.disp_list = self.disp_list
2466        self.Layout()     
2467       
2468    def _check_value_enter(self, list, modified):
2469        """
2470            @param list: model parameter and panel info
2471            each item of the list should be as follow:
2472            item=[cb state, name, value, "+/-", error of fit, min, max , units]
2473        """ 
2474        is_modified =  modified
2475        if len(list)==0:
2476            return is_modified
2477        for item in list:
2478            #skip angle parameters for 1D
2479            if self.data.__class__.__name__ !="Data2D":
2480                if item in self.orientation_params:
2481                    continue
2482            #try:
2483            name = str(item[1])
2484           
2485            if string.find(name,".npts") ==-1 and string.find(name,".nsigmas")==-1:     
2486                ## check model parameters range             
2487                param_min= None
2488                param_max= None
2489               
2490                ## check minimun value
2491                if item[5]!= None and item[5]!= "":
2492                    if item[5].GetValue().lstrip().rstrip()!="":
2493                        try:
2494                           
2495                            param_min = float(item[5].GetValue())
2496                            if not self._validate_qrange(item[5],item[2]):
2497                                if numpy.isfinite(param_min):
2498                                    item[2].SetValue(format_number(param_min))
2499                           
2500                            item[5].SetBackgroundColour(wx.WHITE)
2501                            item[2].SetBackgroundColour(wx.WHITE)
2502                                           
2503                        except:
2504                            msg = "Wrong Fit parameter range entered "
2505                            wx.PostEvent(self.parent, StatusEvent(status = msg))
2506                            raise ValueError, msg
2507                        is_modified = True
2508                ## check maximum value
2509                if item[6]!= None and item[6]!= "":
2510                    if item[6].GetValue().lstrip().rstrip()!="":
2511                        try:                         
2512                            param_max = float(item[6].GetValue())
2513                            if not self._validate_qrange(item[2],item[6]):
2514                                if numpy.isfinite(param_max):
2515                                    item[2].SetValue(format_number(param_max)) 
2516                           
2517                            item[6].SetBackgroundColour(wx.WHITE)
2518                            item[2].SetBackgroundColour(wx.WHITE)
2519                        except:
2520                            msg = "Wrong Fit parameter range entered "
2521                            wx.PostEvent(self.parent, StatusEvent(status = msg))
2522                            raise ValueError, msg
2523                        is_modified = True
2524               
2525                if param_min != None and param_max !=None:
2526                    if not self._validate_qrange(item[5], item[6]):
2527                        msg= "Wrong Fit range entered for parameter "
2528                        msg+= "name %s of model %s "%(name, self.model.name)
2529                        wx.PostEvent(self.parent, StatusEvent(status = msg))
2530               
2531                if name in self.model.details.keys():   
2532                        self.model.details[name][1:3]= param_min,param_max
2533                        is_modified = True
2534             
2535                else:
2536                        self.model.details [name] = ["",param_min,param_max] 
2537                        is_modified = True
2538            try:     
2539                value= float(item[2].GetValue())
2540     
2541                # If the value of the parameter has changed,
2542                # +update the model and set the is_modified flag
2543                if value != self.model.getParam(name) and numpy.isfinite(value):
2544                    self.model.setParam(name,value)
2545                    is_modified = True   
2546            except:
2547                msg = "Wrong Fit parameter value entered "
2548                wx.PostEvent(self.parent, StatusEvent(status = msg))
2549               
2550        return is_modified
2551       
2552    def _set_dipers_Param(self, event):
2553        """
2554            respond to self.enable_disp and self.disable_disp radio box.
2555            The dispersity object is reset inside the model into Gaussian.
2556            When the user select yes , this method display a combo box for more selection
2557            when the user selects No,the combo box disappears.
2558            Redraw the model with the default dispersity (Gaussian)
2559        """
2560       
2561        self._reset_dispersity()
2562   
2563        if self.model ==None:
2564            self.model_disp.Hide()
2565            self.disp_box.Hide()
2566            self.sizer4_4.Clear(True)
2567            return
2568
2569        if self.enable_disp.GetValue():
2570            self.model_disp.Show(True)
2571            self.disp_box.Show(True)
2572            ## layout for model containing no dispersity parameters
2573           
2574            self.disp_list= self.model.getDispParamList()
2575             
2576            if len(self.disp_list)==0 and len(self.disp_cb_dict)==0:
2577                self._layout_sizer_noDipers() 
2578            else:
2579                ## set gaussian sizer
2580                self._on_select_Disp(event=None)
2581        else:
2582            self.model_disp.Hide()
2583            self.disp_box.Hide()
2584            self.disp_box.SetSelection(0) 
2585            self.sizer4_4.Clear(True)
2586           
2587        ## post state to fit panel
2588        self.save_current_state()
2589        if event !=None:
2590            #self._undo.Enable(True)
2591            event = PageInfoEvent(page = self)
2592            wx.PostEvent(self.parent, event)
2593        #draw the model with the current dispersity
2594        self._draw_model()
2595        self.sizer4_4.Layout()
2596        self.sizer5.Layout()
2597        self.Layout()
2598        self.Refresh()     
2599         
2600    def _layout_sizer_noDipers(self):
2601        """
2602            Draw a sizer with no dispersity info
2603        """
2604        ix=0
2605        iy=1
2606        self.fittable_param=[]
2607        self.fixed_param=[]
2608        self.orientation_params_disp=[]
2609       
2610        self.model_disp.Hide()
2611        self.disp_box.Hide()
2612        self.sizer4_4.Clear(True)
2613        model_disp = wx.StaticText(self, -1, 'No PolyDispersity for this model')
2614        self.sizer4_4.Add(model_disp,( iy, ix),(1,1),  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
2615        self.sizer4_4.Layout()
2616        self.sizer4.Layout()
2617        self.SetScrollbars(20,20,25,65)
2618     
2619    def _reset_dispersity(self):
2620        """
2621             put gaussian dispersity into current model
2622        """
2623        if len(self.param_toFit)>0:
2624            for item in self.fittable_param:
2625                if item in self.param_toFit:
2626                    self.param_toFit.remove(item)
2627
2628            for item in self.orientation_params_disp:
2629                if item in self.param_toFit:
2630                    self.param_toFit.remove(item)
2631         
2632        self.fittable_param=[]
2633        self.fixed_param=[]
2634        self.orientation_params_disp=[]
2635        self.values=[]
2636        self.weights=[]
2637     
2638        from sans.models.dispersion_models import GaussianDispersion, ArrayDispersion
2639        if len(self.disp_cb_dict)==0:
2640            self.save_current_state()
2641            self.sizer4_4.Clear(True)
2642            self.Layout()
2643 
2644            return 
2645        if (len(self.disp_cb_dict)>0) :
2646            for p in self.disp_cb_dict:
2647                # The parameter was un-selected. Go back to Gaussian model (with 0 pts)                   
2648                disp_model = GaussianDispersion()
2649               
2650                self._disp_obj_dict[p] = disp_model
2651                # Set the new model as the dispersion object for the selected parameter
2652                try:
2653                   self.model.set_dispersion(p, disp_model)
2654                except:
2655
2656                    pass
2657
2658        ## save state into
2659        self.save_current_state()
2660        self.Layout() 
2661        self.Refresh()
2662                 
2663    def _on_select_Disp(self,event):
2664        """
2665             allow selecting different dispersion
2666             self.disp_list should change type later .now only gaussian
2667        """
2668        n = self.disp_box.GetCurrentSelection()
2669        name = self.disp_box.GetValue()
2670        dispersity= self.disp_box.GetClientData(n)
2671        self.disp_name = name
2672       
2673        if name.lower() == "array":
2674            self._set_sizer_arraydispersion()
2675        else:
2676            self._set_sizer_dispersion(dispersity= dispersity)
2677           
2678        self.state.disp_box= n
2679        ## Redraw the model
2680        self._draw_model() 
2681        #self._undo.Enable(True)
2682        event = PageInfoEvent(page = self)
2683        wx.PostEvent(self.parent, event)
2684       
2685        self.sizer4_4.Layout()
2686        self.sizer4.Layout()
2687        self.SetScrollbars(20,20,25,65)
2688       
2689    def _set_sizer_arraydispersion(self):
2690        """
2691            draw sizer with array dispersity  parameters
2692        """
2693       
2694        if len(self.param_toFit)>0:
2695            for item in self.fittable_param:
2696                if item in self.param_toFit:
2697                    self.param_toFit.remove(item)
2698            for item in self.orientation_params_disp:
2699                if item in self.param_toFit:
2700                    self.param_toFit.remove(item)
2701        for item in self.model.details.keys():
2702            if item in self.model.fixed:
2703                del self.model.details [item]                           
2704
2705        self.fittable_param=[]
2706        self.fixed_param=[]
2707        self.orientation_params_disp=[]
2708        self.sizer4_4.Clear(True) 
2709        self._reset_dispersity()
2710        ix=0
2711        iy=1     
2712        disp1 = wx.StaticText(self, -1, 'Array Dispersion')
2713        self.sizer4_4.Add(disp1,( iy, ix),(1,1),  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
2714       
2715        # Look for model parameters to which we can apply an ArrayDispersion model
2716        # Add a check box for each parameter.
2717        self.disp_cb_dict = {}
2718        ix+=1 
2719        self.noDisper_rbox = wx.RadioButton(self, -1,"None", (10, 10),style= wx.RB_GROUP)
2720        self.Bind(wx.EVT_RADIOBUTTON,self.select_disp_angle , id=self.noDisper_rbox.GetId())
2721        #MAC needs SetValue
2722        self.noDisper_rbox.SetValue(True)
2723        self.sizer4_4.Add(self.noDisper_rbox, (iy, ix),
2724                           (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2725       
2726        for p in self.model.dispersion.keys():
2727            if not p in self.model.orientation_params:
2728                ix+=1 
2729                self.disp_cb_dict[p] = wx.RadioButton(self, -1, p, (10, 10))
2730                self.state.disp_cb_dict[p]=  self.disp_cb_dict[p].GetValue()
2731                self.Bind(wx.EVT_RADIOBUTTON, self.select_disp_angle, id=self.disp_cb_dict[p].GetId())
2732                self.sizer4_4.Add(self.disp_cb_dict[p], (iy, ix), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2733       
2734        for p in self.model.dispersion.keys():
2735            if p in self.model.orientation_params:
2736                ix+=1 
2737                self.disp_cb_dict[p] = wx.RadioButton(self, -1, p, (10, 10))
2738                self.state.disp_cb_dict[p]=  self.disp_cb_dict[p].GetValue()
2739                if not (self.enable2D or self.data.__class__.__name__ =="Data2D"):
2740                    self.disp_cb_dict[p].Hide()
2741                else:
2742                    self.disp_cb_dict[p].Show(True)
2743                self.Bind(wx.EVT_RADIOBUTTON, self.select_disp_angle, id=self.disp_cb_dict[p].GetId())
2744                self.sizer4_4.Add(self.disp_cb_dict[p], (iy, ix), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2745
2746
2747        ix =0
2748        iy +=1 
2749        self.sizer4_4.Add((20,20),(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)       
2750        self.Layout()
2751
2752        self.state.orientation_params =[]
2753        self.state.orientation_params_disp =[]
2754        self.state.parameters =[]
2755        self.state.fittable_param =[]
2756        self.state.fixed_param =[]
2757       
2758        ## save checkbutton state and txtcrtl values
2759       
2760        self._copy_parameters_state(self.orientation_params,
2761                                     self.state.orientation_params)
2762
2763        self._copy_parameters_state(self.orientation_params_disp,
2764                                     self.state.orientation_params_disp)
2765       
2766        self._copy_parameters_state(self.parameters, self.state.parameters)
2767        self._copy_parameters_state(self.fittable_param, self.state.fittable_param)
2768        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
2769       
2770        ## post state to fit panel
2771        event = PageInfoEvent(page = self)
2772        wx.PostEvent(self.parent, event)
2773       
2774    def _set_range_sizer(self, title, box_sizer=None, object1=None,object=None):
2775        """
2776            Fill the Q range sizer
2777        """
2778        self.sizer5.Clear(True)
2779        #--------------------------------------------------------------
2780        if box_sizer == None:
2781            box_description= wx.StaticBox(self, -1,str(title))
2782            boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
2783        else:
2784            #for MAC
2785            boxsizer1 = box_sizer
2786
2787        self.qmin    = self.ModelTextCtrl(self, -1,size=(_BOX_WIDTH,20),style=wx.TE_PROCESS_ENTER,
2788                                            kill_focus_callback = self._onQrangeEnter,
2789                                            text_enter_callback = self._onQrangeEnter)
2790        self.qmin.SetValue(str(self.qmin_x))
2791        self.qmin.SetToolTipString("Minimun value of Q in linear scale.")
2792     
2793        self.qmax    = self.ModelTextCtrl(self, -1,size=(_BOX_WIDTH,20),style=wx.TE_PROCESS_ENTER,
2794                                            kill_focus_callback = self._onQrangeEnter,
2795                                            text_enter_callback = self._onQrangeEnter)
2796        self.qmax.SetValue(str(self.qmax_x))
2797        self.qmax.SetToolTipString("Maximum value of Q in linear scale.")
2798       
2799        id = wx.NewId()
2800        self.reset_qrange =wx.Button(self,id,'Reset',size=(70,23))
2801     
2802        self.reset_qrange.Bind(wx.EVT_BUTTON, self.on_reset_clicked,id=id)
2803        self.reset_qrange.SetToolTipString("Reset Q range to the default values")
2804     
2805        sizer_horizontal=wx.BoxSizer(wx.HORIZONTAL)
2806        sizer= wx.GridSizer(3, 3,2, 5)
2807       
2808        sizer.Add(wx.StaticText(self, -1, '    Q range'))     
2809        sizer.Add(wx.StaticText(self, -1, ' Min'))
2810        sizer.Add(wx.StaticText(self, -1, ' Max'))
2811        sizer.Add(self.reset_qrange)   
2812             
2813        sizer.Add(self.qmin)
2814        sizer.Add(self.qmax)
2815        sizer_horizontal.Add(sizer)
2816        if object!=None:
2817            sizer_horizontal.Add(object)
2818       
2819        if object1!=None:
2820           boxsizer1.Add(object1) 
2821           boxsizer1.Add((10,10))
2822        boxsizer1.Add(sizer_horizontal)
2823        ## save state
2824        self.save_current_state()
2825        #----------------------------------------------------------------
2826        self.sizer5.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
2827        self.sizer5.Layout()
2828
2829    def _fill_save_sizer(self):
2830        """
2831            Draw the layout for saving option
2832        """
2833        # Skipping save state functionality for release 0.9.0
2834        return
2835   
2836        self.sizer6.Clear(True)
2837        box_description= wx.StaticBox(self, -1,"Save Model")
2838        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
2839        sizer_save = wx.BoxSizer(wx.HORIZONTAL)
2840       
2841        self.btSave_title = wx.StaticText(self, -1, 'Save the current Model')
2842        self.btSave = wx.Button(self,wx.NewId(),'Save')
2843        self.btSave.Bind(wx.EVT_BUTTON, self.onSave,id= self.btSave.GetId())
2844        self.btSave.SetToolTipString("Save the current Model")
2845       
2846        sizer_save.Add(self.btSave_title) 
2847        sizer_save.Add((20,20),0, wx.LEFT|wx.RIGHT|wx.EXPAND,45) 
2848             
2849        sizer_save.Add(self.btSave)     
2850       
2851        boxsizer1.Add(sizer_save)
2852        self.sizer6.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
2853        self.sizer6.Layout()
2854        self.SetScrollbars(20,20,25,65)
2855       
2856    def _lay_out(self):
2857        """
2858            returns self.Layout
2859            Note: Mac seems to like this better when self.Layout is called after fitting.
2860        """
2861        self._sleep4sec()
2862        self.Layout()
2863        #self._sleep4sec()
2864        return 
2865   
2866    def _sleep4sec(self):
2867        """
2868            sleep for 1 sec only applied on Mac
2869            Note: This 1sec helps for Mac not to crash on self.:ayout after self._draw_model
2870        """
2871        if ON_MAC == True:
2872            time.sleep(1)
2873             
2874class HelpWindow(wx.Frame):
2875    def __init__(self, parent, id, title):
2876        wx.Frame.__init__(self, parent, id, title, size=(570, 400))
2877       
2878        from sans.models.CylinderModel import CylinderModel
2879        model = CylinderModel()
2880        #from sans.models.LineModel import LineModel
2881        #model = LineModel()
2882        from fitpanel import PageInfo
2883        myinfo = PageInfo(self,model)
2884        from models import ModelList
2885        mylist= ModelList()
2886       
2887        from sans.models.SphereModel import SphereModel
2888        from sans.models.SquareWellStructure import SquareWellStructure
2889        from sans.models.DebyeModel import DebyeModel
2890        from sans.models.LineModel import LineModel
2891        name= "shapes"
2892        list1= [SphereModel]
2893        mylist.set_list( name, list1)
2894       
2895        name= "Shape-independent"
2896        list1= [DebyeModel]
2897        mylist.set_list( name, list1)
2898       
2899        name= "Structure Factors"
2900        list1= [SquareWellStructure]
2901        mylist.set_list( name, list1)
2902       
2903        name= "Added models"
2904        list1= [LineModel]
2905        mylist.set_list( name, list1)
2906       
2907        myinfo.model_list_box = mylist.get_list()
2908       
2909        self.page = ModelPage(self, myinfo) 
2910       
2911       
2912       
2913        self.Centre()
2914        self.Show(True)
2915
2916
2917   
2918if __name__=="__main__":
2919    app = wx.App()
2920    HelpWindow(None, -1, 'HelpWindow')
2921    app.MainLoop()
2922               
Note: See TracBrowser for help on using the repository browser.