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

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 e0e2c44f was 2296316, checked in by Jae Cho <jhjcho@…>, 14 years ago

moving features from the branch

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