source: sasview/fittingview/src/sans/perspectives/fitting/basepage.py @ 2ada16c

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 2ada16c was ea8283d, checked in by Jae Cho <jhjcho@…>, 13 years ago

small fix for loading a state file

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