source: sasview/sansview/perspectives/fitting/basepage.py @ ba924ed

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 ba924ed was 3cd5806, checked in by Gervaise Alina <gervyh@…>, 14 years ago

bindind save button with guiframe toolbar

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