source: sasview/sansview/perspectives/fitting/basepage.py @ 670d77a

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 670d77a was 6f23daf, checked in by Jae Cho <jhjcho@…>, 14 years ago

Adjusted polydispersity help button size for MAC

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