source: sasview/sansview/perspectives/fitting/basepage.py @ 60c7011

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 60c7011 was cc31608, checked in by Gervaise Alina <gervyh@…>, 13 years ago

working on batch fit

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