source: sasview/fittingview/src/sans/perspectives/fitting/basepage.py @ 3b70cc7

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

fixed 2d batch plot

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