source: sasview/src/sas/perspectives/fitting/basepage.py @ 6e653582

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 6e653582 was 6e653582, checked in by Mathieu Doucet <doucetm@…>, 9 years ago

Minor tweak to avoid annoying popup.

  • Property mode set to 100644
File size: 152.1 KB
RevLine 
[0b477f6]1"""
2Base Page for fitting
3"""
[340c2b3]4import sys
5import os
[c77d859]6import wx
7import numpy
[a074145]8import time
[ef26c83]9import copy
[904168e1]10import math
[edd166b]11import string
[27b7acc]12import json
[df7a7e3]13from collections import defaultdict
[340c2b3]14from wx.lib.scrolledpanel import ScrolledPanel
[79492222]15from sas.guiframe.panel_base import PanelBase
16from sas.guiframe.utils import format_number, check_float
17from sas.guiframe.events import PanelOnFocusEvent
18from sas.guiframe.events import StatusEvent
19from sas.guiframe.events import AppendBookmarkEvent
20from sas.guiframe.dataFitting import Data2D
21from sas.guiframe.dataFitting import Data1D
22from sas.guiframe.dataFitting import check_data_validity
23from sas.guiframe.gui_style import GUIFRAME_ID
24from sas.dataloader.data_info import Detector
25from sas.dataloader.data_info import Source
26from sas.perspectives.fitting.pagestate import PageState
27from sas.guiframe.CategoryInstaller import CategoryInstaller
[df7a7e3]28
[ef26c83]29(PageInfoEvent, EVT_PAGE_INFO) = wx.lib.newevent.NewEvent()
30(PreviousStateEvent, EVT_PREVIOUS_STATE) = wx.lib.newevent.NewEvent()
31(NextStateEvent, EVT_NEXT_STATE) = wx.lib.newevent.NewEvent()
[f72333f]32
[e7b1ccf]33_BOX_WIDTH = 76
[6bbeacd4]34_QMIN_DEFAULT = 0.0005
35_QMAX_DEFAULT = 0.5
[6d8053c]36_NPTS_DEFAULT = 50
[ef26c83]37#Control panel width
38if sys.platform.count("win32") > 0:
[b421b1a]39    PANEL_WIDTH = 450
[f1aa385]40    FONT_VARIANT = 0
[35c9d31]41    ON_MAC = False
[9170547]42else:
[c99a6c5]43    PANEL_WIDTH = 500
[f1aa385]44    FONT_VARIANT = 1
[35c9d31]45    ON_MAC = True
[6bbeacd4]46
47
[015d109]48class BasicPage(ScrolledPanel, PanelBase):
[c77d859]49    """
[5062bbf]50    This class provide general structure of  fitpanel page
[c77d859]51    """
[ef26c83]52    ## Internal name for the AUI manager
[6bbeacd4]53    window_name = "Fit Page"
[b787e68c]54    ## Title to appear on top of the window
[6bbeacd4]55    window_caption = "Fit Page "
[59a7f2d]56   
[ef26c83]57    def __init__(self, parent, color='blue', **kwargs):
[5062bbf]58        """
59        """
[015d109]60        ScrolledPanel.__init__(self, parent, **kwargs)
[e030625]61        PanelBase.__init__(self, parent)
[340c2b3]62        self.SetupScrolling()
[ef26c83]63        #Set window's font size
[f1aa385]64        self.SetWindowVariant(variant=FONT_VARIANT)
[6bbeacd4]65     
66        self.SetBackgroundColour(color)
[c77d859]67        ## parent of the page
68        self.parent = parent
[77e23a2]69        ## manager is the fitting plugin
[c77d859]70        ## owner of the page (fitting plugin)
[4a7ad5f]71        self.event_owner = None
[ef26c83]72        ## current model
[ffa69b6]73        self.model = None
[be1ec9f]74        self.m_name = None
[ecf26e1]75        self.index_model = None
[be1ec9f]76        self.panel = None
[cfc0913]77        ## data
[ffa69b6]78        self.data = None
[cc31608]79        #list of available data
80        self.data_list = []
[e575db9]81        self.mask = None
[ecf26e1]82        self.uid = wx.NewId()
[5e48acb]83        self.graph_id = None
[4225aed]84        #Q range for data set
[a6d3553]85        self.qmin_data_set = numpy.inf
[4225aed]86        self.qmax_data_set = None
[67ae937]87        self.npts_data_set = 0
[0b12abb5]88        ## Q range
[f95301b]89        self.qmin = None
90        self.qmax = None
[6bbeacd4]91        self.qmax_x = _QMAX_DEFAULT
92        self.qmin_x = _QMIN_DEFAULT
93        self.npts_x = _NPTS_DEFAULT
[0b12abb5]94        ## total number of point: float
95        self.npts = None
[be1ec9f]96        self.num_points = None
[0b12abb5]97        ## default fitengine type
[bf5e985]98        self.engine_type = 'bumps'
[0b12abb5]99        ## smear default
100        self.current_smearer = None
101        ## 2D smear accuracy default
102        self.smear2d_accuracy = 'Low'
[ef26c83]103        ## slit smear:
[0b12abb5]104        self.dxl = None
105        self.dxw = None
[ef26c83]106        ## pinhole smear
[0b12abb5]107        self.dx_min = None
108        self.dx_max = None
[7d514fc]109        ##semar attrbs
[7b7ff27]110        self.enable_smearer = None
111        self.disable_smearer = None
112        self.pinhole_smearer = None
113        self.slit_smearer = None
[7d514fc]114        ##weigth attrbs
[7b7ff27]115        self.dI_noweight = None
116        self.dI_didata = None
117        self.dI_sqrdata = None
118        self.dI_idata = None
[7d514fc]119        ##other attrbs
120        self.dq_l = None
121        self.dq_r = None
122        self.tcChi = None
123        self.disp_box = None
[fcd6c6a]124        self.model_disp = None
[7d514fc]125        self.Npts_fit = None
[f71625f]126        self.Npts_total = None
[7d514fc]127        self.theory_qmin = None 
128        self.theory_qmax = None
[fcd6c6a]129        self.theory_qmin_x = None
130        self.theory_qmax_x = None
[f71625f]131        self.cb1 = None
132        self.btEditMask = None
133        self.btFit = None
[be1ec9f]134        self.sld_axes = None
135        self.multi_factor = None
[0b12abb5]136       
137        self.disp_cb_dict = {}
138   
[0b477f6]139        #self.state = PageState(parent=parent)
[c77d859]140        ## dictionary containing list of models
[6bbeacd4]141        self.model_list_box = {}
142       
[c77d859]143        ## Data member to store the dispersion object created
144        self._disp_obj_dict = {}
[cfc0913]145        ## selected parameters to apply dispersion
[ef26c83]146        self.disp_cb_dict = {}
[997131a]147        ## smearer object
[69f9084]148        self.enable2D = False
[318b5bbb]149        self._has_magnetic = False
150        self.magnetic_on = False
[cdb042d]151        self.is_mac = ON_MAC
[940aca7]152        self.formfactorbox = None
153        self.structurebox = None
[ea5fa58]154        self.categorybox = None
[c77d859]155        ##list of model parameters. each item must have same length
156        ## each item related to a given parameters
157        ##[cb state, name, value, "+/-", error of fit, min, max , units]
[4a7ad5f]158        self.parameters = []
[fb59ed9]159        # non-fittable parameter whose value is astring
160        self.str_parameters = []
[c77d859]161        ## list of parameters to fit , must be like self.parameters
[4a7ad5f]162        self.param_toFit = []
[c77d859]163        ## list of looking like parameters but with non fittable parameters info
[4a7ad5f]164        self.fixed_param = []
[c77d859]165        ## list of looking like parameters but with  fittable parameters info
[4a7ad5f]166        self.fittable_param = []
[c77d859]167        ##list of dispersion parameters
[4a7ad5f]168        self.disp_list = []
169        self.disp_name = ""
[ffa69b6]170       
[780d095]171        ## list of orientation parameters
[4a7ad5f]172        self.orientation_params = []
173        self.orientation_params_disp = []
[116e1a7]174#       Self.model should ALWAYS be None here.  It was set to none above in
175#       this long init setting.  no obvious function call in between setting
176#       and this - commenting out on 4/8/2014 by PDB.  Remove once clear
177#       it is pointless.
178#        if self.model != None:
179#            self.disp_list = self.model.getDispParamList()
[8960479]180        self.temp_multi_functional = False
[c77d859]181        ##enable model 2D draw
[4a7ad5f]182        self.enable2D = False
[c77d859]183        ## check that the fit range is correct to plot the model again
[4a7ad5f]184        self.fitrange = True
[1b69256]185        ## Create memento to save the current state
[4a7ad5f]186        self.state = PageState(parent=self.parent,
187                               model=self.model, data=self.data)
[240b9966]188        ## flag to determine if state has change
[4a7ad5f]189        self.state_change = False
[71f0373]190        ## save customized array
[4a7ad5f]191        self.values = []
192        self.weights = []
[a074145]193        ## retrieve saved state
[4a7ad5f]194        self.number_saved_state = 0
[a074145]195        ## dictionary of saved state
[ef26c83]196        self.saved_states = {}
[1b69256]197        ## Create context menu for page
198        self.popUpMenu = wx.Menu()
[6bbeacd4]199   
[6d91073]200        id = wx.NewId()
[ef26c83]201        self._keep = wx.MenuItem(self.popUpMenu, id, "Add bookmark",
[4a7ad5f]202                                 " Keep the panel status to recall it later")
[6d91073]203        self.popUpMenu.AppendItem(self._keep)
[2657df9]204        self._keep.Enable(False)
[20b228a0]205        self._set_bookmark_flag(False)
206        self._set_save_flag(False)
[9bc499b6]207        wx.EVT_MENU(self, id, self.on_bookmark)
[6d91073]208        self.popUpMenu.AppendSeparator()
209   
[60132ef]210        ## Default locations
[ef26c83]211        self._default_save_location = os.getcwd()
[a074145]212        ## save initial state on context menu
[1b69256]213        #self.onSave(event=None)
[a074145]214        self.Bind(wx.EVT_CONTEXT_MENU, self.onContextMenu)
[2296316]215       
216        # bind key event
217        self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
[c31fd9f]218       
[cfc0913]219        ## create the basic structure of the panel with empty sizer
220        self.define_page_structure()
[ef26c83]221        ## drawing Initial dispersion parameters sizer
[c77d859]222        self.set_dispers_sizer()
[20b228a0]223       
[c77d859]224        ## layout
225        self.set_layout()
[92f5521a]226   
[ecf26e1]227    def set_index_model(self, index):
228        """
229        Index related to this page
230        """
231        self.index_model = index
232       
233    def create_default_data(self):
234        """
[ef26c83]235        Given the user selection, creates a 1D or 2D data
[ecf26e1]236        Only when the page is on theory mode.
237        """
[6e4c9fe]238        if not hasattr(self, "model_view"):
239            return
240        toggle_mode_on = self.model_view.IsEnabled()
241        if toggle_mode_on:
242            if self.enable2D and not check_data_validity(self.data):
243                self._create_default_2d_data()
244            else:
[cb270ad2]245                if self.pointsbox.GetValue():
246                    self._create_log_1d_data()
247                else:
248                    self._create_default_1d_data()
249                       
[33477fd]250            if self.model != None:
251                if not self.data.is_data:
[be1ec9f]252                    self._manager.page_finder[self.uid].set_fit_data(data=\
253                                                                [self.data])
[33477fd]254            self.on_smear_helper(update=True)
[ef26c83]255            self.state.enable_smearer = self.enable_smearer.GetValue()
256            self.state.disable_smearer = self.disable_smearer.GetValue()
[33477fd]257            self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
258            self.state.slit_smearer = self.slit_smearer.GetValue()
[ecf26e1]259       
260    def _create_default_1d_data(self):
261        """
[ef26c83]262        Create default data for fitting perspective
[ecf26e1]263        Only when the page is on theory mode.
264        :warning: This data is never plotted.
265       
266        """
[ef26c83]267        x = numpy.linspace(start=self.qmin_x, stop=self.qmax_x,
[ecf26e1]268                           num=self.npts_x, endpoint=True)
269        self.data = Data1D(x=x)
[ef26c83]270        self.data.xaxis('\\rm{Q}', "A^{-1}")
[ecf26e1]271        self.data.yaxis('\\rm{Intensity}', "cm^{-1}")
272        self.data.is_data = False
[ef26c83]273        self.data.id = str(self.uid) + " data"
274        self.data.group_id = str(self.uid) + " Model1D"
[cb270ad2]275         
276    def _create_log_1d_data(self):
277        """
278        Create log-spaced data for fitting perspective
279        Only when the page is on theory mode.
280        :warning: This data is never plotted.
281       
282        """
283        if self.qmin_x >= 1.e-10:
284            qmin = numpy.log10(self.qmin_x)
285        else:
286            qmin = -10.   
287           
288        if self.qmax_x <= 1.e10:
289            qmax = numpy.log10(self.qmax_x)
290        else:
291            qmax = 10. 
292               
293        x = numpy.logspace(start=qmin, stop=qmax,
294                           num=self.npts_x, endpoint=True, base=10.0)
295        self.data = Data1D(x=x)
296        self.data.xaxis('\\rm{Q}', "A^{-1}")
297        self.data.yaxis('\\rm{Intensity}', "cm^{-1}")
298        self.data.is_data = False
299        self.data.id = str(self.uid) + " data"
300        self.data.group_id = str(self.uid) + " Model1D"
301     
[ecf26e1]302    def _create_default_2d_data(self):
303        """
304        Create 2D data by default
305        Only when the page is on theory mode.
306        :warning: This data is never plotted.
307        """
308        self.data = Data2D()
[2e95da4]309        qmax = self.qmax_x / math.sqrt(2)
[ecf26e1]310        self.data.xaxis('\\rm{Q_{x}}', 'A^{-1}')
311        self.data.yaxis('\\rm{Q_{y}}', 'A^{-1}')
312        self.data.is_data = False
[ef26c83]313        self.data.id = str(self.uid) + " data"
314        self.data.group_id = str(self.uid) + " Model2D"
315        ## Default values
316        self.data.detector.append(Detector())
[ecf26e1]317        index = len(self.data.detector) - 1
[ef26c83]318        self.data.detector[index].distance = 8000   # mm
319        self.data.source.wavelength = 6             # A
[ecf26e1]320        self.data.detector[index].pixel_size.x = 5  # mm
321        self.data.detector[index].pixel_size.y = 5  # mm
322        self.data.detector[index].beam_center.x = qmax
323        self.data.detector[index].beam_center.y = qmax
324        ## create x_bins and y_bins of the model 2D
[ef26c83]325        #pixel_width_x = self.data.detector[index].pixel_size.x
326        #pixel_width_y = self.data.detector[index].pixel_size.y
327        #center_x = self.data.detector[index].beam_center.x/pixel_width_x
328        #center_y = self.data.detector[index].beam_center.y/pixel_width_y
329        # theory default: assume the beam
[ecf26e1]330        #center is located at the center of sqr detector
[ef26c83]331        xmax = qmax
[32cd80c]332        xmin = -qmax
333        ymax = qmax
334        ymin = -qmax
[ecf26e1]335        qstep = self.npts_x
[2e95da4]336
[ef26c83]337        x = numpy.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
[ecf26e1]338        y = numpy.linspace(start=ymin, stop=ymax, num=qstep, endpoint=True)
339        ## use data info instead
340        new_x = numpy.tile(x, (len(y), 1))
341        new_y = numpy.tile(y, (len(x), 1))
[ef26c83]342        new_y = new_y.swapaxes(0, 1)
[ecf26e1]343        # all data reuire now in 1d array
344        qx_data = new_x.flatten()
345        qy_data = new_y.flatten()
[ef26c83]346        q_data = numpy.sqrt(qx_data * qx_data + qy_data * qy_data)
[ecf26e1]347        # set all True (standing for unmasked) as default
348        mask = numpy.ones(len(qx_data), dtype=bool)
349        # calculate the range of qx and qy: this way,
350        # it is a little more independent
[ef26c83]351        #x_size = xmax - xmin
352        #y_size = ymax - ymin
[ecf26e1]353        # store x and y bin centers in q space
[ef26c83]354        x_bins = x
355        y_bins = y
[ecf26e1]356        # bin size: x- & y-directions
[ef26c83]357        #xstep = x_size / len(x_bins - 1)
358        #ystep = y_size / len(y_bins - 1)
[32cd80c]359 
[ecf26e1]360        self.data.source = Source()
[32cd80c]361        self.data.data = numpy.ones(len(mask))
[ecf26e1]362        self.data.err_data = numpy.ones(len(mask))
[ef26c83]363        self.data.qx_data = qx_data
364        self.data.qy_data = qy_data
365        self.data.q_data = q_data
366        self.data.mask = mask
367        self.data.x_bins = x_bins
368        self.data.y_bins = y_bins
[ecf26e1]369        # max and min taking account of the bin sizes
[ef26c83]370        self.data.xmin = xmin
[ecf26e1]371        self.data.xmax = xmax
[ef26c83]372        self.data.ymin = ymin
373        self.data.ymax = ymax
[2e95da4]374
[3cd5806]375    def on_set_focus(self, event):
376        """
[dafc36f]377        On Set Focus, update guimanger and menu
[3cd5806]378        """
379        if self._manager is not None:
380            wx.PostEvent(self._manager.parent, PanelOnFocusEvent(panel=self))
[58fc26c]381            self.on_tap_focus()
[dafc36f]382               
[58fc26c]383    def on_tap_focus(self):
384        """
385        Update menu1 on cliking the page tap
386        """
387        if self._manager.menu1 != None:
388            chain_menu = self._manager.menu1.FindItemById(\
[ef26c83]389                                                   self._manager.id_reset_flag)
[58fc26c]390            chain_menu.Enable(self.batch_on)
391            sim_menu = self._manager.menu1.FindItemById(self._manager.id_simfit)
[fa02d95]392            flag = self.data.is_data\
[ef26c83]393                            and (self.model != None)
[fa02d95]394            sim_menu.Enable(not self.batch_on and flag)
[be1ec9f]395            batch_menu = \
396                    self._manager.menu1.FindItemById(self._manager.id_batchfit)
[ef26c83]397            batch_menu.Enable(self.batch_on and flag)
[58fc26c]398   
[6f2c919]399    class ModelTextCtrl(wx.TextCtrl):
400        """
[5062bbf]401        Text control for model and fit parameters.
402        Binds the appropriate events for user interactions.
403        Default callback methods can be overwritten on initialization
404       
405        :param kill_focus_callback: callback method for EVT_KILL_FOCUS event
406        :param set_focus_callback:  callback method for EVT_SET_FOCUS event
407        :param mouse_up_callback:   callback method for EVT_LEFT_UP event
408        :param text_enter_callback: callback method for EVT_TEXT_ENTER event
409       
[6f2c919]410        """
[be1ec9f]411        ## Set to True when the mouse is clicked while whole string is selected
[39b7019]412        full_selection = False
413        ## Call back for EVT_SET_FOCUS events
414        _on_set_focus_callback = None
415       
[ef26c83]416        def __init__(self, parent, id=-1,
417                     value=wx.EmptyString,
418                     pos=wx.DefaultPosition,
[4a7ad5f]419                     size=wx.DefaultSize,
[ef26c83]420                     style=0,
[4a7ad5f]421                     validator=wx.DefaultValidator,
422                     name=wx.TextCtrlNameStr,
423                     kill_focus_callback=None,
424                     set_focus_callback=None,
425                     mouse_up_callback=None,
[ef26c83]426                     text_enter_callback=None):
[7975f2b]427             
[4a7ad5f]428            wx.TextCtrl.__init__(self, parent, id, value, pos,
429                                  size, style, validator, name)
[6f2c919]430           
[156a0b2]431            # Bind appropriate events
432            self._on_set_focus_callback = parent.onSetFocus \
433                      if set_focus_callback is None else set_focus_callback
434            self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
[7609f1a]435            self.Bind(wx.EVT_KILL_FOCUS, self._silent_kill_focus \
[ef26c83]436                      if kill_focus_callback is None else kill_focus_callback)
[6f2c919]437            self.Bind(wx.EVT_TEXT_ENTER, parent._onparamEnter \
438                      if text_enter_callback is None else text_enter_callback)
[ef26c83]439            if not ON_MAC:
440                self.Bind(wx.EVT_LEFT_UP, self._highlight_text \
[35c9d31]441                          if mouse_up_callback is None else mouse_up_callback)
[39b7019]442           
443        def _on_set_focus(self, event):
444            """
[5062bbf]445            Catch when the text control is set in focus to highlight the whole
446            text if necessary
447           
448            :param event: mouse event
449           
[39b7019]450            """
451            event.Skip()
452            self.full_selection = True
453            return self._on_set_focus_callback(event)
454       
455        def _highlight_text(self, event):
456            """
[5062bbf]457            Highlight text of a TextCtrl only of no text has be selected
458           
459            :param event: mouse event
460           
[39b7019]461            """
462            # Make sure the mouse event is available to other listeners
463            event.Skip()
[ef26c83]464            control = event.GetEventObject()
[39b7019]465            if self.full_selection:
466                self.full_selection = False
467                # Check that we have a TextCtrl
468                if issubclass(control.__class__, wx.TextCtrl):
[ef26c83]469                    # Check whether text has been selected,
[39b7019]470                    # if not, select the whole string
471                    (start, end) = control.GetSelection()
[ef26c83]472                    if start == end:
473                        control.SetSelection(-1, -1)
[7609f1a]474                       
[ef26c83]475        def _silent_kill_focus(self, event):
[7609f1a]476            """
[3c44c66]477            Save the state of the page
[7609f1a]478            """
[3c44c66]479           
[7609f1a]480            event.Skip()
[be1ec9f]481            #pass
[7609f1a]482   
[ffa69b6]483    def set_page_info(self, page_info):
484        """
[5062bbf]485        set some page important information at once
[ffa69b6]486        """
[116e1a7]487#       THIS METHOD/FUNCTION NO LONGE APPEARS TO BE CALLED.  Started up program
488#       and started new fit window and PR and Invariant and a fit in fitting
489#       but never entered this routine which should be an initialization
490#       routine.  Leave for a while but probably something to clean up at
491#       some point?
492#
493#       PDB April 13 2014
494#
[ef26c83]495        ##window_name
[ffa69b6]496        self.window_name = page_info.window_name
497        ##window_caption
498        self.window_caption = page_info.window_caption
499        ## manager is the fitting plugin
[ef26c83]500        self._manager = page_info.manager
[ffa69b6]501        ## owner of the page (fitting plugin)
[ef26c83]502        self.event_owner = page_info.event_owner
503        ## current model
[ffa69b6]504        self.model = page_info.model
505        ## data
506        self.data = page_info.data
507        ## dictionary containing list of models
508        self.model_list_box = page_info.model_list_box
509        ## Data member to store the dispersion object created
[eddb6ec]510        self.populate_box(model_dict=self.model_list_box)
[ffa69b6]511       
[ef26c83]512    def onContextMenu(self, event):
[a074145]513        """
[5062bbf]514        Retrieve the state selected state
[a074145]515        """
[6d1235b]516        # Skipping the save state functionality for release 0.9.0
[dad49a0]517        #return
[6d1235b]518   
[a074145]519        pos = event.GetPosition()
520        pos = self.ScreenToClient(pos)
[1b69256]521       
[ef26c83]522        self.PopupMenu(self.popUpMenu, pos)
[1b69256]523     
524    def onUndo(self, event):
525        """
[5062bbf]526        Cancel the previous action
[1b69256]527        """
[ef26c83]528        event = PreviousStateEvent(page=self)
[330573d]529        wx.PostEvent(self.parent, event)
530       
[1b69256]531    def onRedo(self, event):
532        """
[ef26c83]533        Restore the previous action cancelled
[1b69256]534        """
[ef26c83]535        event = NextStateEvent(page=self)
[330573d]536        wx.PostEvent(self.parent, event)
[5062bbf]537   
[c77d859]538    def define_page_structure(self):
539        """
[5062bbf]540        Create empty sizer for a panel
[c77d859]541        """
[ef26c83]542        self.vbox = wx.BoxSizer(wx.VERTICAL)
[c77d859]543        self.sizer0 = wx.BoxSizer(wx.VERTICAL)
544        self.sizer1 = wx.BoxSizer(wx.VERTICAL)
545        self.sizer2 = wx.BoxSizer(wx.VERTICAL)
546        self.sizer3 = wx.BoxSizer(wx.VERTICAL)
547        self.sizer4 = wx.BoxSizer(wx.VERTICAL)
548        self.sizer5 = wx.BoxSizer(wx.VERTICAL)
[0a518e4c]549        self.sizer6 = wx.BoxSizer(wx.VERTICAL)
[c77d859]550       
[ef26c83]551        self.sizer0.SetMinSize((PANEL_WIDTH, -1))
552        self.sizer1.SetMinSize((PANEL_WIDTH, -1))
553        self.sizer2.SetMinSize((PANEL_WIDTH, -1))
554        self.sizer3.SetMinSize((PANEL_WIDTH, -1))
555        self.sizer4.SetMinSize((PANEL_WIDTH, -1))
556        self.sizer5.SetMinSize((PANEL_WIDTH, -1))
557        self.sizer6.SetMinSize((PANEL_WIDTH, -1))
[8bd4dc0]558       
[c77d859]559        self.vbox.Add(self.sizer0)
560        self.vbox.Add(self.sizer1)
561        self.vbox.Add(self.sizer2)
562        self.vbox.Add(self.sizer3)
563        self.vbox.Add(self.sizer4)
564        self.vbox.Add(self.sizer5)
[0b12abb5]565        self.vbox.Add(self.sizer6)
[a074145]566       
[c77d859]567    def set_layout(self):
568        """
[5062bbf]569        layout
[c77d859]570        """
571        self.vbox.Layout()
[ef26c83]572        self.vbox.Fit(self)
[c77d859]573        self.SetSizer(self.vbox)
574        self.Centre()
[340c2b3]575 
[ef26c83]576    def set_owner(self, owner):
577        """
[5062bbf]578        set owner of fitpage
579       
580        :param owner: the class responsible of plotting
581       
[c77d859]582        """
[ef26c83]583        self.event_owner = owner
[cfc0913]584        self.state.event_owner = owner
[7609f1a]585       
[c8deee5]586    def get_state(self):
587        """
588        """
589        return self.state
[cc31608]590   
[2f189dc]591    def get_data(self):
592        """
[ef26c83]593        return the current data
[2f189dc]594        """
[ef26c83]595        return self.data
[7609f1a]596   
[cc31608]597    def get_data_list(self):
598        """
[ef26c83]599        return the current data
[cc31608]600        """
[ef26c83]601        return self.data_list
[cc31608]602   
[c77d859]603    def set_manager(self, manager):
604        """
[5062bbf]605        set panel manager
606       
607        :param manager: instance of plugin fitting
608       
[c77d859]609        """
[ef26c83]610        self._manager = manager
[cfc0913]611        self.state.manager = manager
[c77d859]612       
[eddb6ec]613    def populate_box(self, model_dict):
[c77d859]614        """
[5062bbf]615        Store list of model
616       
[eddb6ec]617        :param model_dict: dictionary containing list of models
[5062bbf]618       
[c77d859]619        """
[eddb6ec]620        self.model_list_box = model_dict
[ea5fa58]621        self.state.model_list_box = self.model_list_box
622        self.initialize_combox()
[c77d859]623       
[df7a7e3]624    def set_model_dictionary(self, model_dict):
625        """
626        Store a dictionary linking model name -> model object
627
628        :param model_dict: dictionary containing list of models
629        """
630        self.model_dict = model_dict
631
[ef26c83]632    def initialize_combox(self):
[ffa69b6]633        """
[ef26c83]634        put default value in the combobox
[ffa69b6]635        """ 
636        ## fill combox box
637        if self.model_list_box is None:
638            return
[ea5fa58]639        if len(self.model_list_box) > 0:
[116e1a7]640        ## This is obsolete code since form factor box is no longer static.
641        ## It is now set dynamically through _show_combox and _show_combos_helper
642        ## These are called for first time by formfactor_combo_init
643        ## itself called from fitpanel only.  If we find that I'm wrong and
644        ## we DO need to initialize somehow here - do it by a call to
645        ## formfactor_combo_init
646        ## self.formfator_combo_init()
647        ## BUT NOT HERE -- make it last line of this
648        ## method so that structure box is populated before _show_comboox_helper
649        ## is called.  Otherwise wx will complain mightily:-)
650        ##
651        ## Also change the name to initiatlize_structurebox along with changes
652        ## to other combobox methods (_populate_listbox --> _populate_categorybox
653        ## etc )
654        ##
655        ##     PDB 4/26/2014
656#            self._populate_box(self.formfactorbox,
657#                               self.model_list_box["Shapes"])
[4a7ad5f]658            self._populate_box(self.structurebox,
[ffa69b6]659                                self.model_list_box["Structure Factors"])
[4a7ad5f]660            self.structurebox.Insert("None", 0, None)
[ffa69b6]661            self.structurebox.SetSelection(0)
662            self.structurebox.Hide()
663            self.text2.Hide()
664            self.structurebox.Disable()
665            self.text2.Disable()
666             
667            if self.model.__class__ in self.model_list_box["P(Q)*S(Q)"]:
668                self.structurebox.Show()
669                self.text2.Show()
670                self.structurebox.Enable()
[ef26c83]671                self.text2.Enable()
[116e1a7]672
[ffa69b6]673               
[c77d859]674    def set_dispers_sizer(self):
675        """
[5062bbf]676        fill sizer containing dispersity info
[c77d859]677        """
678        self.sizer4.Clear(True)
[ef26c83]679        name = "Polydispersity and Orientational Distribution"
680        box_description = wx.StaticBox(self, -1, name)
[de5036c]681        box_description.SetForegroundColour(wx.BLUE)
[c77d859]682        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
683        #----------------------------------------------------
[4a7ad5f]684        self.disable_disp = wx.RadioButton(self, -1, 'Off', (10, 10),
685                                            style=wx.RB_GROUP)
[fa58441]686        self.enable_disp = wx.RadioButton(self, -1, 'On', (10, 30))
[6f23daf]687        # best size for MAC and PC
688        if ON_MAC:
[ef26c83]689            size_q = (30, 20)
[6f23daf]690        else:
[ef26c83]691            size_q = (20, 15)
692        self.disp_help_bt = wx.Button(self, wx.NewId(), '?',
693                                      style=wx.BU_EXACTFIT,
[6f23daf]694                                      size=size_q)
[ef26c83]695        self.disp_help_bt.Bind(wx.EVT_BUTTON,
696                        self.on_pd_help_clicked, id=self.disp_help_bt.GetId())
697        self.disp_help_bt.SetToolTipString("Helps for Polydispersion.")
[cfc0913]698       
[4a7ad5f]699        self.Bind(wx.EVT_RADIOBUTTON, self._set_dipers_Param,
700                     id=self.disable_disp.GetId())
701        self.Bind(wx.EVT_RADIOBUTTON, self._set_dipers_Param,
702                   id=self.enable_disp.GetId())
[ff8f99b]703        #MAC needs SetValue
704        self.disable_disp.SetValue(True)
[c77d859]705        sizer_dispersion = wx.BoxSizer(wx.HORIZONTAL)
[ef26c83]706        sizer_dispersion.Add((20, 20))
707        name = ""  # Polydispersity and \nOrientational Distribution "
708        sizer_dispersion.Add(wx.StaticText(self, -1, name))
709        sizer_dispersion.Add(self.enable_disp)
710        sizer_dispersion.Add((20, 20))
711        sizer_dispersion.Add(self.disable_disp)
712        sizer_dispersion.Add((25, 20))
[2296316]713        sizer_dispersion.Add(self.disp_help_bt)
[c77d859]714       
[ef26c83]715        ## fill a sizer for dispersion
716        boxsizer1.Add(sizer_dispersion, 0,
717                wx.TOP | wx.BOTTOM | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE,
718                border=5)
719        self.sizer4_4 = wx.GridBagSizer(6, 5)
[2296316]720
[ef26c83]721        boxsizer1.Add(self.sizer4_4)
[c77d859]722        #-----------------------------------------------------
[ef26c83]723        self.sizer4.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
[3b605bb]724        self.sizer4_4.Layout()
[c77d859]725        self.sizer4.Layout()
[3b605bb]726        self.Layout()
[340c2b3]727     
[3b605bb]728        self.Refresh()
[71f0373]729        ## saving the state of enable dispersity button
[ef26c83]730        self.state.enable_disp = self.enable_disp.GetValue()
731        self.state.disable_disp = self.disable_disp.GetValue()
[ce92ded]732        self.SetupScrolling()
[a074145]733   
734    def onResetModel(self, event):
735        """
[5062bbf]736        Reset model state
[a074145]737        """
[20b228a0]738        menu = event.GetEventObject()
[ef26c83]739        ## post help message for the selected model
[20b228a0]740        msg = menu.GetHelpString(event.GetId())
[ef26c83]741        msg += " reloaded"
[ae84427]742        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[01642fec]743        self.Show(False)
[20b228a0]744        name = menu.GetLabel(event.GetId())
[cbf01fd]745        self._on_select_model_helper()
[93f0a862]746        if self.model != None:
747            self.m_name = self.model.name
[a074145]748        if name in self.saved_states.keys():
749            previous_state = self.saved_states[name]
[f20767b]750            ## reset state of checkbox,textcrtl  and  regular parameters value
[01642fec]751           
[ef26c83]752            self.reset_page(previous_state)
[93f0a862]753        self.state.m_name = self.m_name
[01642fec]754        self.Show(True)
[2296316]755               
[aad74b3]756    def on_preview(self, event):
[2296316]757        """
758        Report the current fit results
[ef26c83]759        """
[2296316]760        # Get plot image from plotpanel
761        images, canvases = self.get_images()
762        # get the report dialog
763        self.state.report(images, canvases)
764       
[ef26c83]765    def on_save(self, event):
[9bc499b6]766        """
[5062bbf]767        Save the current state into file
[ef26c83]768        """
[bb70474]769        self.save_current_state()
770        new_state = self.state.clone()
771        # Ask the user the location of the file to write to.
772        path = None
[ef26c83]773        if self.parent != None:
[baf1ef3]774            self._default_save_location = \
[ae84427]775                        self._manager.parent._default_save_location
[bb70474]776        dlg = wx.FileDialog(self, "Choose a file", self._default_save_location,
[baf1ef3]777                                        self.window_caption, "*.fitv", wx.SAVE)
778
[bb70474]779        if dlg.ShowModal() == wx.ID_OK:
780            path = dlg.GetPath()
781            self._default_save_location = os.path.dirname(path)
[ae84427]782            self._manager.parent._default_save_location =\
[baf1ef3]783                                 self._default_save_location
[bb70474]784        else:
785            return None
[23cdeab]786        # MAC always needs the extension for saving
787        extens = ".fitv"
788        # Make sure the ext included in the file name
789        fName = os.path.splitext(path)[0] + extens
[bb70474]790        #the manager write the state into file
[23cdeab]791        self._manager.save_fit_state(filepath=fName, fitstate=new_state)
[ef26c83]792        return new_state
[0b12abb5]793   
[07c8630]794    def on_copy(self, event):
795        """
796        Copy Parameter values to the clipboad
797        """
798        if event != None:
799            event.Skip()
[2d603a2]800        # It seems MAC needs wxCallAfter
[34dbaf4]801        if event.GetId() == GUIFRAME_ID.COPYEX_ID:
802            print "copy excel"
803            wx.CallAfter(self.get_copy_excel)
804        elif event.GetId() == GUIFRAME_ID.COPYLAT_ID:
805            print "copy latex"
806            wx.CallAfter(self.get_copy_latex)
807        else:
808            wx.CallAfter(self.get_copy)
809
[2d603a2]810       
[07c8630]811    def on_paste(self, event):
812        """
813        Paste Parameter values to the panel if possible
814        """
[2a66329]815        #if event != None:
816        #    event.Skip()
[ef26c83]817        # It seems MAC needs wxCallAfter for the setvalues
818        # for multiple textctrl items, otherwise it tends to crash once a while
[6694604]819        wx.CallAfter(self.get_paste)
[07c8630]820        # messages depending on the flag
[977a965]821        #self._copy_info(True)
[07c8630]822       
823    def _copy_info(self, flag):
824        """
825        Send event dpemding on flag
826       
827        : Param flag: flag that distinguish event
828        """
829        # messages depending on the flag
830        if flag == None:
831            msg = " Parameter values are copied to the clipboard..."
832            infor = 'warning'
833        elif flag:
[6e653582]834            msg = " Parameter values are pasted from the clipboard..."
[07c8630]835            infor = "warning"
836        else:
[6e653582]837            msg = "Error occurred: "
[6fe5100]838            msg += "No valid parameter values to paste from the clipboard..."
[6e653582]839            infor = "warning"
[07c8630]840        # inform msg to wx
[ae84427]841        wx.PostEvent(self._manager.parent,
[ef26c83]842                    StatusEvent(status=msg, info=infor))
[07c8630]843       
[20b228a0]844    def _get_time_stamp(self):
845        """
846        return time and date stings
847        """
[ef26c83]848        # date and time
[be1ec9f]849        year, month, day, hour, minute, second, _, _, _ = time.localtime()
[ef26c83]850        current_time = str(hour) + ":" + str(minute) + ":" + str(second)
851        current_date = str(month) + "/" + str(day) + "/" + str(year)
[20b228a0]852        return current_time, current_date
853     
[9bc499b6]854    def on_bookmark(self, event):
[00c3aac]855        """
[5062bbf]856        save history of the data and model
[00c3aac]857        """
[ef26c83]858        if self.model == None:
859            msg = "Can not bookmark; Please select Data and Model first..."
[4470b10]860            wx.MessageBox(msg, 'Info')
[ef26c83]861            return
[0b12abb5]862        self.save_current_state()
863        new_state = self.state.clone()
864        ##Add model state on context menu
865        self.number_saved_state += 1
[20b228a0]866        current_time, current_date = self._get_time_stamp()
[ef26c83]867        #name= self.model.name+"[%g]"%self.number_saved_state
868        name = "Fitting: %g]" % self.number_saved_state
869        name += self.model.__class__.__name__
[20b228a0]870        name += "bookmarked at %s on %s" % (current_time, current_date)
[ef26c83]871        self.saved_states[name] = new_state
[0b12abb5]872       
873        ## Add item in the context menu
[ef26c83]874        msg = "Model saved at %s on %s" % (current_time, current_date)
875        ## post help message for the selected model
876        msg += " Saved! right click on this page to retrieve this model"
[ae84427]877        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[0b12abb5]878       
[1258aa3]879        id = wx.NewId()
[ef26c83]880        self.popUpMenu.Append(id, name, str(msg))
[1258aa3]881        wx.EVT_MENU(self, id, self.onResetModel)
[ae84427]882        wx.PostEvent(self._manager.parent,
[ef26c83]883                     AppendBookmarkEvent(title=name,
884                                         hint=str(msg),
885                                         handler=self._back_to_bookmark))
886   
887    def _back_to_bookmark(self, event):
[95b2bad]888        """
889        Back to bookmark
890        """
891        self._manager.on_perspective(event)
892        self.onResetModel(event)
[7fd4afd]893        self._draw_model()
[0b477f6]894               
[1328e03]895    def onSetFocus(self, evt):
[77e23a2]896        """
[ef26c83]897        highlight the current textcrtl and hide the error text control shown
[5062bbf]898        after fitting
[77e23a2]899        """
[1328e03]900        return
[c77d859]901   
902    def read_file(self, path):
903        """
[5062bbf]904        Read two columns file
905       
906        :param path: the path to the file to read
907       
[c77d859]908        """
909        try:
[ef26c83]910            if path == None:
[ae84427]911                wx.PostEvent(self._manager.parent,
[d49c956]912                            StatusEvent(status= \
913                            " Selected Distribution was not loaded: %s" % path))
[c77d859]914                return None, None
915            input_f = open(path, 'r')
916            buff = input_f.read()
917            lines = buff.split('\n')
[d49c956]918            input_f.close()
[c77d859]919            angles = []
[ef26c83]920            weights = []
[c77d859]921            for line in lines:
922                toks = line.split()
[502de0a]923                try:
924                    angle = float(toks[0])
925                    weight = float(toks[1])
[d49c956]926                    angles.append(angle)
927                    weights.append(weight)
[502de0a]928                except:
929                    # Skip non-data lines
930                    pass
[c77d859]931            return numpy.array(angles), numpy.array(weights)
932        except:
[ef26c83]933            raise
[5062bbf]934
[cfc0913]935    def createMemento(self):
936        """
[5062bbf]937        return the current state of the page
[cfc0913]938        """
939        return self.state.clone()
940   
941    def save_current_state(self):
942        """
[5062bbf]943        Store current state
[cfc0913]944        """
[e3d1423]945        self.state.engine_type = copy.deepcopy(self.engine_type)
[0aeabc6]946        ## save model option
[ef26c83]947        if self.model != None:
948            self.disp_list = self.model.getDispParamList()
949            self.state.disp_list = copy.deepcopy(self.disp_list)
[87fbc60]950            self.state.model = self.model.clone()
[940aca7]951           
952            #model combobox: complex code because of mac's silent error
953            if self.structurebox != None:
954                if self.structurebox.IsShown():
955                    self.state.structurecombobox = 'None'
956                    s_select = self.structurebox.GetSelection()
957                    if s_select > 0:
958                        self.state.structurecombobox = self.structurebox.\
959                        GetString(s_select)
[ea5fa58]960            if self.formfactorbox != None:
961                f_select = self.formfactorbox.GetSelection()
962                if f_select > 0:
[eddb6ec]963                    self.state.formfactorcombobox = self.formfactorbox.\
964                    GetString(f_select)
[ea5fa58]965        if self.categorybox != None:
[eddb6ec]966            cb_select = self.categorybox.GetSelection()
967            if cb_select > 0:
968                self.state.categorycombobox = self.categorybox.\
969                GetString(cb_select)
[0b12abb5]970       
[c477b31]971        self.state.enable2D = copy.deepcopy(self.enable2D)
[ef26c83]972        self.state.values = copy.deepcopy(self.values)
973        self.state.weights = copy.deepcopy(self.weights)
974        ## save data
975        self.state.data = copy.deepcopy(self.data)
[0b12abb5]976        self.state.qmax_x = self.qmax_x
977        self.state.qmin_x = self.qmin_x
[55bb249c]978        self.state.dI_noweight = copy.deepcopy(self.dI_noweight.GetValue())
979        self.state.dI_didata = copy.deepcopy(self.dI_didata.GetValue())
980        self.state.dI_sqrdata = copy.deepcopy(self.dI_sqrdata.GetValue())
981        self.state.dI_idata = copy.deepcopy(self.dI_idata.GetValue())
[db8590a]982        self.state.dq_l = self.dq_l
983        self.state.dq_r = self.dq_r
[ef26c83]984        if hasattr(self, "enable_disp"):
985            self.state.enable_disp = self.enable_disp.GetValue()
[fc6ea43]986            self.state.disable_disp = self.disable_disp.GetValue()
987           
[6e4c9fe]988        self.state.smearer = copy.deepcopy(self.current_smearer)
[ef26c83]989        if hasattr(self, "enable_smearer"):
[4a7ad5f]990            self.state.enable_smearer = \
991                                copy.deepcopy(self.enable_smearer.GetValue())
992            self.state.disable_smearer = \
993                                copy.deepcopy(self.disable_smearer.GetValue())
[7609f1a]994
[4a7ad5f]995        self.state.pinhole_smearer = \
996                                copy.deepcopy(self.pinhole_smearer.GetValue())
[db8fd5b]997        self.state.dx_max = copy.deepcopy(self.dx_max)
998        self.state.dx_min = copy.deepcopy(self.dx_min)
999        self.state.dxl = copy.deepcopy(self.dxl)
1000        self.state.dxw = copy.deepcopy(self.dxw)
[ef26c83]1001        self.state.slit_smearer = copy.deepcopy(self.slit_smearer.GetValue())
[7609f1a]1002                 
[ef26c83]1003        if len(self._disp_obj_dict) > 0:
1004            for k, v in self._disp_obj_dict.iteritems():
1005                self.state._disp_obj_dict[k] = v
1006
[71f0373]1007            self.state.values = copy.deepcopy(self.values)
1008            self.state.weights = copy.deepcopy(self.weights)
[0aeabc6]1009        ## save plotting range
[b787e68c]1010        self._save_plotting_range()
[d2d0cfdf]1011       
[2296316]1012        self.state.orientation_params = []
1013        self.state.orientation_params_disp = []
1014        self.state.parameters = []
1015        self.state.fittable_param = []
1016        self.state.fixed_param = []
1017        self.state.str_parameters = []
[f20767b]1018
[cfc0913]1019        ## save checkbutton state and txtcrtl values
[ef26c83]1020        self._copy_parameters_state(self.str_parameters,
[2296316]1021                                    self.state.str_parameters)
[fc6ea43]1022        self._copy_parameters_state(self.orientation_params,
1023                                     self.state.orientation_params)
1024        self._copy_parameters_state(self.orientation_params_disp,
1025                                     self.state.orientation_params_disp)
[f20767b]1026       
[d2d0cfdf]1027        self._copy_parameters_state(self.parameters, self.state.parameters)
[4a7ad5f]1028        self._copy_parameters_state(self.fittable_param,
1029                                     self.state.fittable_param)
[d2d0cfdf]1030        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
[3c44c66]1031        #save chisqr
1032        self.state.tcChi = self.tcChi.GetValue()
1033       
[52cac46]1034    def save_current_state_fit(self):
1035        """
[5062bbf]1036        Store current state for fit_page
[52cac46]1037        """
1038        ## save model option
[ef26c83]1039        if self.model != None:
1040            self.disp_list = self.model.getDispParamList()
1041            self.state.disp_list = copy.deepcopy(self.disp_list)
[52cac46]1042            self.state.model = self.model.clone()
[9bc499b6]1043        if hasattr(self, "engine_type"):
1044            self.state.engine_type = copy.deepcopy(self.engine_type)
1045           
[52cac46]1046        self.state.enable2D = copy.deepcopy(self.enable2D)
[ef26c83]1047        self.state.values = copy.deepcopy(self.values)
1048        self.state.weights = copy.deepcopy(self.weights)
1049        ## save data
1050        self.state.data = copy.deepcopy(self.data)
[52cac46]1051       
[ef26c83]1052        if hasattr(self, "enable_disp"):
1053            self.state.enable_disp = self.enable_disp.GetValue()
[52cac46]1054            self.state.disable_disp = self.disable_disp.GetValue()
1055           
[6e4c9fe]1056        self.state.smearer = copy.deepcopy(self.current_smearer)
[ef26c83]1057        if hasattr(self, "enable_smearer"):
[4a7ad5f]1058            self.state.enable_smearer = \
1059                                copy.deepcopy(self.enable_smearer.GetValue())
1060            self.state.disable_smearer = \
1061                                copy.deepcopy(self.disable_smearer.GetValue())
[52cac46]1062           
[4a7ad5f]1063        self.state.pinhole_smearer = \
1064                                copy.deepcopy(self.pinhole_smearer.GetValue())
[ef26c83]1065        self.state.slit_smearer = copy.deepcopy(self.slit_smearer.GetValue())
[55bb249c]1066        self.state.dI_noweight = copy.deepcopy(self.dI_noweight.GetValue())
1067        self.state.dI_didata = copy.deepcopy(self.dI_didata.GetValue())
1068        self.state.dI_sqrdata = copy.deepcopy(self.dI_sqrdata.GetValue())
[ef26c83]1069        self.state.dI_idata = copy.deepcopy(self.dI_idata.GetValue())
[7d514fc]1070        if hasattr(self, "disp_box") and self.disp_box != None:
[52cac46]1071            self.state.disp_box = self.disp_box.GetCurrentSelection()
1072
[4a7ad5f]1073            if len(self.disp_cb_dict) > 0:
1074                for k, v in self.disp_cb_dict.iteritems():
[ef26c83]1075                    if v == None:
[4a7ad5f]1076                        self.state.disp_cb_dict[k] = v
[52cac46]1077                    else:
1078                        try:
[4a7ad5f]1079                            self.state.disp_cb_dict[k] = v.GetValue()
[52cac46]1080                        except:
[4a7ad5f]1081                            self.state.disp_cb_dict[k] = None
1082            if len(self._disp_obj_dict) > 0:
[ef26c83]1083                for k, v in self._disp_obj_dict.iteritems():
[4a7ad5f]1084                    self.state._disp_obj_dict[k] = v
[52cac46]1085                       
1086            self.state.values = copy.deepcopy(self.values)
1087            self.state.weights = copy.deepcopy(self.weights)
[b421b1a]1088           
[52cac46]1089        ## save plotting range
1090        self._save_plotting_range()
1091       
1092        ## save checkbutton state and txtcrtl values
1093        self._copy_parameters_state(self.orientation_params,
1094                                     self.state.orientation_params)
1095        self._copy_parameters_state(self.orientation_params_disp,
1096                                     self.state.orientation_params_disp)
1097        self._copy_parameters_state(self.parameters, self.state.parameters)
[4a7ad5f]1098        self._copy_parameters_state(self.fittable_param,
1099                                             self.state.fittable_param)
[52cac46]1100        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
[a074145]1101   
[ef26c83]1102    def check_invalid_panel(self):
[ffa69b6]1103        """
[5062bbf]1104        check if the user can already perform some action with this panel
[ef26c83]1105        """
[4470b10]1106        if self.data is None:
1107            self.disable_smearer.SetValue(True)
1108            self.disable_disp.SetValue(True)
1109            msg = "Please load Data and select Model to start..."
[ffa69b6]1110            wx.MessageBox(msg, 'Info')
1111            return  True
[5062bbf]1112       
[e88ebfd]1113    def set_model_state(self, state):
1114        """
1115        reset page given a model state
1116        """
1117        self.disp_cb_dict = state.disp_cb_dict
1118        self.disp_list = state.disp_list
1119     
[ea5fa58]1120        ## set the state of the radio box
1121        #self.shape_rbutton.SetValue(state.shape_rbutton)
1122        #self.shape_indep_rbutton.SetValue(state.shape_indep_rbutton)
1123        #self.struct_rbutton.SetValue(state.struct_rbutton)
1124        #self.plugin_rbutton.SetValue(state.plugin_rbutton)
1125       
1126        ## fill model combobox
[e88ebfd]1127        self._show_combox_helper()
[ea5fa58]1128        #select the current model
1129        try:
1130            # to support older version
1131            category_pos = int(state.categorycombobox)
1132        except:
1133            category_pos = 0
1134            for ind_cat in range(self.categorybox.GetCount()):
1135                if self.categorycombobox.GetString(ind_form) == \
1136                                        state.categorycombobox:
1137                    category_pos = int(ind_cat)
1138                    break
1139           
1140        self.categorybox.Select(category_pos)
1141        try:
1142            # to support older version
1143            formfactor_pos = int(state.formfactorcombobox)
1144        except:
1145            formfactor_pos = 0
1146            for ind_form in range(self.formfactorbox.GetCount()):
1147                if self.formfactorbox.GetString(ind_form) == \
1148                                        state.formfactorcombobox:
1149                    formfactor_pos = int(ind_form)
1150                    break
1151           
1152        self.formfactorbox.Select(formfactor_pos)
[d40038e]1153       
1154        try:
1155            # to support older version
1156            structfactor_pos = int(state.structurecombobox)
1157        except:
1158            structfactor_pos = 0
1159            for ind_struct in range(self.structurebox.GetCount()):
[cce182ae]1160                if self.structurebox.GetString(ind_struct) == \
1161                                        state.structurecombobox:
[d40038e]1162                    structfactor_pos = int(ind_struct)
1163                    break
1164               
1165        self.structurebox.SetSelection(structfactor_pos)
1166       
[e88ebfd]1167        if state.multi_factor != None:
1168            self.multifactorbox.SetSelection(state.multi_factor)
1169           
[ef26c83]1170        ## reset state of checkbox,textcrtl  and  regular parameters value
[e88ebfd]1171        self._reset_parameters_state(self.orientation_params_disp,
1172                                     state.orientation_params_disp)
1173        self._reset_parameters_state(self.orientation_params,
1174                                     state.orientation_params)
1175        self._reset_parameters_state(self.str_parameters,
1176                                     state.str_parameters)
[ef26c83]1177        self._reset_parameters_state(self.parameters, state.parameters)
1178        ## display dispersion info layer
[e88ebfd]1179        self.enable_disp.SetValue(state.enable_disp)
1180        self.disable_disp.SetValue(state.disable_disp)
1181       
[7d514fc]1182        if hasattr(self, "disp_box") and self.disp_box != None:
[ef26c83]1183            self.disp_box.SetSelection(state.disp_box)
1184            n = self.disp_box.GetCurrentSelection()
1185            dispersity = self.disp_box.GetClientData(n)
1186            name = dispersity.__name__
[e88ebfd]1187
1188            self._set_dipers_Param(event=None)
1189       
1190            if name == "ArrayDispersion":
1191               
1192                for item in self.disp_cb_dict.keys():
1193                   
[ef26c83]1194                    if hasattr(self.disp_cb_dict[item], "SetValue"):
[e88ebfd]1195                        self.disp_cb_dict[item].SetValue(\
1196                                                    state.disp_cb_dict[item])
1197                        # Create the dispersion objects
[79492222]1198                        from sas.models.dispersion_models import ArrayDispersion
[e88ebfd]1199                        disp_model = ArrayDispersion()
[ef26c83]1200                        if hasattr(state, "values") and \
[e88ebfd]1201                                 self.disp_cb_dict[item].GetValue() == True:
[ef26c83]1202                            if len(state.values) > 0:
1203                                self.values = state.values
1204                                self.weights = state.weights
[e88ebfd]1205                                disp_model.set_weights(self.values,
[ef26c83]1206                                                       state.weights)
[e88ebfd]1207                            else:
1208                                self._reset_dispersity()
1209                       
1210                        self._disp_obj_dict[item] = disp_model
[ef26c83]1211                        # Set the new model as the dispersion object
[e88ebfd]1212                        #for the selected parameter
1213                        self.model.set_dispersion(item, disp_model)
1214                   
1215                        self.model._persistency_dict[item] = \
1216                                                [state.values, state.weights]
1217                   
1218            else:
1219                keys = self.model.getParamList()
1220                for item in keys:
1221                    if item in self.disp_list and \
[ef26c83]1222                        not item in self.model.details:
[e88ebfd]1223                        self.model.details[item] = ["", None, None]
[be1ec9f]1224                self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
1225                self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
[ef26c83]1226        ## smearing info  restore
[e88ebfd]1227        if hasattr(self, "enable_smearer"):
[ef26c83]1228            ## set smearing value whether or not the data
[e88ebfd]1229            #contain the smearing info
1230            self.enable_smearer.SetValue(state.enable_smearer)
1231            self.disable_smearer.SetValue(state.disable_smearer)
[ef26c83]1232            self.onSmear(event=None)
[e88ebfd]1233        self.pinhole_smearer.SetValue(state.pinhole_smearer)
1234        self.slit_smearer.SetValue(state.slit_smearer)
[55bb249c]1235       
1236        self.dI_noweight.SetValue(state.dI_noweight)
1237        self.dI_didata.SetValue(state.dI_didata)
1238        self.dI_sqrdata.SetValue(state.dI_sqrdata)
1239        self.dI_idata.SetValue(state.dI_idata)
1240       
[e88ebfd]1241        ## we have two more options for smearing
[ef26c83]1242        if self.pinhole_smearer.GetValue():
1243            self.onPinholeSmear(event=None)
1244        elif self.slit_smearer.GetValue():
1245            self.onSlitSmear(event=None)
[e88ebfd]1246       
1247        ## reset state of checkbox,textcrtl  and dispersity parameters value
[ef26c83]1248        self._reset_parameters_state(self.fittable_param, state.fittable_param)
1249        self._reset_parameters_state(self.fixed_param, state.fixed_param)
[e88ebfd]1250       
1251        ## draw the model with previous parameters value
1252        self._onparamEnter_helper()
[ef26c83]1253        self.select_param(event=None)
[e88ebfd]1254        #Save state_fit
1255        self.save_current_state_fit()
1256        self._lay_out()
1257        self.Refresh()
1258       
[240b9966]1259    def reset_page_helper(self, state):
[cfc0913]1260        """
[5062bbf]1261        Use page_state and change the state of existing page
1262       
1263        :precondition: the page is already drawn or created
1264       
1265        :postcondition: the state of the underlying data change as well as the
[71f0373]1266            state of the graphic interface
[cfc0913]1267        """
[4a7ad5f]1268        if state == None:
[ef26c83]1269            return
[2296316]1270        # set data, etc. from the state
[2657df9]1271        # reset page between theory and fitting from bookmarking
1272        #if state.data == None:
1273        #    data = None
1274        #else:
1275        data = state.data
1276
1277        if data == None:
1278            data_min = state.qmin
1279            data_max = state.qmax
1280            self.qmin_x = data_min
1281            self.qmax_x = data_max
1282            self.qmin.SetValue(str(data_min))
1283            self.qmax.SetValue(str(data_max))
1284
1285            self.state.data = data
1286            self.state.qmin = self.qmin_x
1287            self.state.qmax = self.qmax_x
1288        else:
1289            self.set_data(data)
1290           
[ef26c83]1291        self.enable2D = state.enable2D
[318b5bbb]1292        try:
1293            self.magnetic_on = state.magnetic_on
1294        except:
1295            # Backward compatibility (for older state files)
1296            self.magnetic_on = False
[0b12abb5]1297        self.engine_type = state.engine_type
1298
1299        self.disp_cb_dict = state.disp_cb_dict
1300        self.disp_list = state.disp_list
[e3d1423]1301     
[ea5fa58]1302        ## set the state of the radio box
1303        #self.shape_rbutton.SetValue(state.shape_rbutton)
1304        #self.shape_indep_rbutton.SetValue(state.shape_indep_rbutton)
1305        #self.struct_rbutton.SetValue(state.struct_rbutton)
1306        #self.plugin_rbutton.SetValue(state.plugin_rbutton)
[0b12abb5]1307       
1308        ## fill model combobox
1309        self._show_combox_helper()
1310        #select the current model
[ea5fa58]1311        try:
1312            # to support older version
1313            category_pos = int(state.categorycombobox)
1314        except:
1315            category_pos = 0
1316            for ind_cat in range(self.categorybox.GetCount()):
1317                if self.categorybox.GetString(ind_cat) == \
1318                                        state.categorycombobox:
1319                    category_pos = int(ind_cat)
1320                    break
1321           
1322        self.categorybox.Select(category_pos)
1323        self._show_combox(None)
1324        try:
1325            # to support older version
1326            formfactor_pos = int(state.formfactorcombobox)
1327        except:
1328            formfactor_pos = 0
1329            for ind_form in range(self.formfactorbox.GetCount()):
1330                if self.formfactorbox.GetString(ind_form) == \
1331                                                    (state.formfactorcombobox):
1332                    formfactor_pos = int(ind_form)
1333                    break
1334           
1335        self.formfactorbox.Select(formfactor_pos)
1336       
[d40038e]1337        try:
1338            # to support older version
1339            structfactor_pos = int(state.structurecombobox)
1340        except:
1341            structfactor_pos = 0
1342            for ind_struct in range(self.structurebox.GetCount()):
[be1ec9f]1343                if self.structurebox.GetString(ind_struct) == \
1344                                                    (state.structurecombobox):
[d40038e]1345                    structfactor_pos = int(ind_struct)
1346                    break
1347           
1348        self.structurebox.SetSelection(structfactor_pos)
1349
[4523b68]1350        if state.multi_factor != None:
[cf6a192]1351            self.multifactorbox.SetSelection(state.multi_factor)
[4523b68]1352
[0b12abb5]1353        #reset the fitting engine type
1354        self.engine_type = state.engine_type
[ef26c83]1355        #draw the pnael according to the new model parameter
[0b12abb5]1356        self._on_select_model(event=None)
[93f0a862]1357           
[2657df9]1358        # take care of 2D button
1359        if data == None and self.model_view.IsEnabled():
1360            if self.enable2D:
[6371c9c]1361                self.model_view.SetLabel("2D Mode")
[2657df9]1362            else:
[6371c9c]1363                self.model_view.SetLabel("1D Mode")
[2657df9]1364        # else:
1365               
[ef26c83]1366        if self._manager != None and self.engine_type != None:
[3cd5806]1367            self._manager._on_change_engine(engine=self.engine_type)
[0b12abb5]1368        ## set the select all check box to the a given state
1369        self.cb1.SetValue(state.cb1)
1370     
1371        ## reset state of checkbox,textcrtl  and  regular parameters value
1372        self._reset_parameters_state(self.orientation_params_disp,
1373                                     state.orientation_params_disp)
1374        self._reset_parameters_state(self.orientation_params,
1375                                     state.orientation_params)
[fb59ed9]1376        self._reset_parameters_state(self.str_parameters,
1377                                     state.str_parameters)
[ef26c83]1378        self._reset_parameters_state(self.parameters, state.parameters)
1379        ## display dispersion info layer
[0b12abb5]1380        self.enable_disp.SetValue(state.enable_disp)
1381        self.disable_disp.SetValue(state.disable_disp)
[2296316]1382        # If the polydispersion is ON
1383        if state.enable_disp:
1384            # reset dispersion according the state
[0b12abb5]1385            self._set_dipers_Param(event=None)
[2296316]1386            self._reset_page_disp_helper(state)
[ef26c83]1387        ##plotting range restore
[0b12abb5]1388        self._reset_plotting_range(state)
1389        ## smearing info  restore
1390        if hasattr(self, "enable_smearer"):
[ef26c83]1391            ## set smearing value whether or not the data
[4a7ad5f]1392            #contain the smearing info
[0b12abb5]1393            self.enable_smearer.SetValue(state.enable_smearer)
1394            self.disable_smearer.SetValue(state.disable_smearer)
[ef26c83]1395            self.onSmear(event=None)
[0b12abb5]1396        self.pinhole_smearer.SetValue(state.pinhole_smearer)
1397        self.slit_smearer.SetValue(state.slit_smearer)
[ea8283d]1398        try:
1399            self.dI_noweight.SetValue(state.dI_noweight)
1400            self.dI_didata.SetValue(state.dI_didata)
1401            self.dI_sqrdata.SetValue(state.dI_sqrdata)
1402            self.dI_idata.SetValue(state.dI_idata)
1403        except:
1404            # to support older state file formats
1405            self.dI_noweight.SetValue(False)
1406            self.dI_didata.SetValue(True)
1407            self.dI_sqrdata.SetValue(False)
1408            self.dI_idata.SetValue(False)
1409 
[0b12abb5]1410        ## we have two more options for smearing
[ef26c83]1411        if self.pinhole_smearer.GetValue():
[db8fd5b]1412            self.dx_min = state.dx_min
1413            self.dx_max = state.dx_max
1414            if self.dx_min != None:
1415                self.smear_pinhole_min.SetValue(str(self.dx_min))
1416            if self.dx_max != None:
1417                self.smear_pinhole_max.SetValue(str(self.dx_max))
[ef26c83]1418            self.onPinholeSmear(event=None)
1419        elif self.slit_smearer.GetValue():
[db8fd5b]1420            self.dxl = state.dxl
1421            self.dxw = state.dxw
1422            if self.dxl != None:
1423                self.smear_slit_height.SetValue(str(self.dxl))
1424            if self.dxw != None:
[0d795bf]1425                self.smear_slit_width.SetValue(str(self.dxw)) 
1426            else:
1427                self.smear_slit_width.SetValue('') 
[ef26c83]1428            self.onSlitSmear(event=None)
[55bb249c]1429       
[0b12abb5]1430        ## reset state of checkbox,textcrtl  and dispersity parameters value
[ef26c83]1431        self._reset_parameters_state(self.fittable_param, state.fittable_param)
1432        self._reset_parameters_state(self.fixed_param, state.fixed_param)
[0b12abb5]1433       
1434        ## draw the model with previous parameters value
1435        self._onparamEnter_helper()
[3c44c66]1436        #reset the value of chisqr when not consistent with the value computed
1437        self.tcChi.SetValue(str(self.state.tcChi))
[0b12abb5]1438        ## reset context menu items
1439        self._reset_context_menu()
[3c44c66]1440       
[0b12abb5]1441        ## set the value of the current state to the state given as parameter
[ef26c83]1442        self.state = state.clone()
[93f0a862]1443        self.state.m_name = self.m_name
[0b12abb5]1444   
[2296316]1445    def _reset_page_disp_helper(self, state):
1446        """
1447        Help to rest page for dispersions
1448        """
1449        keys = self.model.getParamList()
1450        for item in keys:
1451            if item in self.disp_list and \
[ef26c83]1452                not item in self.model.details:
[2296316]1453                self.model.details[item] = ["", None, None]
1454        #for k,v in self.state.disp_cb_dict.iteritems():
[ef26c83]1455        self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
[2296316]1456        self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
1457        self.values = copy.deepcopy(state.values)
1458        self.weights = copy.deepcopy(state.weights)
1459       
1460        for key, disp in state._disp_obj_dict.iteritems():
1461            # From saved file, disp_model can not be sent in model obj.
1462            # it will be sent as a string here, then converted to model object.
1463            if disp.__class__.__name__ == 'str':
[480fe4f]1464                disp_model = None
[79492222]1465                com_str = "from sas.models.dispersion_models "
[480fe4f]1466                com_str += "import %s as disp_func \ndisp_model = disp_func()"
[2296316]1467                exec com_str % disp
[f20767b]1468            else:
[2296316]1469                disp_model = disp
[ef26c83]1470            self._disp_obj_dict[key] = disp_model
[2296316]1471            param_name = key.split('.')[0]
1472            # Try to set dispersion only when available
[ef26c83]1473            # for eg., pass the orient. angles for 1D Cal
[2296316]1474            try:
1475                self.model.set_dispersion(param_name, disp_model)
1476                self.model._persistency_dict[key] = \
1477                                 [state.values, state.weights]
1478            except:
1479                pass
1480            selection = self._find_polyfunc_selection(disp_model)
1481            for list in self.fittable_param:
1482                if list[1] == key and list[7] != None:
1483                    list[7].SetSelection(selection)
[ef26c83]1484                    # For the array disp_model, set the values and weights
[2296316]1485                    if selection == 1:
[ef26c83]1486                        disp_model.set_weights(self.values[key],
1487                                               self.weights[key])
[2296316]1488                        try:
1489                            # Diables all fittable params for array
1490                            list[0].SetValue(False)
1491                            list[0].Disable()
1492                            list[2].Disable()
1493                            list[5].Disable()
1494                            list[6].Disable()
1495                        except:
1496                            pass
1497            # For array, disable all fixed params
1498            if selection == 1:
1499                for item in self.fixed_param:
1500                    if item[1].split(".")[0] == key.split(".")[0]:
1501                        # try it and pass it for the orientation for 1D
1502                        try:
1503                            item[2].Disable()
1504                        except:
1505                            pass
[5582a9f1]1506   
[2296316]1507        # Make sure the check box updated when all checked
1508        if self.cb1.GetValue():
[ef26c83]1509            self.select_all_param(None)
[2296316]1510     
[c77d859]1511    def _selectDlg(self):
1512        """
[5062bbf]1513        open a dialog file to selected the customized dispersity
[c77d859]1514        """
[ef26c83]1515        if self.parent != None:
[baf1ef3]1516            self._default_save_location = \
[ae84427]1517                        self._manager.parent.get_save_location()
[60132ef]1518        dlg = wx.FileDialog(self, "Choose a weight file",
[ef26c83]1519                                self._default_save_location, "",
[4a7ad5f]1520                                "*.*", wx.OPEN)
[c77d859]1521        path = None
1522        if dlg.ShowModal() == wx.ID_OK:
1523            path = dlg.GetPath()
1524        dlg.Destroy()
1525        return path
[5062bbf]1526
[a074145]1527    def _reset_context_menu(self):
1528        """
[5062bbf]1529        reset the context menu
[a074145]1530        """
[be1ec9f]1531        for name, _ in self.state.saved_states.iteritems():
[a074145]1532            self.number_saved_state += 1
1533            ## Add item in the context menu
1534            id = wx.NewId()
[4a7ad5f]1535            msg = 'Save model and state %g' % self.number_saved_state
1536            self.popUpMenu.Append(id, name, msg)
[a074145]1537            wx.EVT_MENU(self, id, self.onResetModel)
1538   
[0aeabc6]1539    def _reset_plotting_range(self, state):
[cfc0913]1540        """
[5062bbf]1541        Reset the plotting range to a given state
[cfc0913]1542        """
[f95301b]1543        self.qmin.SetValue(str(state.qmin))
[ef26c83]1544        self.qmax.SetValue(str(state.qmax))
[0b12abb5]1545
[240b9966]1546    def _save_typeOfmodel(self):
1547        """
[5062bbf]1548        save radiobutton containing the type model that can be selected
[240b9966]1549        """
[ea5fa58]1550        #self.state.shape_rbutton = self.shape_rbutton.GetValue()
1551        #self.state.shape_indep_rbutton = self.shape_indep_rbutton.GetValue()
1552        #self.state.struct_rbutton = self.struct_rbutton.GetValue()
1553        #self.state.plugin_rbutton = self.plugin_rbutton.GetValue()
[940aca7]1554        self.state.structurecombobox = self.structurebox.GetLabel()
[ea5fa58]1555        self.state.formfactorcombobox = self.formfactorbox.GetLabel()
1556        self.state.categorycombobox = self.categorybox.GetLabel()
[c99a6c5]1557       
[240b9966]1558        ## post state to fit panel
[ef26c83]1559        event = PageInfoEvent(page=self)
[240b9966]1560        wx.PostEvent(self.parent, event)
[3595309d]1561       
[ef26c83]1562    def _save_plotting_range(self):
[cfc0913]1563        """
[ef26c83]1564        save the state of plotting range
[cfc0913]1565        """
[b787e68c]1566        self.state.qmin = self.qmin_x
[ef26c83]1567        self.state.qmax = self.qmax_x
[6bbeacd4]1568        self.state.npts = self.npts_x
[cfc0913]1569           
[c77d859]1570    def _onparamEnter_helper(self):
1571        """
[ef26c83]1572        check if values entered by the user are changed and valid to replot
[5062bbf]1573        model
[c77d859]1574        """
[ef26c83]1575        # Flag to register when a parameter has changed.
[7975f2b]1576        is_modified = False
[4a7ad5f]1577        self.fitrange = True
[51a71a3]1578        is_2Ddata = False
[3a37fe0]1579        #self._undo.Enable(True)
[51a71a3]1580        # check if 2d data
[4a7ad5f]1581        if self.data.__class__.__name__ == "Data2D":
[51a71a3]1582            is_2Ddata = True
[ef26c83]1583        if self.model != None:
[edd166b]1584            try:
[4a7ad5f]1585                is_modified = self._check_value_enter(self.fittable_param,
1586                                                     is_modified)
1587                is_modified = self._check_value_enter(self.fixed_param,
1588                                                      is_modified)
1589                is_modified = self._check_value_enter(self.parameters,
[ef26c83]1590                                                      is_modified)
[edd166b]1591            except:
1592                pass
[c99a6c5]1593
[c77d859]1594            # Here we should check whether the boundaries have been modified.
[ef26c83]1595            # If qmin and qmax have been modified, update qmin and qmax and
[c77d859]1596            # set the is_modified flag to True
[f95301b]1597            if self._validate_qrange(self.qmin, self.qmax):
1598                tempmin = float(self.qmin.GetValue())
[7975f2b]1599                if tempmin != self.qmin_x:
1600                    self.qmin_x = tempmin
[c77d859]1601                    is_modified = True
[7975f2b]1602                tempmax = float(self.qmax.GetValue())
1603                if tempmax != self.qmax_x:
1604                    self.qmax_x = tempmax
[c77d859]1605                    is_modified = True
[b787e68c]1606           
[51a71a3]1607                if is_2Ddata:
[ef26c83]1608                    # set mask
[51a71a3]1609                    is_modified = self._validate_Npts()
[247cb58]1610                   
[51a71a3]1611            else:
[ef26c83]1612                self.fitrange = False
[d2c4c06]1613               
1614            if not self.data.is_data:
1615                is_modified = True
1616
[c77d859]1617            ## if any value is modify draw model with new value
[51a71a3]1618            if not self.fitrange:
[247cb58]1619                #self.btFit.Disable()
[ef26c83]1620                if is_2Ddata:
1621                    self.btEditMask.Disable()
[51a71a3]1622            else:
[ef26c83]1623                if is_2Ddata and self.data.is_data and not self.batch_on:
[054f004]1624                    self.btEditMask.Enable(True)
[51a71a3]1625            if is_modified and self.fitrange:
[ecf26e1]1626                # Theory case: need to get npts value to draw
1627                self.npts_x = float(self.Npts_total.GetValue())
1628                self.create_default_data()
[ef26c83]1629                self.state_change = True
1630                self._draw_model()
[7975f2b]1631                self.Refresh()
1632        return is_modified
1633   
[35c9d31]1634    def _update_paramv_on_fit(self):
1635        """
[5062bbf]1636        make sure that update param values just before the fitting
[35c9d31]1637        """
1638        #flag for qmin qmax check values
[7609f1a]1639        flag = True
[51a71a3]1640        self.fitrange = True
[35c9d31]1641        is_modified = False
[51a71a3]1642
[66ff250]1643        #wx.PostEvent(self._manager.parent, StatusEvent(status=" \
1644        #updating ... ",type="update"))
[4fbc93e]1645
[35c9d31]1646        ##So make sure that update param values on_Fit.
1647        #self._undo.Enable(True)
[ef26c83]1648        if self.model != None:
[33477fd]1649            if self.Npts_total.GetValue() != self.Npts_fit.GetValue():
1650                if not self.data.is_data:
1651                    self._manager.page_finder[self.uid].set_fit_data(data=\
[ef26c83]1652                                                                [self.data])
[35c9d31]1653            ##Check the values
[ef26c83]1654            self._check_value_enter(self.fittable_param, is_modified)
1655            self._check_value_enter(self.fixed_param, is_modified)
1656            self._check_value_enter(self.parameters, is_modified)
[35c9d31]1657
1658            # If qmin and qmax have been modified, update qmin and qmax and
[ef26c83]1659            # Here we should check whether the boundaries have been modified.
[7975f2b]1660            # If qmin and qmax have been modified, update qmin and qmax and
1661            # set the is_modified flag to True
[f95301b]1662            self.fitrange = self._validate_qrange(self.qmin, self.qmax)
[51a71a3]1663            if self.fitrange:
[f95301b]1664                tempmin = float(self.qmin.GetValue())
[7975f2b]1665                if tempmin != self.qmin_x:
1666                    self.qmin_x = tempmin
1667                tempmax = float(self.qmax.GetValue())
1668                if tempmax != self.qmax_x:
1669                    self.qmax_x = tempmax
[7609f1a]1670                if tempmax == tempmin:
[ef26c83]1671                    flag = False
[7609f1a]1672                temp_smearer = None
1673                if not self.disable_smearer.GetValue():
[ef26c83]1674                    temp_smearer = self.current_smearer
[7609f1a]1675                    if self.slit_smearer.GetValue():
1676                        flag = self.update_slit_smear()
1677                    elif self.pinhole_smearer.GetValue():
1678                        flag = self.update_pinhole_smear()
1679                    else:
[6bbeacd4]1680                        self._manager.set_smearer(smearer=temp_smearer,
[66ff250]1681                                                  uid=self.uid,
[ecf26e1]1682                                                  fid=self.data.id,
[ef26c83]1683                                                  qmin=float(self.qmin_x),
1684                                                  qmax=float(self.qmax_x),
[ecf26e1]1685                            enable_smearer=not self.disable_smearer.GetValue(),
[6bbeacd4]1686                                                      draw=False)
[4fbc93e]1687                elif not self._is_2D():
[3cd5806]1688                    self._manager.set_smearer(smearer=temp_smearer,
[4a7ad5f]1689                                              qmin=float(self.qmin_x),
[ef26c83]1690                                              uid=self.uid,
[ecf26e1]1691                                              fid=self.data.id,
[ef26c83]1692                                              qmax=float(self.qmax_x),
[ecf26e1]1693                            enable_smearer=not self.disable_smearer.GetValue(),
[18e430a]1694                                                 draw=False)
[0cf97c5]1695                    if self.data != None:
[ef26c83]1696                        index_data = ((self.qmin_x <= self.data.x) & \
[0cf97c5]1697                                      (self.data.x <= self.qmax_x))
[ef26c83]1698                        val = str(len(self.data.x[index_data == True]))
[0cf97c5]1699                        self.Npts_fit.SetValue(val)
1700                    else:
1701                        # No data in the panel
1702                        try:
1703                            self.npts_x = float(self.Npts_total.GetValue())
1704                        except:
1705                            flag = False
1706                            return flag
[51a71a3]1707                    flag = True
[4fbc93e]1708                if self._is_2D():
[ef26c83]1709                    # only 2D case set mask
[51a71a3]1710                    flag = self._validate_Npts()
1711                    if not flag:
1712                        return flag
[ef26c83]1713            else:
1714                flag = False
1715        else:
[7975f2b]1716            flag = False
[51a71a3]1717
[ef26c83]1718        #For invalid q range, disable the mask editor and fit button, vs.
[51a71a3]1719        if not self.fitrange:
[55a3257]1720            if self._is_2D():
1721                self.btEditMask.Disable()
[51a71a3]1722        else:
[33477fd]1723            if self._is_2D() and  self.data.is_data and not self.batch_on:
[55a3257]1724                self.btEditMask.Enable(True)
[51a71a3]1725
[7609f1a]1726        if not flag:
[4a7ad5f]1727            msg = "Cannot Plot or Fit :Must select a "
1728            msg += " model or Fitting range is not valid!!!  "
[ae84427]1729            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[51a71a3]1730       
[33477fd]1731        try:
1732            self.save_current_state()
1733        except:
1734            pass
[4470b10]1735   
[ef26c83]1736        return flag
[acd0bda3]1737               
[c99a6c5]1738    def _is_modified(self, is_modified):
[acd0bda3]1739        """
[5062bbf]1740        return to self._is_modified
[acd0bda3]1741        """
[c99a6c5]1742        return is_modified
[acd0bda3]1743                       
[4a7ad5f]1744    def _reset_parameters_state(self, listtorestore, statelist):
[cfc0913]1745        """
[5062bbf]1746        Reset the parameters at the given state
[cfc0913]1747        """
[4a7ad5f]1748        if len(statelist) == 0 or len(listtorestore) == 0:
[6999659]1749            return
[ef26c83]1750        if len(statelist) != len(listtorestore):
[cfc0913]1751            return
[c99a6c5]1752
[cfc0913]1753        for j in range(len(listtorestore)):
1754            item_page = listtorestore[j]
1755            item_page_info = statelist[j]
1756            ##change the state of the check box for simple parameters
[ef26c83]1757            if item_page[0] != None:
[cfc0913]1758                item_page[0].SetValue(item_page_info[0])
[ef26c83]1759            if item_page[2] != None:
[cfc0913]1760                item_page[2].SetValue(item_page_info[2])
[2296316]1761                if item_page[2].__class__.__name__ == "ComboBox":
[ef26c83]1762                    if item_page_info[2] in self.model.fun_list:
1763                        fun_val = self.model.fun_list[item_page_info[2]]
1764                        self.model.setParam(item_page_info[1], fun_val)
1765            if item_page[3] != None:
[cfc0913]1766                ## show or hide text +/-
1767                if item_page_info[2]:
1768                    item_page[3].Show(True)
1769                else:
1770                    item_page[3].Hide()
[ef26c83]1771            if item_page[4] != None:
[cfc0913]1772                ## show of hide the text crtl for fitting error
1773                if item_page_info[4][0]:
1774                    item_page[4].Show(True)
1775                    item_page[4].SetValue(item_page_info[4][1])
1776                else:
1777                    item_page[3].Hide()
[ef26c83]1778            if item_page[5] != None:
[cfc0913]1779                ## show of hide the text crtl for fitting error
[2296316]1780                item_page[5].Show(item_page_info[5][0])
1781                item_page[5].SetValue(item_page_info[5][1])
1782               
[ef26c83]1783            if item_page[6] != None:
[cfc0913]1784                ## show of hide the text crtl for fitting error
[2296316]1785                item_page[6].Show(item_page_info[6][0])
1786                item_page[6].SetValue(item_page_info[6][1])
1787                   
1788    def _reset_strparam_state(self, listtorestore, statelist):
1789        """
1790        Reset the string parameters at the given state
1791        """
1792        if len(statelist) == 0:
1793            return
1794
1795        listtorestore = copy.deepcopy(statelist)
1796       
1797        for j in range(len(listtorestore)):
1798            item_page = listtorestore[j]
1799            item_page_info = statelist[j]
1800            ##change the state of the check box for simple parameters
1801           
[ef26c83]1802            if item_page[0] != None:
[2296316]1803                item_page[0].SetValue(format_number(item_page_info[0], True))
1804
1805            if item_page[2] != None:
1806                param_name = item_page_info[1]
1807                value = item_page_info[2]
1808                selection = value
[ef26c83]1809                if value in self.model.fun_list:
[2296316]1810                    selection = self.model.fun_list[value]
1811                item_page[2].SetValue(selection)
1812                self.model.setParam(param_name, selection)
[5062bbf]1813                                     
[cfc0913]1814    def _copy_parameters_state(self, listtocopy, statelist):
1815        """
[ef26c83]1816        copy the state of button
[5062bbf]1817       
1818        :param listtocopy: the list of check button to copy
1819        :param statelist: list of state object to store the current state
1820       
[cfc0913]1821        """
[ef26c83]1822        if len(listtocopy) == 0:
[cfc0913]1823            return
[1c1436d]1824       
[cfc0913]1825        for item in listtocopy:
[f20767b]1826 
[cfc0913]1827            checkbox_state = None
[ef26c83]1828            if item[0] != None:
1829                checkbox_state = item[0].GetValue()
[cfc0913]1830            parameter_name = item[1]
1831            parameter_value = None
[ef26c83]1832            if item[2] != None:
[cfc0913]1833                parameter_value = item[2].GetValue()
1834            static_text = None
[ef26c83]1835            if item[3] != None:
[cfc0913]1836                static_text = item[3].IsShown()
1837            error_value = None
1838            error_state = None
[ef26c83]1839            if item[4] != None:
[cfc0913]1840                error_value = item[4].GetValue()
1841                error_state = item[4].IsShown()
1842               
1843            min_value = None
1844            min_state = None
[ef26c83]1845            if item[5] != None:
[cfc0913]1846                min_value = item[5].GetValue()
1847                min_state = item[5].IsShown()
1848               
1849            max_value = None
1850            max_state = None
[ef26c83]1851            if item[6] != None:
[cfc0913]1852                max_value = item[6].GetValue()
1853                max_state = item[6].IsShown()
[ef26c83]1854            unit = None
1855            if item[7] != None:
[240b9966]1856                unit = item[7].GetLabel()
[cfc0913]1857               
1858            statelist.append([checkbox_state, parameter_name, parameter_value,
[ef26c83]1859                              static_text, [error_state, error_value],
1860                              [min_state, min_value],
1861                              [max_state, max_value], unit])
[cfc0913]1862           
[116e1a7]1863#    The following funcion seems to be superseded with fillsizer and
1864#    init combo box.  certainly it seems not to know about categories and uses
1865#    only shapes and shape independent -- tested after commenting out and does
1866#    not seem to cause problem.  Leave commented out for now but delete in
1867#    a code cleanup once clear it really is no longer used.
1868#    PDB  8 April 2014
1869
1870#    def _set_model_sizer_selection(self, model):
1871#        """
1872#        Display the sizer according to the type of the current model
1873#        """
1874#        if model == None:
1875#            return
1876#        if hasattr(model, "s_model"):
1877#           
1878#            class_name = model.s_model.__class__
1879#            name = model.s_model.name
1880#            flag = (name != "NoStructure")
1881#            if flag and \
1882#                (class_name in self.model_list_box["Structure Factors"]):
1883#                self.structurebox.Show()
1884#                self.text2.Show()
1885#                self.structurebox.Enable()
1886#               self.text2.Enable()
1887 #               items = self.structurebox.GetItems()
1888 #               self.sizer1.Layout()
1889 #               
1890 #               for i in range(len(items)):
1891 #                   if items[i] == str(name):
1892 #                       self.structurebox.SetSelection(i)
1893 #                       break
1894 #                   
1895 #       if hasattr(model, "p_model"):
1896 #           class_name = model.p_model.__class__
1897 #           name = model.p_model.name
1898 #           self.formfactorbox.Clear()
1899 #           
1900 #           for k, list in self.model_list_box.iteritems():
1901 #               if k in["P(Q)*S(Q)", "Shapes"] and \
1902 #                   class_name in self.model_list_box["Shapes"]:
1903 #                   self.shape_rbutton.SetValue(True)
1904 #                   ## fill the form factor list with new model
1905 #                   self._populate_box(self.formfactorbox,
1906 #                                      self.model_list_box["Shapes"])
1907 #                   items = self.formfactorbox.GetItems()
1908 #                   ## set comboxbox to the selected item
1909 #                   for i in range(len(items)):
1910 #                       if items[i] == str(name):
1911 #                           self.formfactorbox.SetSelection(i)
1912 #                           break
1913 #                   return
1914 #               elif k == "Shape-Independent":
1915 #                   self.shape_indep_rbutton.SetValue(True)
1916 #               elif k == "Structure Factors":
1917 #                   self.struct_rbutton.SetValue(True)
1918 #               elif k == "Multi-Functions":
1919 #                   continue
1920 #               else:
1921 #                   self.plugin_rbutton.SetValue(True)
1922 #             
1923 #               if class_name in list:
1924 #                   ## fill the form factor list with new model
1925 #                   self._populate_box(self.formfactorbox, list)
1926 #                   items = self.formfactorbox.GetItems()
1927 #                   ## set comboxbox to the selected item
1928 #                   for i in range(len(items)):
1929 #                       if items[i] == str(name):
1930 #                           self.formfactorbox.SetSelection(i)
1931 #                           break
1932 #                   break
1933 #       else:
[cdbe88e]1934            ## Select the model from the menu
[116e1a7]1935#            class_name = model.__class__
1936#            name = model.name
1937#            self.formfactorbox.Clear()
1938#            items = self.formfactorbox.GetItems()
1939#   
1940#            for k, list in self.model_list_box.iteritems():
1941#                if k in["P(Q)*S(Q)", "Shapes"] and \
1942#                    class_name in self.model_list_box["Shapes"]:
1943#                    if class_name in self.model_list_box["P(Q)*S(Q)"]:
1944#                        self.structurebox.Show()
1945#                        self.text2.Show()
1946#                       self.structurebox.Enable()
1947#                       self.structurebox.SetSelection(0)
1948#                       self.text2.Enable()
1949#                   else:
1950#                        self.structurebox.Hide()
1951#                        self.text2.Hide()
1952#                        self.structurebox.Disable()
1953#                        self.structurebox.SetSelection(0)
1954#                        self.text2.Disable()
1955#                       
1956#                    self.shape_rbutton.SetValue(True)
[376916c]1957                    ## fill the form factor list with new model
[116e1a7]1958#                    self._populate_box(self.formfactorbox,
1959#                                       self.model_list_box["Shapes"])
1960#                    items = self.formfactorbox.GetItems()
1961#                    ## set comboxbox to the selected item
1962#                    for i in range(len(items)):
1963#                        if items[i] == str(name):
1964#                            self.formfactorbox.SetSelection(i)
1965#                            break
1966#                    return
1967#                elif k == "Shape-Independent":
1968#                    self.shape_indep_rbutton.SetValue(True)
1969#                elif k == "Structure Factors":
1970#                    self.struct_rbutton.SetValue(True)
1971#                elif k == "Multi-Functions":
1972#                    continue
1973#                else:
1974#                    self.plugin_rbutton.SetValue(True)
1975#                if class_name in list:
1976#                    self.structurebox.SetSelection(0)
1977#                    self.structurebox.Disable()
1978#                    self.text2.Disable()
[376916c]1979                    ## fill the form factor list with new model
[116e1a7]1980#                    self._populate_box(self.formfactorbox, list)
1981#                    items = self.formfactorbox.GetItems()
[c77d859]1982                    ## set comboxbox to the selected item
[116e1a7]1983#                    for i in range(len(items)):
1984#                        if items[i] == str(name):
1985#                            self.formfactorbox.SetSelection(i)
1986#                            break
1987#                    break
[7fd4afd]1988               
[e3f6ef5]1989    def _draw_model(self, update_chisqr=True, source='model'):
[c77d859]1990        """
[5062bbf]1991        Method to draw or refresh a plotted model.
1992        The method will use the data member from the model page
1993        to build a call to the fitting perspective manager.
[2296316]1994       
1995        :param chisqr: update chisqr value [bool]
[c77d859]1996        """
[7fd4afd]1997        wx.CallAfter(self._draw_model_after, update_chisqr, source)
1998       
1999    def _draw_model_after(self, update_chisqr=True, source='model'):
2000        """
2001        Method to draw or refresh a plotted model.
2002        The method will use the data member from the model page
2003        to build a call to the fitting perspective manager.
2004       
2005        :param chisqr: update chisqr value [bool]
2006        """
[6bbeacd4]2007        #if self.check_invalid_panel():
2008        #    return
[ef26c83]2009        if self.model != None:
2010            temp_smear = None
[fca9cbd9]2011            if hasattr(self, "enable_smearer"):
[7609f1a]2012                if not self.disable_smearer.GetValue():
[ef26c83]2013                    temp_smear = self.current_smearer
[f7ef313]2014            # compute weight for the current data
[b9a5f0e]2015            from sas.perspectives.fitting.utils import get_weight
[f7ef313]2016            flag = self.get_weight_flag()
2017            weight = get_weight(data=self.data, is2d=self._is_2D(), flag=flag)
[fa65e99]2018            toggle_mode_on = self.model_view.IsEnabled()
[01642fec]2019            is_2d = self._is_2D()
[ef26c83]2020            self._manager.draw_model(self.model,
[f72333f]2021                                    data=self.data,
[ef26c83]2022                                    smearer=temp_smear,
2023                                    qmin=float(self.qmin_x),
[484faf7]2024                                    qmax=float(self.qmax_x),
[66ff250]2025                                    page_id=self.uid,
[ef26c83]2026                                    toggle_mode_on=toggle_mode_on,
2027                                    state=self.state,
[01642fec]2028                                    enable2D=is_2d,
[55bb249c]2029                                    update_chisqr=update_chisqr,
[e3f6ef5]2030                                    source='model',
[55bb249c]2031                                    weight=weight)
[0b477f6]2032       
[a1b2471]2033    def _on_show_sld(self, event=None):
2034        """
2035        Plot SLD profile
2036        """
2037        # get profile data
[ef26c83]2038        x, y = self.model.getProfile()
[a1b2471]2039
[79492222]2040        from sas.plottools import Data1D as pf_data1d
2041        #from sas.perspectives.theory.profile_dialog import SLDPanel
2042        from sas.guiframe.local_perspectives.plotting.profile_dialog \
[da9ac4e6]2043        import SLDPanel
[be1ec9f]2044        sld_data = pf_data1d(x, y)
[a1b2471]2045        sld_data.name = 'SLD'
[fb59ed9]2046        sld_data.axes = self.sld_axes
[ef26c83]2047        self.panel = SLDPanel(self, data=sld_data, axes=self.sld_axes, id=-1)
2048        self.panel.ShowModal()
[a1b2471]2049       
[ef26c83]2050    def _set_multfactor_combobox(self, multiplicity=10):
[4523b68]2051        """
2052        Set comboBox for muitfactor of CoreMultiShellModel
[fb59ed9]2053        :param multiplicit: no. of multi-functionality
[4523b68]2054        """
[fb59ed9]2055        # build content of the combobox
[ef26c83]2056        for idx in range(0, multiplicity):
2057            self.multifactorbox.Append(str(idx), int(idx))
[4523b68]2058        self._hide_multfactor_combobox()
2059       
[ef26c83]2060    def _show_multfactor_combobox(self):
[4523b68]2061        """
2062        Show the comboBox of muitfactor of CoreMultiShellModel
[ef26c83]2063        """
[4523b68]2064        if not self.mutifactor_text.IsShown():
2065            self.mutifactor_text.Show(True)
[fb59ed9]2066            self.mutifactor_text1.Show(True)
[4523b68]2067        if not self.multifactorbox.IsShown():
[ef26c83]2068            self.multifactorbox.Show(True)
[4523b68]2069             
[ef26c83]2070    def _hide_multfactor_combobox(self):
[4523b68]2071        """
2072        Hide the comboBox of muitfactor of CoreMultiShellModel
[ef26c83]2073        """
[4523b68]2074        if self.mutifactor_text.IsShown():
2075            self.mutifactor_text.Hide()
[fb59ed9]2076            self.mutifactor_text1.Hide()
[4523b68]2077        if self.multifactorbox.IsShown():
[ef26c83]2078            self.multifactorbox.Hide()
[ea5fa58]2079   
2080    def formfactor_combo_init(self):
2081        """
2082        First time calls _show_combox_helper
2083        """
2084        self._show_combox(None)
2085               
[0b12abb5]2086    def _show_combox_helper(self):
[c77d859]2087        """
[0b12abb5]2088        Fill panel's combo box according to the type of model selected
[c77d859]2089        """
[ea5fa58]2090        custom_model = 'Customized Models'
2091        mod_cat = self.categorybox.GetStringSelection()
2092        self.structurebox.SetSelection(0)
2093        self.structurebox.Disable()
2094        self.formfactorbox.Clear()
2095        if mod_cat == None:
2096            return
2097        m_list = []
2098        try:
2099            if mod_cat == custom_model:
2100                for model in self.model_list_box[mod_cat]:
2101                    str_m = str(model).split(".")[0]
2102                    #self.model_box.Append(str_m)
2103                    m_list.append(self.model_dict[str_m])
2104            else:
[ae4c139]2105                cat_dic = self.master_category_dict[mod_cat]
2106                for (model, enabled) in cat_dic:
[ea5fa58]2107                    if enabled:
2108                        m_list.append(self.model_dict[model])
[ae4c139]2109                    #else:
2110                    #    msg = "This model is disabled by Category Manager."
2111                    #    wx.PostEvent(self.parent.parent,
2112                    #                 StatusEvent(status=msg, info="error"))
[ea5fa58]2113        except:
2114            msg = "%s\n" % (sys.exc_value)
[ae84427]2115            wx.PostEvent(self._manager.parent,
[ea5fa58]2116                         StatusEvent(status=msg, info="error"))
2117        self._populate_box(self.formfactorbox, m_list)
[ef67145]2118   
2119    def _on_modify_cat(self, event=None): 
2120        self._manager.parent.on_category_panel(event) 
[3595309d]2121       
[0b12abb5]2122    def _show_combox(self, event=None):
2123        """
2124        Show combox box associate with type of model selected
2125        """
[dbbdf11]2126        self.Show(False)
[0b12abb5]2127        self._show_combox_helper()
[77e23a2]2128        self._on_select_model(event=None)
[dbbdf11]2129        self.Show(True)
[3595309d]2130        self._save_typeOfmodel()
[3b605bb]2131        self.sizer4_4.Layout()
[9853ad0]2132        self.sizer4.Layout()
[3b605bb]2133        self.Layout()
2134        self.Refresh()
[340c2b3]2135 
[ea5fa58]2136    def _populate_box(self, combobox, list):
[c77d859]2137        """
[5062bbf]2138        fill combox box with dict item
2139       
2140        :param list: contains item to fill the combox
[c77d859]2141            item must model class
2142        """
[f74673c]2143        mlist = []
[ea5fa58]2144        for models in list:
[ef26c83]2145            model = models()
[c77d859]2146            name = model.__class__.__name__
[ef26c83]2147            if models.__name__ != "NoStructure":
[0a518e4c]2148                if hasattr(model, "name"):
2149                    name = model.name
[ef26c83]2150                mlist.append((name, models))
[f74673c]2151               
2152        # Sort the models
[8df5faa]2153        mlist_sorted = sorted(mlist)
[f74673c]2154        for item in mlist_sorted:
[ef26c83]2155            combobox.Append(item[0], item[1])
[c77d859]2156        return 0
[6bbeacd4]2157   
[6e9976b]2158    def _onQrangeEnter(self, event):
2159        """
[5062bbf]2160        Check validity of value enter in the Q range field
[6bbeacd4]2161       
2162        """
2163        tcrtl = event.GetEventObject()
2164        #Clear msg if previously shown.
2165        msg = ""
2166        wx.PostEvent(self.parent, StatusEvent(status=msg))
2167        # Flag to register when a parameter has changed.
[be1ec9f]2168        #is_modified = False
[6bbeacd4]2169        if tcrtl.GetValue().lstrip().rstrip() != "":
2170            try:
[be1ec9f]2171                float(tcrtl.GetValue())
[6bbeacd4]2172                tcrtl.SetBackgroundColour(wx.WHITE)
2173                # If qmin and qmax have been modified, update qmin and qmax
[f95301b]2174                if self._validate_qrange(self.qmin, self.qmax):
2175                    tempmin = float(self.qmin.GetValue())
[6bbeacd4]2176                    if tempmin != self.qmin_x:
2177                        self.qmin_x = tempmin
2178                    tempmax = float(self.qmax.GetValue())
2179                    if tempmax != self.qmax_x:
2180                        self.qmax_x = tempmax
2181                else:
2182                    tcrtl.SetBackgroundColour("pink")
[6fe5100]2183                    msg = "Model Error: wrong value entered: %s" % sys.exc_value
[6bbeacd4]2184                    wx.PostEvent(self.parent, StatusEvent(status=msg))
[ef26c83]2185                    return
[6bbeacd4]2186            except:
2187                tcrtl.SetBackgroundColour("pink")
[6fe5100]2188                msg = "Model Error: wrong value entered: %s" % sys.exc_value
[6bbeacd4]2189                wx.PostEvent(self.parent, StatusEvent(status=msg))
[ef26c83]2190                return
[6bbeacd4]2191            #Check if # of points for theory model are valid(>0).
2192            if self.npts != None:
2193                if check_float(self.npts):
2194                    temp_npts = float(self.npts.GetValue())
[ef26c83]2195                    if temp_npts != self.num_points:
[6bbeacd4]2196                        self.num_points = temp_npts
[be1ec9f]2197                        #is_modified = True
[6bbeacd4]2198                else:
[6fe5100]2199                    msg = "Cannot plot: No points in Q range!!!  "
[6bbeacd4]2200                    wx.PostEvent(self.parent, StatusEvent(status=msg))
2201        else:
[ef26c83]2202            tcrtl.SetBackgroundColour("pink")
[6fe5100]2203            msg = "Model Error: wrong value entered!!!"
[ef26c83]2204            wx.PostEvent(self.parent, StatusEvent(status=msg))
[6bbeacd4]2205        self.save_current_state()
2206        event = PageInfoEvent(page=self)
2207        wx.PostEvent(self.parent, event)
2208        self.state_change = False
2209        #Draw the model for a different range
[b582d6bc]2210        if not self.data.is_data:
2211            self.create_default_data()
[6bbeacd4]2212        self._draw_model()
2213                   
2214    def _theory_qrange_enter(self, event):
2215        """
2216        Check validity of value enter in the Q range field
[6e9976b]2217        """
2218       
[ef26c83]2219        tcrtl = event.GetEventObject()
[6e9976b]2220        #Clear msg if previously shown.
[ef26c83]2221        msg = ""
[ae84427]2222        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[6e9976b]2223        # Flag to register when a parameter has changed.
2224        is_modified = False
[ef26c83]2225        if tcrtl.GetValue().lstrip().rstrip() != "":
[6e9976b]2226            try:
2227                value = float(tcrtl.GetValue())
2228                tcrtl.SetBackgroundColour(wx.WHITE)
2229
2230                # If qmin and qmax have been modified, update qmin and qmax
[6bbeacd4]2231                if self._validate_qrange(self.theory_qmin, self.theory_qmax):
2232                    tempmin = float(self.theory_qmin.GetValue())
2233                    if tempmin != self.theory_qmin_x:
2234                        self.theory_qmin_x = tempmin
2235                    tempmax = float(self.theory_qmax.GetValue())
[6e9976b]2236                    if tempmax != self.qmax_x:
[6bbeacd4]2237                        self.theory_qmax_x = tempmax
[6e9976b]2238                else:
2239                    tcrtl.SetBackgroundColour("pink")
[6fe5100]2240                    msg = "Model Error: wrong value entered: %s" % sys.exc_value
[ef26c83]2241                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2242                    return
[6e9976b]2243            except:
2244                tcrtl.SetBackgroundColour("pink")
[6fe5100]2245                msg = "Model Error: wrong value entered: %s" % sys.exc_value
[ef26c83]2246                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2247                return
[6e9976b]2248            #Check if # of points for theory model are valid(>0).
[ef26c83]2249            if self.Npts_total.IsEditable():
[0cf97c5]2250                if check_float(self.Npts_total):
2251                    temp_npts = float(self.Npts_total.GetValue())
[ef26c83]2252                    if temp_npts != self.num_points:
[6e9976b]2253                        self.num_points = temp_npts
2254                        is_modified = True
2255                else:
[6fe5100]2256                    msg = "Cannot Plot: No points in Q range!!!  "
[ae84427]2257                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[6e9976b]2258        else:
[ef26c83]2259            tcrtl.SetBackgroundColour("pink")
[6fe5100]2260            msg = "Model Error: wrong value entered!!!"
[ae84427]2261            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[6e9976b]2262        self.save_current_state()
[ef26c83]2263        event = PageInfoEvent(page=self)
[6e9976b]2264        wx.PostEvent(self.parent, event)
[ef26c83]2265        self.state_change = False
[484faf7]2266        #Draw the model for a different range
[ecf26e1]2267        self.create_default_data()
[484faf7]2268        self._draw_model()
[6e9976b]2269                   
[ef26c83]2270    def _on_select_model_helper(self):
[c77d859]2271        """
[5062bbf]2272        call back for model selection
[c77d859]2273        """
[376916c]2274        ## reset dictionary containing reference to dispersion
2275        self._disp_obj_dict = {}
[ef26c83]2276        self.disp_cb_dict = {}
[8960479]2277        self.temp_multi_functional = False
[ea5fa58]2278        f_id = self.formfactorbox.GetCurrentSelection()
2279        #For MAC
2280        form_factor = None
2281        if f_id >= 0:
2282            form_factor = self.formfactorbox.GetClientData(f_id)
[9170547]2283
[376916c]2284        if not form_factor in  self.model_list_box["multiplication"]:
[6dc9ad8]2285            self.structurebox.Hide()
[ef26c83]2286            self.text2.Hide()
[3b605bb]2287            self.structurebox.Disable()
2288            self.structurebox.SetSelection(0)
[c097f02]2289            self.text2.Disable()
[87fbc60]2290        else:
[6dc9ad8]2291            self.structurebox.Show()
2292            self.text2.Show()
[87fbc60]2293            self.structurebox.Enable()
[c097f02]2294            self.text2.Enable()
[4523b68]2295           
[ef26c83]2296        if form_factor != None:
2297            # set multifactor for Mutifunctional models
[be1ec9f]2298            if form_factor().__class__ in \
2299                                        self.model_list_box["Multi-Functions"]:
[4523b68]2300                m_id = self.multifactorbox.GetCurrentSelection()
[fb59ed9]2301                multiplicity = form_factor().multiplicity_info[0]
2302                self.multifactorbox.Clear()
2303                self._set_multfactor_combobox(multiplicity)
2304                self._show_multfactor_combobox()
[ef26c83]2305                #ToDo:  this info should be called directly from the model
2306                text = form_factor().multiplicity_info[1]  # 'No. of Shells: '
[fb59ed9]2307
2308                self.mutifactor_text.SetLabel(text)
[ef26c83]2309                if m_id > multiplicity - 1:
[fb59ed9]2310                    # default value
2311                    m_id = 1
2312                   
[4523b68]2313                self.multi_factor = self.multifactorbox.GetClientData(m_id)
[ef26c83]2314                if self.multi_factor == None:
2315                    self.multi_factor = 0
[4523b68]2316                form_factor = form_factor(int(self.multi_factor))
[fb59ed9]2317                self.multifactorbox.SetSelection(m_id)
2318                # Check len of the text1 and max_multiplicity
2319                text = ''
[be1ec9f]2320                if form_factor.multiplicity_info[0] == \
2321                                        len(form_factor.multiplicity_info[2]):
[fb59ed9]2322                    text = form_factor.multiplicity_info[2][self.multi_factor]
2323                self.mutifactor_text1.SetLabel(text)
2324                # Check if model has  get sld profile.
2325                if len(form_factor.multiplicity_info[3]) > 0:
2326                    self.sld_axes = form_factor.multiplicity_info[3]
2327                    self.show_sld_button.Show(True)
2328                else:
2329                    self.sld_axes = ""
2330
[4523b68]2331            else:
2332                self._hide_multfactor_combobox()
[a1b2471]2333                self.show_sld_button.Hide()
[4523b68]2334                form_factor = form_factor()
2335                self.multi_factor = None
2336        else:
2337            self._hide_multfactor_combobox()
[a1b2471]2338            self.show_sld_button.Hide()
[ef26c83]2339            self.multi_factor = None
[4523b68]2340             
[3b605bb]2341        s_id = self.structurebox.GetCurrentSelection()
[ef26c83]2342        struct_factor = self.structurebox.GetClientData(s_id)
[4523b68]2343       
[ef26c83]2344        if  struct_factor != None:
[79492222]2345            from sas.models.MultiplicationModel import MultiplicationModel
[ef26c83]2346            self.model = MultiplicationModel(form_factor, struct_factor())
[8960479]2347            # multifunctional form factor
2348            if len(form_factor.non_fittable) > 0:
2349                self.temp_multi_functional = True
[c77d859]2350        else:
[fbf4bf8]2351            if form_factor != None:
[ef26c83]2352                self.model = form_factor
[fbf4bf8]2353            else:
2354                self.model = None
2355                return self.model
[318b5bbb]2356        # check if model has magnetic parameters
2357        if len(self.model.magnetic_params) > 0:
2358            self._has_magnetic = True 
2359        else:
2360            self._has_magnetic = False 
[cfc0913]2361        ## post state to fit panel
[ef26c83]2362        self.state.parameters = []
2363        self.state.model = self.model
[4523b68]2364        self.state.qmin = self.qmin_x
2365        self.state.multi_factor = self.multi_factor
[ef26c83]2366        self.disp_list = self.model.getDispParamList()
[f20767b]2367        self.state.disp_list = self.disp_list
[fadf925]2368        self.on_set_focus(None)
[ef26c83]2369        self.Layout()
[c99a6c5]2370       
[85b3971]2371    def _validate_qrange(self, qmin_ctrl, qmax_ctrl):
2372        """
[5062bbf]2373        Verify that the Q range controls have valid values
2374        and that Qmin < Qmax.
2375       
2376        :param qmin_ctrl: text control for Qmin
2377        :param qmax_ctrl: text control for Qmax
2378       
[ef26c83]2379        :return: True is the Q range is value, False otherwise
[5062bbf]2380       
[85b3971]2381        """
2382        qmin_validity = check_float(qmin_ctrl)
2383        qmax_validity = check_float(qmax_ctrl)
2384        if not (qmin_validity and qmax_validity):
2385            return False
2386        else:
2387            qmin = float(qmin_ctrl.GetValue())
2388            qmax = float(qmax_ctrl.GetValue())
[e0e22f2c]2389            if qmin < qmax:
[ef26c83]2390                #Make sure to set both colours white.
[85b3971]2391                qmin_ctrl.SetBackgroundColour(wx.WHITE)
2392                qmin_ctrl.Refresh()
2393                qmax_ctrl.SetBackgroundColour(wx.WHITE)
2394                qmax_ctrl.Refresh()
2395            else:
2396                qmin_ctrl.SetBackgroundColour("pink")
2397                qmin_ctrl.Refresh()
2398                qmax_ctrl.SetBackgroundColour("pink")
2399                qmax_ctrl.Refresh()
[ef26c83]2400                msg = "Invalid Q range: Q min must be smaller than Q max"
[ae84427]2401                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[85b3971]2402                return False
2403        return True
[51a71a3]2404   
[ef26c83]2405    def _validate_Npts(self):
[51a71a3]2406        """
[5062bbf]2407        Validate the number of points for fitting is more than 10 points.
2408        If valid, setvalues Npts_fit otherwise post msg.
[51a71a3]2409        """
2410        #default flag
2411        flag = True
[1a74523]2412        # Theory
2413        if self.data == None and self.enable2D:
2414            return flag
[166f2f8]2415        for data in self.data_list:
2416            # q value from qx and qy
[ef26c83]2417            radius = numpy.sqrt(data.qx_data * data.qx_data +
2418                                data.qy_data * data.qy_data)
[166f2f8]2419            #get unmasked index
2420            index_data = (float(self.qmin.GetValue()) <= radius) & \
2421                            (radius <= float(self.qmax.GetValue()))
[ef26c83]2422            index_data = (index_data) & (data.mask)
[166f2f8]2423            index_data = (index_data) & (numpy.isfinite(data.data))
[7609f1a]2424
[166f2f8]2425            if len(index_data[index_data]) < 10:
2426                # change the color pink.
2427                self.qmin.SetBackgroundColour("pink")
2428                self.qmin.Refresh()
2429                self.qmax.SetBackgroundColour("pink")
2430                self.qmax.Refresh()
[6fe5100]2431                msg = "Data Error: "
2432                msg += "Too few points in %s." % data.name
[ae84427]2433                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[166f2f8]2434                self.fitrange = False
2435                flag = False
2436            else:
[ef26c83]2437                self.Npts_fit.SetValue(str(len(index_data[index_data == True])))
[166f2f8]2438                self.fitrange = True
[51a71a3]2439           
2440        return flag
[94078a8]2441
[ef26c83]2442    def _validate_Npts_1D(self):
[94078a8]2443        """
2444        Validate the number of points for fitting is more than 5 points.
2445        If valid, setvalues Npts_fit otherwise post msg.
2446        """
2447        #default flag
2448        flag = True
2449        # Theory
2450        if self.data == None:
2451            return flag
2452        for data in self.data_list:
2453            # q value from qx and qy
[ef26c83]2454            radius = data.x
[94078a8]2455            #get unmasked index
2456            index_data = (float(self.qmin.GetValue()) <= radius) & \
2457                            (radius <= float(self.qmax.GetValue()))
2458            index_data = (index_data) & (numpy.isfinite(data.y))
2459
2460            if len(index_data[index_data]) < 5:
2461                # change the color pink.
2462                self.qmin.SetBackgroundColour("pink")
2463                self.qmin.Refresh()
2464                self.qmax.SetBackgroundColour("pink")
2465                self.qmax.Refresh()
[6fe5100]2466                msg = "Data Error: "
2467                msg += "Too few points in %s." % data.name
[ae84427]2468                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[94078a8]2469                self.fitrange = False
2470                flag = False
2471            else:
[ef26c83]2472                self.Npts_fit.SetValue(str(len(index_data[index_data == True])))
[94078a8]2473                self.fitrange = True
2474           
2475        return flag
[51a71a3]2476   
[ea5fa58]2477    def _check_value_enter(self, list, modified):
[c77d859]2478        """
[ea5fa58]2479        :param list: model parameter and panel info
2480        :Note: each item of the list should be as follow:
[5062bbf]2481            item=[check button state, parameter's name,
[ef26c83]2482                paramater's value, string="+/-",
2483                parameter's error of fit,
2484                parameter's minimum value,
2485                parrameter's maximum value ,
[5062bbf]2486                parameter's units]
[ef26c83]2487        """
2488        is_modified = modified
[ea5fa58]2489        if len(list) == 0:
[c99a6c5]2490            return is_modified
[ea5fa58]2491        for item in list:
[edd166b]2492            #skip angle parameters for 1D
[ef26c83]2493            if not self.enable2D:
[edd166b]2494                if item in self.orientation_params:
2495                    continue
2496            #try:
2497            name = str(item[1])
2498           
[ef26c83]2499            if string.find(name, ".npts") == -1 and \
2500                                        string.find(name, ".nsigmas") == -1:
2501                ## check model parameters range
2502                param_min = None
2503                param_max = None
[7975f2b]2504               
[c985bef]2505                ## check minimun value
[ef26c83]2506                if item[5] != None and item[5] != "":
2507                    if item[5].GetValue().lstrip().rstrip() != "":
[edd166b]2508                        try:
2509                            param_min = float(item[5].GetValue())
[ef26c83]2510                            if not self._validate_qrange(item[5], item[2]):
[7975f2b]2511                                if numpy.isfinite(param_min):
2512                                    item[2].SetValue(format_number(param_min))
[6e9976b]2513                           
2514                            item[5].SetBackgroundColour(wx.WHITE)
2515                            item[2].SetBackgroundColour(wx.WHITE)
2516                                           
[edd166b]2517                        except:
[6fe5100]2518                            msg = "Wrong fit parameter range entered"
[ae84427]2519                            wx.PostEvent(self._manager.parent,
[ef26c83]2520                                         StatusEvent(status=msg))
[edd166b]2521                            raise ValueError, msg
[c985bef]2522                        is_modified = True
[77e23a2]2523                ## check maximum value
[ef26c83]2524                if item[6] != None and item[6] != "":
2525                    if item[6].GetValue().lstrip().rstrip() != "":
2526                        try:
[edd166b]2527                            param_max = float(item[6].GetValue())
[ef26c83]2528                            if not self._validate_qrange(item[2], item[6]):
[7975f2b]2529                                if numpy.isfinite(param_max):
[ef26c83]2530                                    item[2].SetValue(format_number(param_max))
[6e9976b]2531                           
2532                            item[6].SetBackgroundColour(wx.WHITE)
2533                            item[2].SetBackgroundColour(wx.WHITE)
[edd166b]2534                        except:
2535                            msg = "Wrong Fit parameter range entered "
[ae84427]2536                            wx.PostEvent(self._manager.parent,
[ef26c83]2537                                         StatusEvent(status=msg))
[edd166b]2538                            raise ValueError, msg
[c985bef]2539                        is_modified = True
[7975f2b]2540               
[ef26c83]2541                if param_min != None and param_max != None:
[85b3971]2542                    if not self._validate_qrange(item[5], item[6]):
[ef26c83]2543                        msg = "Wrong Fit range entered for parameter "
2544                        msg += "name %s of model %s " % (name, self.model.name)
[ae84427]2545                        wx.PostEvent(self._manager.parent,
[ef26c83]2546                                     StatusEvent(status=msg))
[7975f2b]2547               
[ef26c83]2548                if name in self.model.details.keys():
[be1ec9f]2549                    self.model.details[name][1:3] = param_min, param_max
2550                    is_modified = True
[edd166b]2551                else:
[be1ec9f]2552                    self.model.details[name] = ["", param_min, param_max]
2553                    is_modified = True
[ef26c83]2554            try:
[2296316]2555                # Check if the textctr is enabled
2556                if item[2].IsEnabled():
[ef26c83]2557                    value = float(item[2].GetValue())
[2296316]2558                    item[2].SetBackgroundColour("white")
2559                    # If the value of the parameter has changed,
2560                    # +update the model and set the is_modified flag
2561                    if value != self.model.getParam(name) and \
2562                                                numpy.isfinite(value):
2563                        self.model.setParam(name, value)
[6e9976b]2564            except:
[7987962]2565                item[2].SetBackgroundColour("pink")
[6e9976b]2566                msg = "Wrong Fit parameter value entered "
[ae84427]2567                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[7975f2b]2568               
[ef26c83]2569        return is_modified
[c77d859]2570       
2571    def _set_dipers_Param(self, event):
2572        """
[5062bbf]2573        respond to self.enable_disp and self.disable_disp radio box.
[ef26c83]2574        The dispersity object is reset inside the model into Gaussian.
2575        When the user select yes , this method display a combo box for
2576        more selection when the user selects No,the combo box disappears.
[5062bbf]2577        Redraw the model with the default dispersity (Gaussian)
[c77d859]2578        """
[4470b10]2579        ## On selction if no model exists.
[ef26c83]2580        if self.model == None:
[4470b10]2581            self.disable_disp.SetValue(True)
[ef26c83]2582            msg = "Please select a Model first..."
[4470b10]2583            wx.MessageBox(msg, 'Info')
[ef26c83]2584            wx.PostEvent(self._manager.parent,
2585                         StatusEvent(status="Polydispersion: %s" % msg))
[4470b10]2586            return
2587
[1c1436d]2588        self._reset_dispersity()
[1467e1a6]2589   
[ef26c83]2590        if self.model == None:
[70c57ebf]2591            self.model_disp.Hide()
2592            self.sizer4_4.Clear(True)
2593            return
[b421b1a]2594
[1c1436d]2595        if self.enable_disp.GetValue():
2596            ## layout for model containing no dispersity parameters
[f20767b]2597           
[ef26c83]2598            self.disp_list = self.model.getDispParamList()
[f20767b]2599             
[ef26c83]2600            if len(self.disp_list) == 0 and len(self.disp_cb_dict) == 0:
2601                self._layout_sizer_noDipers()
[c77d859]2602            else:
[ef26c83]2603                ## set gaussian sizer
[1c1436d]2604                self._on_select_Disp(event=None)
2605        else:
2606            self.sizer4_4.Clear(True)
[f20767b]2607           
[ef26c83]2608        ## post state to fit panel
[1c1436d]2609        self.save_current_state()
[ef26c83]2610        if event != None:
2611            event = PageInfoEvent(page=self)
[240b9966]2612            wx.PostEvent(self.parent, event)
[1467e1a6]2613        #draw the model with the current dispersity
[f20767b]2614        self._draw_model()
[f1aa385]2615        self.sizer4_4.Layout()
2616        self.sizer5.Layout()
[71f0373]2617        self.Layout()
[ef26c83]2618        self.Refresh()
[3b605bb]2619         
[c77d859]2620    def _layout_sizer_noDipers(self):
2621        """
[5062bbf]2622        Draw a sizer with no dispersity info
[c77d859]2623        """
[ef26c83]2624        ix = 0
2625        iy = 1
2626        self.fittable_param = []
2627        self.fixed_param = []
2628        self.orientation_params_disp = []
[1c1436d]2629       
[c77d859]2630        self.sizer4_4.Clear(True)
[01b6bd0]2631        text = "No polydispersity available for this model"
2632        model_disp = wx.StaticText(self, -1, text)
[ef26c83]2633        self.sizer4_4.Add(model_disp, (iy, ix), (1, 1),
2634                          wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
[dcf29d7]2635        self.sizer4_4.Layout()
[c77d859]2636        self.sizer4.Layout()
[340c2b3]2637   
[c77d859]2638    def _reset_dispersity(self):
2639        """
[5062bbf]2640        put gaussian dispersity into current model
[c77d859]2641        """
[ef26c83]2642        if len(self.param_toFit) > 0:
[1c1436d]2643            for item in self.fittable_param:
[513115c]2644                if item in self.param_toFit:
[1c1436d]2645                    self.param_toFit.remove(item)
[edd166b]2646
[1c1436d]2647            for item in self.orientation_params_disp:
[513115c]2648                if item in self.param_toFit:
[1c1436d]2649                    self.param_toFit.remove(item)
[513115c]2650         
[ef26c83]2651        self.fittable_param = []
2652        self.fixed_param = []
2653        self.orientation_params_disp = []
2654        self.values = {}
2655        self.weights = {}
[f20767b]2656     
[79492222]2657        from sas.models.dispersion_models import GaussianDispersion
[ef26c83]2658        if len(self.disp_cb_dict) == 0:
[e2f7b92]2659            self.save_current_state()
[3b605bb]2660            self.sizer4_4.Clear(True)
2661            self.Layout()
[ef26c83]2662            return
2663        if (len(self.disp_cb_dict) > 0):
[f20767b]2664            for p in self.disp_cb_dict:
[ef26c83]2665                # The parameter was un-selected.
2666                # Go back to Gaussian model (with 0 pts)
[f20767b]2667                disp_model = GaussianDispersion()
2668               
[ff8f99b]2669                self._disp_obj_dict[p] = disp_model
[ef26c83]2670                # Set the new model as the dispersion object
2671                # for the selected parameter
[f20767b]2672                try:
[ef26c83]2673                    self.model.set_dispersion(p, disp_model)
[f20767b]2674                except:
[c985bef]2675
[f20767b]2676                    pass
[7975f2b]2677
[240b9966]2678        ## save state into
2679        self.save_current_state()
[ef26c83]2680        self.Layout()
[c985bef]2681        self.Refresh()
[7975f2b]2682                 
[ef26c83]2683    def _on_select_Disp(self, event):
[c77d859]2684        """
[5062bbf]2685        allow selecting different dispersion
2686        self.disp_list should change type later .now only gaussian
[c77d859]2687        """
[2296316]2688        self._set_sizer_dispersion()
2689
[6e9150d]2690        ## Redraw the model
[ef26c83]2691        self._draw_model()
[3a37fe0]2692        #self._undo.Enable(True)
[ef26c83]2693        event = PageInfoEvent(page=self)
[3b9e023]2694        wx.PostEvent(self.parent, event)
2695       
[7975f2b]2696        self.sizer4_4.Layout()
2697        self.sizer4.Layout()
[36cb4d2f]2698        self.SetupScrolling()
[340c2b3]2699   
[ef26c83]2700    def _on_disp_func(self, event=None):
[c77d859]2701        """
[2296316]2702        Select a distribution function for the polydispersion
[f20767b]2703       
[ef26c83]2704        :Param event: ComboBox event
[2296316]2705        """
2706        # get ready for new event
2707        if event != None:
2708            event.Skip()
2709        # Get event object
[ef26c83]2710        disp_box = event.GetEventObject()
[2296316]2711
2712        # Try to select a Distr. function
[ef26c83]2713        try:
[2296316]2714            disp_box.SetBackgroundColour("white")
2715            selection = disp_box.GetCurrentSelection()
2716            param_name = disp_box.Name.split('.')[0]
2717            disp_name = disp_box.GetValue()
[ef26c83]2718            dispersity = disp_box.GetClientData(selection)
[2296316]2719   
2720            #disp_model =  GaussianDispersion()
2721            disp_model = dispersity()
2722            # Get param names to reset the values of the param
2723            name1 = param_name + ".width"
2724            name2 = param_name + ".npts"
2725            name3 = param_name + ".nsigmas"
2726            # Check Disp. function whether or not it is 'array'
2727            if disp_name.lower() == "array":
[ef26c83]2728                value2 = ""
2729                value3 = ""
[2296316]2730                value1 = self._set_array_disp(name=name1, disp=disp_model)
2731            else:
2732                self._del_array_values(name1)
2733                #self._reset_array_disp(param_name)
2734                self._disp_obj_dict[name1] = disp_model
2735                self.model.set_dispersion(param_name, disp_model)
[ef26c83]2736                self.state._disp_obj_dict[name1] = disp_model
[2296316]2737 
[ef26c83]2738                value1 = str(format_number(self.model.getParam(name1), True))
2739                value2 = str(format_number(self.model.getParam(name2)))
2740                value3 = str(format_number(self.model.getParam(name3)))
[2296316]2741            # Reset fittable polydispersin parameter value
[513115c]2742            for item in self.fittable_param:
[ef26c83]2743                if item[1] == name1:
2744                    item[2].SetValue(value1)
[2296316]2745                    item[5].SetValue("")
2746                    item[6].SetValue("")
2747                    # Disable for array
2748                    if disp_name.lower() == "array":
2749                        item[0].SetValue(False)
2750                        item[0].Disable()
2751                        item[2].Disable()
[ace0e33]2752                        item[3].Show(False)
2753                        item[4].Show(False)
[2296316]2754                        item[5].Disable()
2755                        item[6].Disable()
2756                    else:
2757                        item[0].Enable()
2758                        item[2].Enable()
2759                        item[5].Enable()
[ef26c83]2760                        item[6].Enable()
[2296316]2761                    break
2762            # Reset fixed polydispersion params
2763            for item in self.fixed_param:
2764                if item[1] == name2:
2765                    item[2].SetValue(value2) 
2766                    # Disable Npts for array
2767                    if disp_name.lower() == "array":
2768                        item[2].Disable()
2769                    else:
2770                        item[2].Enable()
2771                if item[1] == name3:
[ef26c83]2772                    item[2].SetValue(value3)
[2296316]2773                    # Disable Nsigs for array
2774                    if disp_name.lower() == "array":
2775                        item[2].Disable()
2776                    else:
2777                        item[2].Enable()
2778               
2779            # Make sure the check box updated when all checked
2780            if self.cb1.GetValue():
[fc1761b]2781                #self.select_all_param(None)
2782                self.get_all_checked_params()
[2296316]2783
2784            # update params
[ef26c83]2785            self._update_paramv_on_fit()
[2296316]2786            # draw
2787            self._draw_model()
2788            self.Refresh()
2789        except:
2790            # Error msg
2791            msg = "Error occurred:"
2792            msg += " Could not select the distribution function..."
2793            msg += " Please select another distribution function."
2794            disp_box.SetBackgroundColour("pink")
2795            # Focus on Fit button so that users can see the pinky box
2796            self.btFit.SetFocus()
[ae84427]2797            wx.PostEvent(self._manager.parent,
[2296316]2798                         StatusEvent(status=msg, info="error"))
2799       
2800    def _set_array_disp(self, name=None, disp=None):
2801        """
2802        Set array dispersion
2803       
2804        :param name: name of the parameter for the dispersion to be set
2805        :param disp: the polydisperion object
2806        """
[ef26c83]2807        # The user wants this parameter to be averaged.
[2296316]2808        # Pop up the file selection dialog.
2809        path = self._selectDlg()
2810        # Array data
2811        values = []
2812        weights = []
2813        # If nothing was selected, just return
2814        if path is None:
2815            self.disp_cb_dict[name].SetValue(False)
2816            #self.noDisper_rbox.SetValue(True)
2817            return
2818        self._default_save_location = os.path.dirname(path)
[ae84427]2819        if self._manager != None:
2820            self._manager.parent._default_save_location =\
[baf1ef3]2821                             self._default_save_location
[f20767b]2822
[ef26c83]2823        basename = os.path.basename(path)
2824        values, weights = self.read_file(path)
[3b9e023]2825       
[2296316]2826        # If any of the two arrays is empty, notify the user that we won't
2827        # proceed
[ef26c83]2828        if len(self.param_toFit) > 0:
[2296316]2829            if name in self.param_toFit:
2830                self.param_toFit.remove(name)
2831
2832        # Tell the user that we are about to apply the distribution
2833        msg = "Applying loaded %s distribution: %s" % (name, path)
[ae84427]2834        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[6b39d58]2835        self._set_array_disp_model(name=name, disp=disp,
2836                                    values=values, weights=weights)
2837        return basename
2838   
[ef26c83]2839    def _set_array_disp_model(self, name=None, disp=None,
[6b39d58]2840                              values=[], weights=[]):
2841        """
2842        Set array dispersion model
2843       
2844        :param name: name of the parameter for the dispersion to be set
2845        :param disp: the polydisperion object
2846        """
[2296316]2847        disp.set_weights(values, weights)
2848        self._disp_obj_dict[name] = disp
2849        self.model.set_dispersion(name.split('.')[0], disp)
[ef26c83]2850        self.state._disp_obj_dict[name] = disp
[2296316]2851        self.values[name] = values
2852        self.weights[name] = weights
2853        # Store the object to make it persist outside the
2854        # scope of this method
2855        #TODO: refactor model to clean this up?
2856        self.state.values = {}
2857        self.state.weights = {}
2858        self.state.values = copy.deepcopy(self.values)
2859        self.state.weights = copy.deepcopy(self.weights)
2860
[ef26c83]2861        # Set the new model as the dispersion object for the
[2296316]2862        #selected parameter
2863        #self.model.set_dispersion(p, disp_model)
[ef26c83]2864        # Store a reference to the weights in the model object
[2296316]2865        #so that
2866        # it's not lost when we use the model within another thread.
[ef26c83]2867        self.state.model = self.model.clone()
[2296316]2868        self.model._persistency_dict[name.split('.')[0]] = \
2869                                        [values, weights]
2870        self.state.model._persistency_dict[name.split('.')[0]] = \
[ef26c83]2871                                        [values, weights]
[6b39d58]2872                                       
[ef26c83]2873    def _del_array_values(self, name=None):
[2296316]2874        """
2875        Reset array dispersion
[f20767b]2876       
[ef26c83]2877        :param name: name of the parameter for the dispersion to be set
[2296316]2878        """
2879        # Try to delete values and weight of the names array dic if exists
2880        try:
2881            del self.values[name]
2882            del self.weights[name]
2883            # delete all other dic
2884            del self.state.values[name]
2885            del self.state.weights[name]
[ef26c83]2886            del self.model._persistency_dict[name.split('.')[0]]
[2296316]2887            del self.state.model._persistency_dict[name.split('.')[0]]
2888        except:
2889            pass
2890                                           
[7975f2b]2891    def _lay_out(self):
2892        """
[5062bbf]2893        returns self.Layout
2894       
2895        :Note: Mac seems to like this better when self.
2896            Layout is called after fitting.
[7975f2b]2897        """
2898        self._sleep4sec()
2899        self.Layout()
[ef26c83]2900        return
[7975f2b]2901   
2902    def _sleep4sec(self):
2903        """
[12eac73]2904            sleep for 1 sec only applied on Mac
[ef26c83]2905            Note: This 1sec helps for Mac not to crash on self.
2906            Layout after self._draw_model
[7975f2b]2907        """
2908        if ON_MAC == True:
[12eac73]2909            time.sleep(1)
[f72333f]2910           
[ef26c83]2911    def _find_polyfunc_selection(self, disp_func=None):
[2296316]2912        """
[ef26c83]2913        FInd Comboox selection from disp_func
[2296316]2914       
2915        :param disp_function: dispersion distr. function
2916        """
2917        # List of the poly_model name in the combobox
[ef26c83]2918        list = ["RectangleDispersion", "ArrayDispersion",
2919                "LogNormalDispersion", "GaussianDispersion",
2920                "SchulzDispersion"]
[2296316]2921
2922        # Find the selection
2923        try:
2924            selection = list.index(disp_func.__class__.__name__)
2925            return selection
2926        except:
[ef26c83]2927            return 3
[2296316]2928                           
[ef26c83]2929    def on_reset_clicked(self, event):
[904168e1]2930        """
[5062bbf]2931        On 'Reset' button  for Q range clicked
[904168e1]2932        """
[7609f1a]2933        flag = True
[904168e1]2934        ##For 3 different cases: Data2D, Data1D, and theory
[06aa2eeb]2935        if self.model == None:
[ef26c83]2936            msg = "Please select a model first..."
[06aa2eeb]2937            wx.MessageBox(msg, 'Info')
2938            flag = False
2939            return
2940           
2941        elif self.data.__class__.__name__ == "Data2D":
[ef26c83]2942            data_min = 0
2943            x = max(math.fabs(self.data.xmin), math.fabs(self.data.xmax))
2944            y = max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
[904168e1]2945            self.qmin_x = data_min
2946            self.qmax_x = math.sqrt(x*x + y*y)
[3b70cc7]2947            #self.data.mask = numpy.ones(len(self.data.data),dtype=bool)
[f72333f]2948            # check smearing
2949            if not self.disable_smearer.GetValue():
[ef26c83]2950                ## set smearing value whether or
2951                # not the data contain the smearing info
[f72333f]2952                if self.pinhole_smearer.GetValue():
2953                    flag = self.update_pinhole_smear()
2954                else:
2955                    flag = True
[06aa2eeb]2956                   
2957        elif self.data == None:
2958            self.qmin_x = _QMIN_DEFAULT
2959            self.qmax_x = _QMAX_DEFAULT
[ef26c83]2960            self.num_points = _NPTS_DEFAULT
[06aa2eeb]2961            self.state.npts = self.num_points
2962           
[6318298]2963        elif self.data.__class__.__name__ != "Data2D":
[904168e1]2964            self.qmin_x = min(self.data.x)
2965            self.qmax_x = max(self.data.x)
[7609f1a]2966            # check smearing
2967            if not self.disable_smearer.GetValue():
[ef26c83]2968                ## set smearing value whether or
2969                # not the data contain the smearing info
[7609f1a]2970                if self.slit_smearer.GetValue():
2971                    flag = self.update_slit_smear()
2972                elif self.pinhole_smearer.GetValue():
2973                    flag = self.update_pinhole_smear()
2974                else:
2975                    flag = True
[904168e1]2976        else:
[06aa2eeb]2977            flag = False
[7975f2b]2978           
[7609f1a]2979        if flag == False:
[ef26c83]2980            msg = "Cannot Plot :Must enter a number!!!  "
[ae84427]2981            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[51a71a3]2982        else:
2983            # set relative text ctrs.
[f95301b]2984            self.qmin.SetValue(str(self.qmin_x))
[51a71a3]2985            self.qmax.SetValue(str(self.qmax_x))
[bf5e985]2986            self.show_npts2fit()
[ef26c83]2987            # At this point, some button and variables satatus (disabled?)
2988            # should be checked such as color that should be reset to
2989            # white in case that it was pink.
[51a71a3]2990            self._onparamEnter_helper()
2991
[7609f1a]2992        self.save_current_state()
[904168e1]2993        self.state.qmin = self.qmin_x
2994        self.state.qmax = self.qmax_x
[00c3aac]2995       
[904168e1]2996        #reset the q range values
2997        self._reset_plotting_range(self.state)
2998        self._draw_model()
[2296316]2999       
[cb270ad2]3000    def select_log(self, event):
3001        """
3002        Log checked to generate log spaced points for theory model
3003        """
3004
[2296316]3005    def get_images(self):
3006        """
3007        Get the images of the plots corresponding this panel for report
3008       
3009        : return graphs: list of figures
[be1ec9f]3010        : Need Move to guiframe
[2296316]3011        """
3012        # set list of graphs
3013        graphs = []
3014        canvases = []
[1c6c1b7]3015        res_item = None
[2296316]3016        # call gui_manager
[ae84427]3017        gui_manager = self._manager.parent
[2296316]3018        # loops through the panels [dic]
[be1ec9f]3019        for _, item2 in gui_manager.plot_panels.iteritems():
[ef26c83]3020            data_title = self.data.group_id
[2296316]3021            # try to get all plots belonging to this control panel
[ef26c83]3022            try:
[1c6c1b7]3023                g_id = item2.group_id
3024                if g_id == data_title or \
3025                        str(g_id).count("res" + str(self.graph_id)) or \
3026                        str(g_id).count(str(self.uid)) > 0:
3027                    if str(g_id).count("res" + str(self.graph_id)) > 0:
3028                        res_item = [item2.figure, item2.canvas]
3029                    else:
3030                        # append to the list
3031                        graphs.append(item2.figure)
3032                        canvases.append(item2.canvas) 
[ef26c83]3033            except:
3034                # Not for control panels
3035                pass
[1c6c1b7]3036        # Make sure the resduals plot goes to the last
3037        if res_item != None:
3038            graphs.append(res_item[0])
3039            canvases.append(res_item[1])
[2296316]3040        # return the list of graphs
3041        return graphs, canvases
[904168e1]3042
[ef26c83]3043    def on_model_help_clicked(self, event):
[7ad6ff5]3044        """
[5062bbf]3045        on 'More details' button
[7ad6ff5]3046        """
[79492222]3047        from sas.perspectives.fitting.help_panel import  HelpWindow
3048        from sas.models import get_data_path
[c77d859]3049       
[2296316]3050        # Get models help model_function path
[70b760da]3051        path = get_data_path(media='media')
[ef26c83]3052        model_path = os.path.join(path, "model_functions.html")
[7ad6ff5]3053        if self.model == None:
3054            name = 'FuncHelp'
[ea5fa58]3055        else:
3056            name = self.formfactorbox.GetValue()
[ef26c83]3057        frame = HelpWindow(None, -1, pageToOpen=model_path)
[318b5bbb]3058        # If model name exists and model is not a custom model
3059        #mod_cat = self.categorybox.GetStringSelection()
[ea5fa58]3060        if frame.rhelp.HasAnchor(name):
3061            frame.Show(True)
3062            frame.rhelp.ScrollToAnchor(name)
3063        else:
3064            if self.model != None:
3065                frame.Destroy()
3066                msg = 'Model description:\n'
3067                if str(self.model.description).rstrip().lstrip() == '':
3068                    msg += "Sorry, no information is available for this model."
3069                else:
3070                    msg += self.model.description + '\n'
3071                info = "Info"
3072                wx.MessageBox(msg, info)
3073            else:
3074                frame.Show(True)
3075
[318b5bbb]3076    def _on_mag_help(self, event):   
3077        """
3078        Magnetic angles help panel
3079        """
[79492222]3080        from sas.perspectives.fitting.help_panel import  HelpWindow
[318b5bbb]3081        # Get models help model_function path
[79492222]3082        #import sas.perspectives.fitting as fitmedia
3083        from sas.models import get_data_path
[318b5bbb]3084
3085        media = get_data_path(media='media')
[5eb663a]3086        path = os.path.join(media, "mag_pic.html") 
[318b5bbb]3087        name = "Polar/Magnetic Angles"
3088        frame = HelpWindow(None, -1, 
3089                           title=' Help: Polarization/Magnetization Angles', 
3090                           pageToOpen=path, size=(865, 450))   
3091        try: 
3092            frame.splitter.DetachWindow(frame.lpanel)
3093            # Display only the right side one
3094            frame.lpanel.Hide() 
3095            frame.Show(True)
3096        except:
3097            frame.Destroy() 
3098            msg = 'Display Error\n'
3099            info = "Info"
3100            wx.MessageBox(msg, info)
3101
3102    def _on_mag_on(self, event):   
3103        """
3104        Magnetic Parameters ON/OFF
3105        """
3106        button = event.GetEventObject()
3107
3108        if button.GetLabel().count('ON') > 0:
3109            self.magnetic_on = True
3110            button.SetLabel("Magnetic OFF")
3111            m_value = 1.0e-06
3112            for key in self.model.magnetic_params:
3113                if key.count('M0') > 0:
3114                    self.model.setParam(key, m_value)
3115                    m_value += 0.5e-06
3116        else:
3117            self.magnetic_on = False
3118            button.SetLabel("Magnetic ON")
3119            for key in self.model.magnetic_params:
3120                if key.count('M0') > 0:
3121                    #reset mag value to zero fo safety
3122                    self.model.setParam(key, 0.0)
3123                   
3124        self.Show(False)   
3125        self.set_model_param_sizer(self.model)
3126        #self._set_sizer_dispersion()
3127        self.state.magnetic_on = self.magnetic_on
3128        self.SetupScrolling()
3129        self.Show(True)
[ea5fa58]3130           
[2296316]3131    def on_pd_help_clicked(self, event):
3132        """
3133        Button event for PD help
3134        """
3135        from help_panel import  HelpWindow
[b9a5f0e]3136        import sas.models as models
[2296316]3137       
3138        # Get models help model_function path
3139        path = models.get_data_path(media='media')
[ef26c83]3140        pd_path = os.path.join(path, "pd_help.html")
[2296316]3141
[ef26c83]3142        frame = HelpWindow(None, -1, pageToOpen=pd_path)
[2296316]3143        frame.Show(True)
3144       
3145    def on_left_down(self, event):
3146        """
3147        Get key stroke event
3148        """
3149        # Figuring out key combo: Cmd for copy, Alt for paste
3150        if event.CmdDown() and event.ShiftDown():
[be1ec9f]3151            self.get_paste()
[2296316]3152        elif event.CmdDown():
[be1ec9f]3153            self.get_copy()
[2296316]3154        else:
3155            event.Skip()
3156            return
3157        # make event free
3158        event.Skip()
3159       
[951a2f5]3160    def get_copy(self):
3161        """
3162        Get copy params to clipboard
3163        """
[ef26c83]3164        content = self.get_copy_params()
[951a2f5]3165        flag = self.set_clipboard(content)
[ef26c83]3166        self._copy_info(flag)
3167        return flag
[2296316]3168           
[ef26c83]3169    def get_copy_params(self):
[2296316]3170        """
3171        Get the string copies of the param names and values in the tap
[ef26c83]3172        """
[b9a5f0e]3173        content = 'sasview_parameter_values:'
[ef26c83]3174        # Do it if params exist
3175        if  self.parameters != []:
[2296316]3176           
[ef26c83]3177            # go through the parameters
[be1ec9f]3178            strings = self._get_copy_helper(self.parameters,
[2296316]3179                                           self.orientation_params)
[be1ec9f]3180            content += strings
[2296316]3181           
3182            # go through the fittables
[be1ec9f]3183            strings = self._get_copy_helper(self.fittable_param,
[2296316]3184                                           self.orientation_params_disp)
[be1ec9f]3185            content += strings
[2296316]3186
3187            # go through the fixed params
[be1ec9f]3188            strings = self._get_copy_helper(self.fixed_param,
[2296316]3189                                           self.orientation_params_disp)
[be1ec9f]3190            content += strings
[2296316]3191               
3192            # go through the str params
[be1ec9f]3193            strings = self._get_copy_helper(self.str_parameters,
[2296316]3194                                           self.orientation_params)
[be1ec9f]3195            content += strings
[951a2f5]3196            return content
3197        else:
3198            return False
[34dbaf4]3199
3200    def get_copy_excel(self):
3201        """
3202        Get copy params to clipboard
3203        """
3204        content = self.get_copy_params_excel()
3205        flag = self.set_clipboard(content)
3206        self._copy_info(flag)
3207        return flag
3208
3209    def get_copy_params_excel(self):
3210        """
3211        Get the string copies of the param names and values in the tap
3212        """
3213        content = ''
3214
3215        crlf = chr(13) + chr(10)
3216        tab = chr(9)
3217
3218        # Do it if params exist
3219        if  self.parameters != []:
3220
3221            for param in self.parameters:
3222                content += param[1] #parameter name
3223                content += tab
3224                content += param[1]+"_err"
3225                content += tab
3226
3227            content += crlf
3228
3229            #row of values and errors...
3230            for param in self.parameters:
3231                content += param[2].GetValue() #value
3232                content +=tab
3233                content += param[4].GetValue() #error
3234                content +=tab
3235
3236            return content
3237        else:
3238            return False
3239
3240
3241    def get_copy_latex(self):
3242        """
3243        Get copy params to clipboard
3244        """
3245        content = self.get_copy_params_latex()
3246        flag = self.set_clipboard(content)
3247        self._copy_info(flag)
3248        return flag
3249
3250    def get_copy_params_latex(self):
3251        """
3252        Get the string copies of the param names and values in the tap
3253        """
3254        content = '\\begin{table}'
3255        content += '\\begin{tabular}[h]'
3256
3257        crlf = chr(13) + chr(10)
3258        tab = chr(9)
3259
3260        # Do it if params exist
3261        if  self.parameters != []:
3262
3263            content += '{|'
3264            for param in self.parameters:
3265                content += 'l|l|'
3266            content += '}\hline'
3267            content += crlf
3268
3269            for index, param in enumerate(self.parameters):
3270                content += param[1].replace('_','\_') #parameter name
3271                content += ' & '
3272                content += param[1].replace('_','\_')+"\_err"
3273                if index < len(self.parameters)-1:
3274                    content += ' & '
3275            content += '\\\\ \\hline'
3276            content += crlf
3277
3278            #row of values and errors...
3279            for index, param in enumerate(self.parameters):
3280                content += param[2].GetValue() #parameter value
3281                content += ' & '
3282                content += param[4].GetValue() #parameter error
3283                if index < len(self.parameters)-1:
3284                    content += ' & '
3285            content += '\\\\ \\hline'
3286            content += crlf
3287
3288            content += '\\end{tabular}'
3289            content += '\\end{table}'
3290            return content
3291        else:
3292            return False
3293
3294
[ef26c83]3295    def set_clipboard(self, content=None):
[951a2f5]3296        """
3297        Put the string to the clipboard
[ef26c83]3298        """
[951a2f5]3299        if not content:
3300            return False
[2296316]3301        if wx.TheClipboard.Open():
3302            wx.TheClipboard.SetData(wx.TextDataObject(str(content)))
3303            wx.TheClipboard.Close()
[951a2f5]3304            return True
[2296316]3305        return None
3306   
3307    def _get_copy_helper(self, param, orient_param):
3308        """
3309        Helping get value and name of the params
3310       
3311        : param param:  parameters
3312        : param orient_param = oritational params
3313        : return content: strings [list] [name,value:....]
3314        """
3315        content = ''
3316        # go through the str params
[ef26c83]3317        for item in param:
[1ac202f]3318            # copy only the params shown
3319            if not item[2].IsShown():
3320                continue
[68a921f]3321            disfunc = ''
3322            try:
3323                if item[7].__class__.__name__ == 'ComboBox':
[706667b]3324                    disfunc = str(item[7].GetValue())
[68a921f]3325            except:
3326                pass
[706667b]3327           
[2296316]3328            # 2D
[25c0def]3329            if self.data.__class__.__name__ == "Data2D":
[fc1761b]3330                try:
3331                    check = item[0].GetValue()
3332                except:
3333                    check = None
[2296316]3334                name = item[1]
3335                value = item[2].GetValue()
3336            # 1D
3337            else:
3338                ## for 1D all parameters except orientation
3339                if not item[1] in orient_param:
[fc1761b]3340                    try:
3341                        check = item[0].GetValue()
3342                    except:
3343                        check = None
[2296316]3344                    name = item[1]
3345                    value = item[2].GetValue()
[706667b]3346
[2296316]3347            # add to the content
[68a921f]3348            if disfunc != '':
[706667b]3349               
[68a921f]3350                disfunc = ',' + disfunc
[be1ec9f]3351            # Need to support array func for copy/paste
[ace0e33]3352            try:
3353                if disfunc.count('array') > 0:
3354                    disfunc += ','
3355                    for val in self.values[name]:
3356                        disfunc += ' ' + str(val)
3357                    disfunc += ','
3358                    for weight in self.weights[name]:
3359                        disfunc += ' ' + str(weight)
3360            except:
3361                pass
[ef26c83]3362            content += name + ',' + str(check) + ',' + value + disfunc + ':'
[68a921f]3363
[2296316]3364        return content
[951a2f5]3365   
[ef26c83]3366    def get_clipboard(self):
[951a2f5]3367        """
3368        Get strings in the clipboard
3369        """
[ef26c83]3370        text = ""
3371        # Get text from the clip board
[951a2f5]3372        if wx.TheClipboard.Open():
[25c0def]3373            if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
3374                data = wx.TextDataObject()
3375                # get wx dataobject
[2a66329]3376                success = wx.TheClipboard.GetData(data)
[25c0def]3377                # get text
[2a66329]3378                if success:
3379                    text = data.GetText()
3380                else:
3381                    text = ''
[25c0def]3382            # close clipboard
3383            wx.TheClipboard.Close()
[951a2f5]3384        return text
[2296316]3385   
[951a2f5]3386    def get_paste(self):
3387        """
3388        Paste params from the clipboard
3389        """
3390        text = self.get_clipboard()
[817991b]3391        flag = self.get_paste_params(text)
3392        self._copy_info(flag)
3393        return flag
[951a2f5]3394       
[ef26c83]3395    def get_paste_params(self, text=''):
[2296316]3396        """
3397        Get the string copies of the param names and values in the tap
[ef26c83]3398        """
3399        context = {}
3400        # put the text into dictionary
[2296316]3401        lines = text.split(':')
[b9a5f0e]3402        if lines[0] != 'sasview_parameter_values':
[977a965]3403            self._copy_info(False)
[2296316]3404            return False
3405        for line in lines[1:-1]:
3406            if len(line) != 0:
[25c0def]3407                item = line.split(',')
[fc1761b]3408                check = item[1]
[2296316]3409                name = item[0]
[fc1761b]3410                value = item[2]
[2296316]3411                # Transfer the text to content[dictionary]
[fc1761b]3412                context[name] = [check, value]
[68a921f]3413            # ToDo: PlugIn this poly disp function for pasting
[706667b]3414            try:
[fc1761b]3415                poly_func = item[3]
[ace0e33]3416                context[name].append(poly_func)
3417                try:
[ef26c83]3418                    # take the vals and weights for  array
[fc1761b]3419                    array_values = item[4].split(' ')
3420                    array_weights = item[5].split(' ')
[ace0e33]3421                    val = [float(a_val) for a_val in array_values[1:]]
3422                    weit = [float(a_weit) for a_weit in array_weights[1:]]
3423                   
3424                    context[name].append(val)
3425                    context[name].append(weit)
3426                except:
3427                    raise
[706667b]3428            except:
[ace0e33]3429                poly_func = ''
3430                context[name].append(poly_func)
[706667b]3431
[ef26c83]3432        # Do it if params exist
[2296316]3433        if  self.parameters != []:
[ef26c83]3434            # go through the parameters
3435            self._get_paste_helper(self.parameters,
[2296316]3436                                   self.orientation_params, context)
3437
3438            # go through the fittables
[ef26c83]3439            self._get_paste_helper(self.fittable_param,
3440                                   self.orientation_params_disp,
[706667b]3441                                   context)
[2296316]3442
3443            # go through the fixed params
[ef26c83]3444            self._get_paste_helper(self.fixed_param,
[2296316]3445                                   self.orientation_params_disp, context)
3446           
3447            # go through the str params
[ef26c83]3448            self._get_paste_helper(self.str_parameters,
[2296316]3449                                   self.orientation_params, context)
[6b39d58]3450               
[817991b]3451            return True
3452        return None
[2296316]3453   
3454    def _get_paste_helper(self, param, orient_param, content):
3455        """
3456        Helping set values of the params
3457       
3458        : param param:  parameters
3459        : param orient_param: oritational params
[ef26c83]3460        : param content: dictionary [ name, value: name1.value1,...]
[2296316]3461        """
3462        # go through the str params
[ef26c83]3463        for item in param:
[2296316]3464            # 2D
[25c0def]3465            if self.data.__class__.__name__ == "Data2D":
[2296316]3466                name = item[1]
3467                if name in content.keys():
[fc1761b]3468                    check = content[name][0]
3469                    pd = content[name][1]
[706667b]3470                    if name.count('.') > 0:
3471                        try:
[ace0e33]3472                            float(pd)
[706667b]3473                        except:
[01642fec]3474                            #continue
3475                            if not pd and pd != '':
3476                                continue
[ace0e33]3477                    item[2].SetValue(str(pd))
[01642fec]3478                    if item in self.fixed_param and pd == '':
3479                        # Only array func has pd == '' case.
3480                        item[2].Enable(False)
[706667b]3481                    if item[2].__class__.__name__ == "ComboBox":
[ef26c83]3482                        if content[name][1] in self.model.fun_list:
[fc1761b]3483                            fun_val = self.model.fun_list[content[name][1]]
[25c0def]3484                            self.model.setParam(name, fun_val)
[706667b]3485                   
[fc1761b]3486                    value = content[name][1:]
[ace0e33]3487                    self._paste_poly_help(item, value)
[fc1761b]3488                    if check == 'True':
3489                        is_true = True
3490                    elif check == 'False':
3491                        is_true = False
3492                    else:
3493                        is_true = None
3494                    if is_true != None:
3495                        item[0].SetValue(is_true)
3496            # 1D
[2296316]3497            else:
3498                ## for 1D all parameters except orientation
3499                if not item[1] in orient_param:
3500                    name = item[1]
3501                    if name in content.keys():
[fc1761b]3502                        check = content[name][0]
[ef26c83]3503                        # Avoid changing combox content
[fc1761b]3504                        value = content[name][1:]
[ace0e33]3505                        pd = value[0]
[706667b]3506                        if name.count('.') > 0:
3507                            try:
[ace0e33]3508                                pd = float(pd)
[706667b]3509                            except:
[01642fec]3510                                #continue
3511                                if not pd and pd != '':
3512                                    continue
[ace0e33]3513                        item[2].SetValue(str(pd))
3514                        if item in self.fixed_param and pd == '':
3515                            # Only array func has pd == '' case.
3516                            item[2].Enable(False)
[d8c54ead]3517                        if item[2].__class__.__name__ == "ComboBox":
[ef26c83]3518                            if value[0] in self.model.fun_list:
[706667b]3519                                fun_val = self.model.fun_list[value[0]]
[25c0def]3520                                self.model.setParam(name, fun_val)
[d8c54ead]3521                                # save state
[ace0e33]3522                        self._paste_poly_help(item, value)
[fc1761b]3523                        if check == 'True':
3524                            is_true = True
3525                        elif check == 'False':
3526                            is_true = False
3527                        else:
3528                            is_true = None
3529                        if is_true != None:
3530                            item[0].SetValue(is_true)
[ace0e33]3531                       
3532    def _paste_poly_help(self, item, value):
3533        """
3534        Helps get paste for poly function
3535       
3536        :param item: Gui param items
3537        :param value: the values for parameter ctrols
3538        """
[6b39d58]3539        is_array = False
[ace0e33]3540        if len(value[1]) > 0:
3541            # Only for dispersion func.s
3542            try:
3543                item[7].SetValue(value[1])
3544                selection = item[7].GetCurrentSelection()
[01642fec]3545                name = item[7].Name
3546                param_name = name.split('.')[0]
[25c0def]3547                dispersity = item[7].GetClientData(selection)
[ace0e33]3548                disp_model = dispersity()
3549                # Only for array disp
3550                try:
3551                    pd_vals = numpy.array(value[2])
3552                    pd_weights = numpy.array(value[3])
3553                    if len(pd_vals) > 0 and len(pd_vals) > 0:
3554                        if len(pd_vals) == len(pd_weights):
[6b39d58]3555                            self._set_disp_array_cb(item=item)
[ef26c83]3556                            self._set_array_disp_model(name=name,
[6b39d58]3557                                                       disp=disp_model,
[ef26c83]3558                                                       values=pd_vals,
[6b39d58]3559                                                       weights=pd_weights)
3560                            is_array = True
[ace0e33]3561                except:
[ef26c83]3562                    pass
[6b39d58]3563                if not is_array:
3564                    self._disp_obj_dict[name] = disp_model
[ef26c83]3565                    self.model.set_dispersion(name,
[6b39d58]3566                                              disp_model)
3567                    self.state._disp_obj_dict[name] = \
3568                                              disp_model
3569                    self.model.set_dispersion(param_name, disp_model)
3570                    self.state.values = self.values
[ef26c83]3571                    self.state.weights = self.weights
[6b39d58]3572                    self.model._persistency_dict[param_name] = \
[ef26c83]3573                                            [self.state.values,
[25c0def]3574                                             self.state.weights]
[6b39d58]3575                         
[ace0e33]3576            except:
[ef26c83]3577                print "Error in BasePage._paste_poly_help: %s" % sys.exc_value
[6b39d58]3578   
3579    def _set_disp_array_cb(self, item):
3580        """
3581        Set cb for array disp
3582        """
3583        item[0].SetValue(False)
3584        item[0].Enable(False)
3585        item[2].Enable(False)
3586        item[3].Show(False)
3587        item[4].Show(False)
3588        item[5].SetValue('')
3589        item[5].Enable(False)
3590        item[6].SetValue('')
3591        item[6].Enable(False)
[25c0def]3592       
3593    def update_pinhole_smear(self):
3594        """
3595            Method to be called by sub-classes
[be1ec9f]3596            Moveit; This method doesn't belong here
[25c0def]3597        """
3598        print "BasicPage.update_pinhole_smear was called: skipping"
3599        return
[0b477f6]3600
[ea5fa58]3601
3602
3603
[df7a7e3]3604    def _read_category_info(self):
3605        """
3606        Reads the categories in from file
3607        """
3608
3609        # # ILL mod starts here - July 2012 kieranrcampbell@gmail.com
3610        self.master_category_dict = defaultdict(list)
3611        self.by_model_dict = defaultdict(list)
3612        self.model_enabled_dict = defaultdict(bool)
3613
3614        try:
[ea5fa58]3615            categorization_file = CategoryInstaller.get_user_file()
3616            if not os.path.isfile(categorization_file):
3617                categorization_file = CategoryInstaller.get_default_file()
[27b7acc]3618            cat_file = open(categorization_file, 'rb')                           
3619            self.master_category_dict = json.load(cat_file)
[df7a7e3]3620            self._regenerate_model_dict()
[657e52c]3621            cat_file.close()
[df7a7e3]3622
3623        except IOError:
[ea5fa58]3624            raise
[df7a7e3]3625            print 'Problem reading in category file.'
3626            print 'We even looked for it, made sure it was there.'
3627            print 'An existential crisis if there ever was one.'
3628
3629    def _regenerate_model_dict(self):
3630        """
3631        regenerates self.by_model_dict which has each model name as the
3632        key and the list of categories belonging to that model
3633        along with the enabled mapping
3634        """
3635
3636        self.by_model_dict = defaultdict(list)
3637        for category in self.master_category_dict:
[ea5fa58]3638            for (model, enabled) in self.master_category_dict[category]:
[df7a7e3]3639                self.by_model_dict[model].append(category)
3640                self.model_enabled_dict[model] = enabled
3641   
3642    def _populate_listbox(self):
3643        """
3644        fills out the category list box
3645        """
[ea5fa58]3646        uncat_str = 'Customized Models'
[df7a7e3]3647        self._read_category_info()
3648
[ea5fa58]3649        self.categorybox.Clear()
[df7a7e3]3650        cat_list = sorted(self.master_category_dict.keys())
[ea5fa58]3651        if not uncat_str in cat_list:
3652            cat_list.append(uncat_str)
3653       
[df7a7e3]3654        for category in cat_list:
3655            if category != '':
[ea5fa58]3656                self.categorybox.Append(category)
[df7a7e3]3657
[ea5fa58]3658        if self.categorybox.GetSelection() == wx.NOT_FOUND:
3659            self.categorybox.SetSelection(0)
[df7a7e3]3660        else:
[ea5fa58]3661            self.categorybox.SetSelection( \
3662                self.categorybox.GetSelection())
[df7a7e3]3663
[ea5fa58]3664        #self._on_change_cat(None)
[df7a7e3]3665
3666
3667    def _on_change_cat(self, event):
3668        """
3669        Callback for category change action
3670        """
3671        self.model_name = None
[ea5fa58]3672        category = self.categorybox.GetStringSelection()
[df7a7e3]3673        if category == None:
3674            return
3675        self.model_box.Clear()
3676
[ea5fa58]3677        if category == 'Customized Models':
3678            for model in self.model_list_box[category]:
[df7a7e3]3679                str_m = str(model).split(".")[0]
3680                self.model_box.Append(str_m)
3681
3682        else:
3683            for (model,enabled) in sorted(self.master_category_dict[category],
3684                                      key = lambda name: name[0]):
3685                if(enabled):
3686                    self.model_box.Append(model)
3687
[ea5fa58]3688
3689
3690
[0b477f6]3691    def _fill_model_sizer(self, sizer):
3692        """
3693        fill sizer containing model info
3694        """
3695        ##Add model function Details button in fitpanel.
3696        ##The following 3 lines are for Mac. Let JHC know before modifying...
3697        title = "Model"
3698        self.formfactorbox = None
3699        self.multifactorbox = None
3700        self.mbox_description = wx.StaticBox(self, -1, str(title))
3701        boxsizer1 = wx.StaticBoxSizer(self.mbox_description, wx.VERTICAL)
[ea5fa58]3702        sizer_cat = wx.BoxSizer(wx.HORIZONTAL)
[0b477f6]3703        self.mbox_description.SetForegroundColour(wx.RED)
3704        id = wx.NewId()
3705        self.model_help = wx.Button(self, id, 'Details', size=(80, 23))
3706        self.model_help.Bind(wx.EVT_BUTTON, self.on_model_help_clicked, id=id)
3707        self.model_help.SetToolTipString("Model Function Help")
3708        id = wx.NewId()
3709        self.model_view = wx.Button(self, id, "Show 2D", size=(80, 23))
3710        self.model_view.Bind(wx.EVT_BUTTON, self._onModel2D, id=id)
3711        hint = "toggle view of model from 1D to 2D  or 2D to 1D"
3712        self.model_view.SetToolTipString(hint)
3713       
[ea5fa58]3714        cat_set_box = wx.StaticBox(self, -1, 'Category')
3715        sizer_cat_box = wx.StaticBoxSizer(cat_set_box, wx.HORIZONTAL)
3716        sizer_cat_box.SetMinSize((200, 50))
3717        self.categorybox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
[ae4c139]3718        self.categorybox.SetToolTip( wx.ToolTip("Select a Category/Type") )
[ea5fa58]3719        self._populate_listbox()
3720        wx.EVT_COMBOBOX(self.categorybox, -1, self._show_combox)
3721        #self.shape_rbutton = wx.RadioButton(self, -1, 'Shapes',
3722        #                                     style=wx.RB_GROUP)
3723        #self.shape_indep_rbutton = wx.RadioButton(self, -1,
3724        #                                          "Shape-Independent")
3725        #self.struct_rbutton = wx.RadioButton(self, -1, "Structure Factor ")
3726        #self.plugin_rbutton = wx.RadioButton(self, -1, "Uncategorized")
3727               
3728        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3729        #                   id=self.shape_rbutton.GetId())
3730        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3731        #                    id=self.shape_indep_rbutton.GetId())
3732        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3733        #                    id=self.struct_rbutton.GetId())
3734        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3735        #                    id=self.plugin_rbutton.GetId())
3736        #MAC needs SetValue
[ef67145]3737       
3738        show_cat_button = wx.Button(self, -1, "Modify")
3739        cat_tip = "Modify model categories \n"
3740        cat_tip += "(also accessible from the menu bar)."
3741        show_cat_button.SetToolTip( wx.ToolTip(cat_tip) )
3742        show_cat_button.Bind(wx.EVT_BUTTON, self._on_modify_cat)
3743        sizer_cat_box.Add(self.categorybox, 1, wx.RIGHT, 3)
3744        sizer_cat_box.Add((10,10))
3745        sizer_cat_box.Add(show_cat_button)
[ea5fa58]3746        #self.shape_rbutton.SetValue(True)
3747     
3748        sizer_radiobutton = wx.GridSizer(2, 2, 5, 5)
3749
3750        #sizer_radiobutton.Add(self.shape_rbutton)
3751        #sizer_radiobutton.Add(self.shape_indep_rbutton)
3752        sizer_radiobutton.Add((5,5))
3753        sizer_radiobutton.Add(self.model_view, 1, wx.RIGHT, 15)
3754        #sizer_radiobutton.Add(self.plugin_rbutton)
3755        #sizer_radiobutton.Add(self.struct_rbutton)
3756        sizer_radiobutton.Add((5,5))
3757        sizer_radiobutton.Add(self.model_help, 1, wx.RIGHT, 15)
3758        sizer_cat.Add(sizer_cat_box, 1, wx.LEFT, 2.5)
3759        sizer_cat.Add(sizer_radiobutton)
[0b477f6]3760        sizer_selection = wx.BoxSizer(wx.HORIZONTAL)
3761        mutifactor_selection = wx.BoxSizer(wx.HORIZONTAL)
3762       
3763        self.text1 = wx.StaticText(self, -1, "")
[ea5fa58]3764        self.text2 = wx.StaticText(self, -1, "P(Q)*S(Q)")
[0b477f6]3765        self.mutifactor_text = wx.StaticText(self, -1, "No. of Shells: ")
3766        self.mutifactor_text1 = wx.StaticText(self, -1, "")
3767        self.show_sld_button = wx.Button(self, -1, "Show SLD Profile")
3768        self.show_sld_button.Bind(wx.EVT_BUTTON, self._on_show_sld)
3769
[ea5fa58]3770        self.formfactorbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
[ae4c139]3771        self.formfactorbox.SetToolTip( wx.ToolTip("Select a Model") )
[ea5fa58]3772        if self.model != None:
3773            self.formfactorbox.SetValue(self.model.name)
[0b477f6]3774        self.structurebox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
3775        self.multifactorbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
3776        self.initialize_combox()
[ea5fa58]3777        wx.EVT_COMBOBOX(self.formfactorbox, -1, self._on_select_model)
[0b477f6]3778
3779        wx.EVT_COMBOBOX(self.structurebox, -1, self._on_select_model)
3780        wx.EVT_COMBOBOX(self.multifactorbox, -1, self._on_select_model)
3781        ## check model type to show sizer
3782        if self.model != None:
[ea5fa58]3783            print "_set_model_sizer_selection: disabled."
3784            #self._set_model_sizer_selection(self.model)
3785       
3786        sizer_selection.Add(self.text1)
3787        sizer_selection.Add((10, 5))
3788        sizer_selection.Add(self.formfactorbox)
3789        sizer_selection.Add((5, 5))
3790        sizer_selection.Add(self.text2)
3791        sizer_selection.Add((5, 5))
3792        sizer_selection.Add(self.structurebox)
[0b477f6]3793       
[ea5fa58]3794        mutifactor_selection.Add((13, 5))
[0b477f6]3795        mutifactor_selection.Add(self.mutifactor_text)
3796        mutifactor_selection.Add(self.multifactorbox)
3797        mutifactor_selection.Add((5, 5))
3798        mutifactor_selection.Add(self.mutifactor_text1)
3799        mutifactor_selection.Add((10, 5))
3800        mutifactor_selection.Add(self.show_sld_button)
3801
[ea5fa58]3802        boxsizer1.Add(sizer_cat)
3803        boxsizer1.Add((10, 10))
3804        boxsizer1.Add(sizer_selection)
[0b477f6]3805        boxsizer1.Add((10, 10))
3806        boxsizer1.Add(mutifactor_selection)
3807       
3808        self._set_multfactor_combobox()
3809        self.multifactorbox.SetSelection(1)
3810        self.show_sld_button.Hide()
3811        sizer.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
3812        sizer.Layout()
[fcd6c6a]3813       
3814    def on_smear_helper(self, update=False):
3815        """
3816        Help for onSmear if implemented
3817       
3818        :param update: force or not to update
3819        """
3820    def reset_page(self, state, first=False):
3821        """
3822        reset the state  if implemented
3823        """
3824    def onSmear(self, event):
3825        """
3826        Create a smear object if implemented
3827        """
3828    def onPinholeSmear(self, event):
3829        """
3830        Create a custom pinhole smear object if implemented
3831        """
3832    def onSlitSmear(self, event):
3833        """
3834        Create a custom slit smear object if implemented
3835        """
3836    def update_slit_smear(self):
3837        """
3838        called by kill_focus on pinhole TextCntrl
3839        to update the changes if implemented
3840        """
3841    def select_param(self, event):
3842        """
3843        Select TextCtrl  checked if implemented
3844        """
3845    def set_data(self, data=None):
3846        """
3847        Sets data if implemented
3848        """
3849    def _is_2D(self):
3850        """
3851        Check if data_name is Data2D if implemented
3852        """
3853    def _on_select_model(self, event=None):
3854        """
3855        call back for model selection if implemented
3856        """
3857    def select_all_param(self, event):
3858        """
3859        set to true or false all checkBox if implemented
3860        """
3861    def get_weight_flag(self):
3862        """
3863        Get flag corresponding to a given weighting dI data if implemented
3864        """
3865    def _set_sizer_dispersion(self):
3866        """
3867        draw sizer for dispersity if implemented
3868        """
3869    def get_all_checked_params(self):
3870        """
3871        Found all parameters current check and add them to list of parameters
3872        to fit if implemented
3873        """
[bf5e985]3874    def show_npts2fit(self):
[fcd6c6a]3875        """
3876        setValue Npts for fitting if implemented
3877        """
3878    def _onModel2D(self, event):
3879        """
3880        toggle view of model from 1D to 2D  or 2D from 1D if implemented
[6fe5100]3881        """
Note: See TracBrowser for help on using the repository browser.