source: sasview/src/sas/perspectives/fitting/basepage.py @ 0e4e554

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 0e4e554 was 0e4e554, checked in by ajj, 9 years ago

start switching to sasmodels including dispersion

  • Property mode set to 100644
File size: 152.3 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
[0e4e554]1198                        #from sas.models.dispersion_models import ArrayDispersion
1199                        from sasmodels.weights import ArrayDispersion
[e88ebfd]1200                        disp_model = ArrayDispersion()
[ef26c83]1201                        if hasattr(state, "values") and \
[e88ebfd]1202                                 self.disp_cb_dict[item].GetValue() == True:
[ef26c83]1203                            if len(state.values) > 0:
1204                                self.values = state.values
1205                                self.weights = state.weights
[e88ebfd]1206                                disp_model.set_weights(self.values,
[ef26c83]1207                                                       state.weights)
[e88ebfd]1208                            else:
1209                                self._reset_dispersity()
1210                       
1211                        self._disp_obj_dict[item] = disp_model
[ef26c83]1212                        # Set the new model as the dispersion object
[e88ebfd]1213                        #for the selected parameter
1214                        self.model.set_dispersion(item, disp_model)
1215                   
1216                        self.model._persistency_dict[item] = \
1217                                                [state.values, state.weights]
1218                   
1219            else:
1220                keys = self.model.getParamList()
1221                for item in keys:
1222                    if item in self.disp_list and \
[ef26c83]1223                        not item in self.model.details:
[e88ebfd]1224                        self.model.details[item] = ["", None, None]
[be1ec9f]1225                self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
1226                self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
[ef26c83]1227        ## smearing info  restore
[e88ebfd]1228        if hasattr(self, "enable_smearer"):
[ef26c83]1229            ## set smearing value whether or not the data
[e88ebfd]1230            #contain the smearing info
1231            self.enable_smearer.SetValue(state.enable_smearer)
1232            self.disable_smearer.SetValue(state.disable_smearer)
[ef26c83]1233            self.onSmear(event=None)
[e88ebfd]1234        self.pinhole_smearer.SetValue(state.pinhole_smearer)
1235        self.slit_smearer.SetValue(state.slit_smearer)
[55bb249c]1236       
1237        self.dI_noweight.SetValue(state.dI_noweight)
1238        self.dI_didata.SetValue(state.dI_didata)
1239        self.dI_sqrdata.SetValue(state.dI_sqrdata)
1240        self.dI_idata.SetValue(state.dI_idata)
1241       
[e88ebfd]1242        ## we have two more options for smearing
[ef26c83]1243        if self.pinhole_smearer.GetValue():
1244            self.onPinholeSmear(event=None)
1245        elif self.slit_smearer.GetValue():
1246            self.onSlitSmear(event=None)
[e88ebfd]1247       
1248        ## reset state of checkbox,textcrtl  and dispersity parameters value
[ef26c83]1249        self._reset_parameters_state(self.fittable_param, state.fittable_param)
1250        self._reset_parameters_state(self.fixed_param, state.fixed_param)
[e88ebfd]1251       
1252        ## draw the model with previous parameters value
1253        self._onparamEnter_helper()
[ef26c83]1254        self.select_param(event=None)
[e88ebfd]1255        #Save state_fit
1256        self.save_current_state_fit()
1257        self._lay_out()
1258        self.Refresh()
1259       
[240b9966]1260    def reset_page_helper(self, state):
[cfc0913]1261        """
[5062bbf]1262        Use page_state and change the state of existing page
1263       
1264        :precondition: the page is already drawn or created
1265       
1266        :postcondition: the state of the underlying data change as well as the
[71f0373]1267            state of the graphic interface
[cfc0913]1268        """
[4a7ad5f]1269        if state == None:
[ef26c83]1270            return
[2296316]1271        # set data, etc. from the state
[2657df9]1272        # reset page between theory and fitting from bookmarking
1273        #if state.data == None:
1274        #    data = None
1275        #else:
1276        data = state.data
1277
1278        if data == None:
1279            data_min = state.qmin
1280            data_max = state.qmax
1281            self.qmin_x = data_min
1282            self.qmax_x = data_max
1283            self.qmin.SetValue(str(data_min))
1284            self.qmax.SetValue(str(data_max))
1285
1286            self.state.data = data
1287            self.state.qmin = self.qmin_x
1288            self.state.qmax = self.qmax_x
1289        else:
1290            self.set_data(data)
1291           
[ef26c83]1292        self.enable2D = state.enable2D
[318b5bbb]1293        try:
1294            self.magnetic_on = state.magnetic_on
1295        except:
1296            # Backward compatibility (for older state files)
1297            self.magnetic_on = False
[0b12abb5]1298        self.engine_type = state.engine_type
1299
1300        self.disp_cb_dict = state.disp_cb_dict
1301        self.disp_list = state.disp_list
[e3d1423]1302     
[ea5fa58]1303        ## set the state of the radio box
1304        #self.shape_rbutton.SetValue(state.shape_rbutton)
1305        #self.shape_indep_rbutton.SetValue(state.shape_indep_rbutton)
1306        #self.struct_rbutton.SetValue(state.struct_rbutton)
1307        #self.plugin_rbutton.SetValue(state.plugin_rbutton)
[0b12abb5]1308       
1309        ## fill model combobox
1310        self._show_combox_helper()
1311        #select the current model
[ea5fa58]1312        try:
1313            # to support older version
1314            category_pos = int(state.categorycombobox)
1315        except:
1316            category_pos = 0
1317            for ind_cat in range(self.categorybox.GetCount()):
1318                if self.categorybox.GetString(ind_cat) == \
1319                                        state.categorycombobox:
1320                    category_pos = int(ind_cat)
1321                    break
1322           
1323        self.categorybox.Select(category_pos)
1324        self._show_combox(None)
1325        try:
1326            # to support older version
1327            formfactor_pos = int(state.formfactorcombobox)
1328        except:
1329            formfactor_pos = 0
1330            for ind_form in range(self.formfactorbox.GetCount()):
1331                if self.formfactorbox.GetString(ind_form) == \
1332                                                    (state.formfactorcombobox):
1333                    formfactor_pos = int(ind_form)
1334                    break
1335           
1336        self.formfactorbox.Select(formfactor_pos)
1337       
[d40038e]1338        try:
1339            # to support older version
1340            structfactor_pos = int(state.structurecombobox)
1341        except:
1342            structfactor_pos = 0
1343            for ind_struct in range(self.structurebox.GetCount()):
[be1ec9f]1344                if self.structurebox.GetString(ind_struct) == \
1345                                                    (state.structurecombobox):
[d40038e]1346                    structfactor_pos = int(ind_struct)
1347                    break
1348           
1349        self.structurebox.SetSelection(structfactor_pos)
1350
[4523b68]1351        if state.multi_factor != None:
[cf6a192]1352            self.multifactorbox.SetSelection(state.multi_factor)
[4523b68]1353
[0b12abb5]1354        #reset the fitting engine type
1355        self.engine_type = state.engine_type
[ef26c83]1356        #draw the pnael according to the new model parameter
[0b12abb5]1357        self._on_select_model(event=None)
[93f0a862]1358           
[2657df9]1359        # take care of 2D button
1360        if data == None and self.model_view.IsEnabled():
1361            if self.enable2D:
[6371c9c]1362                self.model_view.SetLabel("2D Mode")
[2657df9]1363            else:
[6371c9c]1364                self.model_view.SetLabel("1D Mode")
[2657df9]1365        # else:
1366               
[ef26c83]1367        if self._manager != None and self.engine_type != None:
[3cd5806]1368            self._manager._on_change_engine(engine=self.engine_type)
[0b12abb5]1369        ## set the select all check box to the a given state
1370        self.cb1.SetValue(state.cb1)
1371     
1372        ## reset state of checkbox,textcrtl  and  regular parameters value
1373        self._reset_parameters_state(self.orientation_params_disp,
1374                                     state.orientation_params_disp)
1375        self._reset_parameters_state(self.orientation_params,
1376                                     state.orientation_params)
[fb59ed9]1377        self._reset_parameters_state(self.str_parameters,
1378                                     state.str_parameters)
[ef26c83]1379        self._reset_parameters_state(self.parameters, state.parameters)
1380        ## display dispersion info layer
[0b12abb5]1381        self.enable_disp.SetValue(state.enable_disp)
1382        self.disable_disp.SetValue(state.disable_disp)
[2296316]1383        # If the polydispersion is ON
1384        if state.enable_disp:
1385            # reset dispersion according the state
[0b12abb5]1386            self._set_dipers_Param(event=None)
[2296316]1387            self._reset_page_disp_helper(state)
[ef26c83]1388        ##plotting range restore
[0b12abb5]1389        self._reset_plotting_range(state)
1390        ## smearing info  restore
1391        if hasattr(self, "enable_smearer"):
[ef26c83]1392            ## set smearing value whether or not the data
[4a7ad5f]1393            #contain the smearing info
[0b12abb5]1394            self.enable_smearer.SetValue(state.enable_smearer)
1395            self.disable_smearer.SetValue(state.disable_smearer)
[ef26c83]1396            self.onSmear(event=None)
[0b12abb5]1397        self.pinhole_smearer.SetValue(state.pinhole_smearer)
1398        self.slit_smearer.SetValue(state.slit_smearer)
[ea8283d]1399        try:
1400            self.dI_noweight.SetValue(state.dI_noweight)
1401            self.dI_didata.SetValue(state.dI_didata)
1402            self.dI_sqrdata.SetValue(state.dI_sqrdata)
1403            self.dI_idata.SetValue(state.dI_idata)
1404        except:
1405            # to support older state file formats
1406            self.dI_noweight.SetValue(False)
1407            self.dI_didata.SetValue(True)
1408            self.dI_sqrdata.SetValue(False)
1409            self.dI_idata.SetValue(False)
1410 
[0b12abb5]1411        ## we have two more options for smearing
[ef26c83]1412        if self.pinhole_smearer.GetValue():
[db8fd5b]1413            self.dx_min = state.dx_min
1414            self.dx_max = state.dx_max
1415            if self.dx_min != None:
1416                self.smear_pinhole_min.SetValue(str(self.dx_min))
1417            if self.dx_max != None:
1418                self.smear_pinhole_max.SetValue(str(self.dx_max))
[ef26c83]1419            self.onPinholeSmear(event=None)
1420        elif self.slit_smearer.GetValue():
[db8fd5b]1421            self.dxl = state.dxl
1422            self.dxw = state.dxw
1423            if self.dxl != None:
1424                self.smear_slit_height.SetValue(str(self.dxl))
1425            if self.dxw != None:
[0d795bf]1426                self.smear_slit_width.SetValue(str(self.dxw)) 
1427            else:
1428                self.smear_slit_width.SetValue('') 
[ef26c83]1429            self.onSlitSmear(event=None)
[55bb249c]1430       
[0b12abb5]1431        ## reset state of checkbox,textcrtl  and dispersity parameters value
[ef26c83]1432        self._reset_parameters_state(self.fittable_param, state.fittable_param)
1433        self._reset_parameters_state(self.fixed_param, state.fixed_param)
[0b12abb5]1434       
1435        ## draw the model with previous parameters value
1436        self._onparamEnter_helper()
[3c44c66]1437        #reset the value of chisqr when not consistent with the value computed
1438        self.tcChi.SetValue(str(self.state.tcChi))
[0b12abb5]1439        ## reset context menu items
1440        self._reset_context_menu()
[3c44c66]1441       
[0b12abb5]1442        ## set the value of the current state to the state given as parameter
[ef26c83]1443        self.state = state.clone()
[93f0a862]1444        self.state.m_name = self.m_name
[0b12abb5]1445   
[2296316]1446    def _reset_page_disp_helper(self, state):
1447        """
1448        Help to rest page for dispersions
1449        """
1450        keys = self.model.getParamList()
1451        for item in keys:
1452            if item in self.disp_list and \
[ef26c83]1453                not item in self.model.details:
[2296316]1454                self.model.details[item] = ["", None, None]
1455        #for k,v in self.state.disp_cb_dict.iteritems():
[ef26c83]1456        self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
[2296316]1457        self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
1458        self.values = copy.deepcopy(state.values)
1459        self.weights = copy.deepcopy(state.weights)
1460       
1461        for key, disp in state._disp_obj_dict.iteritems():
1462            # From saved file, disp_model can not be sent in model obj.
1463            # it will be sent as a string here, then converted to model object.
1464            if disp.__class__.__name__ == 'str':
[480fe4f]1465                disp_model = None
[0e4e554]1466                #com_str = "from sas.models.dispersion_models "
1467                com_str = "from sasmodels.weights "
[480fe4f]1468                com_str += "import %s as disp_func \ndisp_model = disp_func()"
[2296316]1469                exec com_str % disp
[f20767b]1470            else:
[2296316]1471                disp_model = disp
[ef26c83]1472            self._disp_obj_dict[key] = disp_model
[2296316]1473            param_name = key.split('.')[0]
1474            # Try to set dispersion only when available
[ef26c83]1475            # for eg., pass the orient. angles for 1D Cal
[2296316]1476            try:
1477                self.model.set_dispersion(param_name, disp_model)
1478                self.model._persistency_dict[key] = \
1479                                 [state.values, state.weights]
1480            except:
1481                pass
1482            selection = self._find_polyfunc_selection(disp_model)
1483            for list in self.fittable_param:
1484                if list[1] == key and list[7] != None:
1485                    list[7].SetSelection(selection)
[ef26c83]1486                    # For the array disp_model, set the values and weights
[2296316]1487                    if selection == 1:
[ef26c83]1488                        disp_model.set_weights(self.values[key],
1489                                               self.weights[key])
[2296316]1490                        try:
1491                            # Diables all fittable params for array
1492                            list[0].SetValue(False)
1493                            list[0].Disable()
1494                            list[2].Disable()
1495                            list[5].Disable()
1496                            list[6].Disable()
1497                        except:
1498                            pass
1499            # For array, disable all fixed params
1500            if selection == 1:
1501                for item in self.fixed_param:
1502                    if item[1].split(".")[0] == key.split(".")[0]:
1503                        # try it and pass it for the orientation for 1D
1504                        try:
1505                            item[2].Disable()
1506                        except:
1507                            pass
[5582a9f1]1508   
[2296316]1509        # Make sure the check box updated when all checked
1510        if self.cb1.GetValue():
[ef26c83]1511            self.select_all_param(None)
[2296316]1512     
[c77d859]1513    def _selectDlg(self):
1514        """
[5062bbf]1515        open a dialog file to selected the customized dispersity
[c77d859]1516        """
[ef26c83]1517        if self.parent != None:
[baf1ef3]1518            self._default_save_location = \
[ae84427]1519                        self._manager.parent.get_save_location()
[60132ef]1520        dlg = wx.FileDialog(self, "Choose a weight file",
[ef26c83]1521                                self._default_save_location, "",
[4a7ad5f]1522                                "*.*", wx.OPEN)
[c77d859]1523        path = None
1524        if dlg.ShowModal() == wx.ID_OK:
1525            path = dlg.GetPath()
1526        dlg.Destroy()
1527        return path
[5062bbf]1528
[a074145]1529    def _reset_context_menu(self):
1530        """
[5062bbf]1531        reset the context menu
[a074145]1532        """
[be1ec9f]1533        for name, _ in self.state.saved_states.iteritems():
[a074145]1534            self.number_saved_state += 1
1535            ## Add item in the context menu
1536            id = wx.NewId()
[4a7ad5f]1537            msg = 'Save model and state %g' % self.number_saved_state
1538            self.popUpMenu.Append(id, name, msg)
[a074145]1539            wx.EVT_MENU(self, id, self.onResetModel)
1540   
[0aeabc6]1541    def _reset_plotting_range(self, state):
[cfc0913]1542        """
[5062bbf]1543        Reset the plotting range to a given state
[cfc0913]1544        """
[f95301b]1545        self.qmin.SetValue(str(state.qmin))
[ef26c83]1546        self.qmax.SetValue(str(state.qmax))
[0b12abb5]1547
[240b9966]1548    def _save_typeOfmodel(self):
1549        """
[5062bbf]1550        save radiobutton containing the type model that can be selected
[240b9966]1551        """
[ea5fa58]1552        #self.state.shape_rbutton = self.shape_rbutton.GetValue()
1553        #self.state.shape_indep_rbutton = self.shape_indep_rbutton.GetValue()
1554        #self.state.struct_rbutton = self.struct_rbutton.GetValue()
1555        #self.state.plugin_rbutton = self.plugin_rbutton.GetValue()
[940aca7]1556        self.state.structurecombobox = self.structurebox.GetLabel()
[ea5fa58]1557        self.state.formfactorcombobox = self.formfactorbox.GetLabel()
1558        self.state.categorycombobox = self.categorybox.GetLabel()
[c99a6c5]1559       
[240b9966]1560        ## post state to fit panel
[ef26c83]1561        event = PageInfoEvent(page=self)
[240b9966]1562        wx.PostEvent(self.parent, event)
[3595309d]1563       
[ef26c83]1564    def _save_plotting_range(self):
[cfc0913]1565        """
[ef26c83]1566        save the state of plotting range
[cfc0913]1567        """
[b787e68c]1568        self.state.qmin = self.qmin_x
[ef26c83]1569        self.state.qmax = self.qmax_x
[6bbeacd4]1570        self.state.npts = self.npts_x
[cfc0913]1571           
[c77d859]1572    def _onparamEnter_helper(self):
1573        """
[ef26c83]1574        check if values entered by the user are changed and valid to replot
[5062bbf]1575        model
[c77d859]1576        """
[ef26c83]1577        # Flag to register when a parameter has changed.
[7975f2b]1578        is_modified = False
[4a7ad5f]1579        self.fitrange = True
[51a71a3]1580        is_2Ddata = False
[3a37fe0]1581        #self._undo.Enable(True)
[51a71a3]1582        # check if 2d data
[4a7ad5f]1583        if self.data.__class__.__name__ == "Data2D":
[51a71a3]1584            is_2Ddata = True
[ef26c83]1585        if self.model != None:
[edd166b]1586            try:
[4a7ad5f]1587                is_modified = self._check_value_enter(self.fittable_param,
1588                                                     is_modified)
1589                is_modified = self._check_value_enter(self.fixed_param,
1590                                                      is_modified)
1591                is_modified = self._check_value_enter(self.parameters,
[ef26c83]1592                                                      is_modified)
[edd166b]1593            except:
1594                pass
[c99a6c5]1595
[c77d859]1596            # Here we should check whether the boundaries have been modified.
[ef26c83]1597            # If qmin and qmax have been modified, update qmin and qmax and
[c77d859]1598            # set the is_modified flag to True
[f95301b]1599            if self._validate_qrange(self.qmin, self.qmax):
1600                tempmin = float(self.qmin.GetValue())
[7975f2b]1601                if tempmin != self.qmin_x:
1602                    self.qmin_x = tempmin
[c77d859]1603                    is_modified = True
[7975f2b]1604                tempmax = float(self.qmax.GetValue())
1605                if tempmax != self.qmax_x:
1606                    self.qmax_x = tempmax
[c77d859]1607                    is_modified = True
[b787e68c]1608           
[51a71a3]1609                if is_2Ddata:
[ef26c83]1610                    # set mask
[51a71a3]1611                    is_modified = self._validate_Npts()
[247cb58]1612                   
[51a71a3]1613            else:
[ef26c83]1614                self.fitrange = False
[d2c4c06]1615               
1616            if not self.data.is_data:
1617                is_modified = True
1618
[c77d859]1619            ## if any value is modify draw model with new value
[51a71a3]1620            if not self.fitrange:
[247cb58]1621                #self.btFit.Disable()
[ef26c83]1622                if is_2Ddata:
1623                    self.btEditMask.Disable()
[51a71a3]1624            else:
[ef26c83]1625                if is_2Ddata and self.data.is_data and not self.batch_on:
[054f004]1626                    self.btEditMask.Enable(True)
[51a71a3]1627            if is_modified and self.fitrange:
[ecf26e1]1628                # Theory case: need to get npts value to draw
1629                self.npts_x = float(self.Npts_total.GetValue())
1630                self.create_default_data()
[ef26c83]1631                self.state_change = True
1632                self._draw_model()
[7975f2b]1633                self.Refresh()
1634        return is_modified
1635   
[35c9d31]1636    def _update_paramv_on_fit(self):
1637        """
[5062bbf]1638        make sure that update param values just before the fitting
[35c9d31]1639        """
1640        #flag for qmin qmax check values
[7609f1a]1641        flag = True
[51a71a3]1642        self.fitrange = True
[35c9d31]1643        is_modified = False
[51a71a3]1644
[66ff250]1645        #wx.PostEvent(self._manager.parent, StatusEvent(status=" \
1646        #updating ... ",type="update"))
[4fbc93e]1647
[35c9d31]1648        ##So make sure that update param values on_Fit.
1649        #self._undo.Enable(True)
[ef26c83]1650        if self.model != None:
[33477fd]1651            if self.Npts_total.GetValue() != self.Npts_fit.GetValue():
1652                if not self.data.is_data:
1653                    self._manager.page_finder[self.uid].set_fit_data(data=\
[ef26c83]1654                                                                [self.data])
[35c9d31]1655            ##Check the values
[ef26c83]1656            self._check_value_enter(self.fittable_param, is_modified)
1657            self._check_value_enter(self.fixed_param, is_modified)
1658            self._check_value_enter(self.parameters, is_modified)
[35c9d31]1659
1660            # If qmin and qmax have been modified, update qmin and qmax and
[ef26c83]1661            # Here we should check whether the boundaries have been modified.
[7975f2b]1662            # If qmin and qmax have been modified, update qmin and qmax and
1663            # set the is_modified flag to True
[f95301b]1664            self.fitrange = self._validate_qrange(self.qmin, self.qmax)
[51a71a3]1665            if self.fitrange:
[f95301b]1666                tempmin = float(self.qmin.GetValue())
[7975f2b]1667                if tempmin != self.qmin_x:
1668                    self.qmin_x = tempmin
1669                tempmax = float(self.qmax.GetValue())
1670                if tempmax != self.qmax_x:
1671                    self.qmax_x = tempmax
[7609f1a]1672                if tempmax == tempmin:
[ef26c83]1673                    flag = False
[7609f1a]1674                temp_smearer = None
1675                if not self.disable_smearer.GetValue():
[ef26c83]1676                    temp_smearer = self.current_smearer
[7609f1a]1677                    if self.slit_smearer.GetValue():
1678                        flag = self.update_slit_smear()
1679                    elif self.pinhole_smearer.GetValue():
1680                        flag = self.update_pinhole_smear()
1681                    else:
[6bbeacd4]1682                        self._manager.set_smearer(smearer=temp_smearer,
[66ff250]1683                                                  uid=self.uid,
[ecf26e1]1684                                                  fid=self.data.id,
[ef26c83]1685                                                  qmin=float(self.qmin_x),
1686                                                  qmax=float(self.qmax_x),
[ecf26e1]1687                            enable_smearer=not self.disable_smearer.GetValue(),
[6bbeacd4]1688                                                      draw=False)
[4fbc93e]1689                elif not self._is_2D():
[3cd5806]1690                    self._manager.set_smearer(smearer=temp_smearer,
[4a7ad5f]1691                                              qmin=float(self.qmin_x),
[ef26c83]1692                                              uid=self.uid,
[ecf26e1]1693                                              fid=self.data.id,
[ef26c83]1694                                              qmax=float(self.qmax_x),
[ecf26e1]1695                            enable_smearer=not self.disable_smearer.GetValue(),
[18e430a]1696                                                 draw=False)
[0cf97c5]1697                    if self.data != None:
[ef26c83]1698                        index_data = ((self.qmin_x <= self.data.x) & \
[0cf97c5]1699                                      (self.data.x <= self.qmax_x))
[ef26c83]1700                        val = str(len(self.data.x[index_data == True]))
[0cf97c5]1701                        self.Npts_fit.SetValue(val)
1702                    else:
1703                        # No data in the panel
1704                        try:
1705                            self.npts_x = float(self.Npts_total.GetValue())
1706                        except:
1707                            flag = False
1708                            return flag
[51a71a3]1709                    flag = True
[4fbc93e]1710                if self._is_2D():
[ef26c83]1711                    # only 2D case set mask
[51a71a3]1712                    flag = self._validate_Npts()
1713                    if not flag:
1714                        return flag
[ef26c83]1715            else:
1716                flag = False
1717        else:
[7975f2b]1718            flag = False
[51a71a3]1719
[ef26c83]1720        #For invalid q range, disable the mask editor and fit button, vs.
[51a71a3]1721        if not self.fitrange:
[55a3257]1722            if self._is_2D():
1723                self.btEditMask.Disable()
[51a71a3]1724        else:
[33477fd]1725            if self._is_2D() and  self.data.is_data and not self.batch_on:
[55a3257]1726                self.btEditMask.Enable(True)
[51a71a3]1727
[7609f1a]1728        if not flag:
[4a7ad5f]1729            msg = "Cannot Plot or Fit :Must select a "
1730            msg += " model or Fitting range is not valid!!!  "
[ae84427]1731            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[51a71a3]1732       
[33477fd]1733        try:
1734            self.save_current_state()
1735        except:
1736            pass
[4470b10]1737   
[ef26c83]1738        return flag
[acd0bda3]1739               
[c99a6c5]1740    def _is_modified(self, is_modified):
[acd0bda3]1741        """
[5062bbf]1742        return to self._is_modified
[acd0bda3]1743        """
[c99a6c5]1744        return is_modified
[acd0bda3]1745                       
[4a7ad5f]1746    def _reset_parameters_state(self, listtorestore, statelist):
[cfc0913]1747        """
[5062bbf]1748        Reset the parameters at the given state
[cfc0913]1749        """
[4a7ad5f]1750        if len(statelist) == 0 or len(listtorestore) == 0:
[6999659]1751            return
[ef26c83]1752        if len(statelist) != len(listtorestore):
[cfc0913]1753            return
[c99a6c5]1754
[cfc0913]1755        for j in range(len(listtorestore)):
1756            item_page = listtorestore[j]
1757            item_page_info = statelist[j]
1758            ##change the state of the check box for simple parameters
[ef26c83]1759            if item_page[0] != None:
[cfc0913]1760                item_page[0].SetValue(item_page_info[0])
[ef26c83]1761            if item_page[2] != None:
[cfc0913]1762                item_page[2].SetValue(item_page_info[2])
[2296316]1763                if item_page[2].__class__.__name__ == "ComboBox":
[ef26c83]1764                    if item_page_info[2] in self.model.fun_list:
1765                        fun_val = self.model.fun_list[item_page_info[2]]
1766                        self.model.setParam(item_page_info[1], fun_val)
1767            if item_page[3] != None:
[cfc0913]1768                ## show or hide text +/-
1769                if item_page_info[2]:
1770                    item_page[3].Show(True)
1771                else:
1772                    item_page[3].Hide()
[ef26c83]1773            if item_page[4] != None:
[cfc0913]1774                ## show of hide the text crtl for fitting error
1775                if item_page_info[4][0]:
1776                    item_page[4].Show(True)
1777                    item_page[4].SetValue(item_page_info[4][1])
1778                else:
1779                    item_page[3].Hide()
[ef26c83]1780            if item_page[5] != None:
[cfc0913]1781                ## show of hide the text crtl for fitting error
[2296316]1782                item_page[5].Show(item_page_info[5][0])
1783                item_page[5].SetValue(item_page_info[5][1])
1784               
[ef26c83]1785            if item_page[6] != None:
[cfc0913]1786                ## show of hide the text crtl for fitting error
[2296316]1787                item_page[6].Show(item_page_info[6][0])
1788                item_page[6].SetValue(item_page_info[6][1])
1789                   
1790    def _reset_strparam_state(self, listtorestore, statelist):
1791        """
1792        Reset the string parameters at the given state
1793        """
1794        if len(statelist) == 0:
1795            return
1796
1797        listtorestore = copy.deepcopy(statelist)
1798       
1799        for j in range(len(listtorestore)):
1800            item_page = listtorestore[j]
1801            item_page_info = statelist[j]
1802            ##change the state of the check box for simple parameters
1803           
[ef26c83]1804            if item_page[0] != None:
[2296316]1805                item_page[0].SetValue(format_number(item_page_info[0], True))
1806
1807            if item_page[2] != None:
1808                param_name = item_page_info[1]
1809                value = item_page_info[2]
1810                selection = value
[ef26c83]1811                if value in self.model.fun_list:
[2296316]1812                    selection = self.model.fun_list[value]
1813                item_page[2].SetValue(selection)
1814                self.model.setParam(param_name, selection)
[5062bbf]1815                                     
[cfc0913]1816    def _copy_parameters_state(self, listtocopy, statelist):
1817        """
[ef26c83]1818        copy the state of button
[5062bbf]1819       
1820        :param listtocopy: the list of check button to copy
1821        :param statelist: list of state object to store the current state
1822       
[cfc0913]1823        """
[ef26c83]1824        if len(listtocopy) == 0:
[cfc0913]1825            return
[1c1436d]1826       
[cfc0913]1827        for item in listtocopy:
[f20767b]1828 
[cfc0913]1829            checkbox_state = None
[ef26c83]1830            if item[0] != None:
1831                checkbox_state = item[0].GetValue()
[cfc0913]1832            parameter_name = item[1]
1833            parameter_value = None
[ef26c83]1834            if item[2] != None:
[cfc0913]1835                parameter_value = item[2].GetValue()
1836            static_text = None
[ef26c83]1837            if item[3] != None:
[cfc0913]1838                static_text = item[3].IsShown()
1839            error_value = None
1840            error_state = None
[ef26c83]1841            if item[4] != None:
[cfc0913]1842                error_value = item[4].GetValue()
1843                error_state = item[4].IsShown()
1844               
1845            min_value = None
1846            min_state = None
[ef26c83]1847            if item[5] != None:
[cfc0913]1848                min_value = item[5].GetValue()
1849                min_state = item[5].IsShown()
1850               
1851            max_value = None
1852            max_state = None
[ef26c83]1853            if item[6] != None:
[cfc0913]1854                max_value = item[6].GetValue()
1855                max_state = item[6].IsShown()
[ef26c83]1856            unit = None
1857            if item[7] != None:
[240b9966]1858                unit = item[7].GetLabel()
[cfc0913]1859               
1860            statelist.append([checkbox_state, parameter_name, parameter_value,
[ef26c83]1861                              static_text, [error_state, error_value],
1862                              [min_state, min_value],
1863                              [max_state, max_value], unit])
[cfc0913]1864           
[116e1a7]1865#    The following funcion seems to be superseded with fillsizer and
1866#    init combo box.  certainly it seems not to know about categories and uses
1867#    only shapes and shape independent -- tested after commenting out and does
1868#    not seem to cause problem.  Leave commented out for now but delete in
1869#    a code cleanup once clear it really is no longer used.
1870#    PDB  8 April 2014
1871
1872#    def _set_model_sizer_selection(self, model):
1873#        """
1874#        Display the sizer according to the type of the current model
1875#        """
1876#        if model == None:
1877#            return
1878#        if hasattr(model, "s_model"):
1879#           
1880#            class_name = model.s_model.__class__
1881#            name = model.s_model.name
1882#            flag = (name != "NoStructure")
1883#            if flag and \
1884#                (class_name in self.model_list_box["Structure Factors"]):
1885#                self.structurebox.Show()
1886#                self.text2.Show()
1887#                self.structurebox.Enable()
1888#               self.text2.Enable()
1889 #               items = self.structurebox.GetItems()
1890 #               self.sizer1.Layout()
1891 #               
1892 #               for i in range(len(items)):
1893 #                   if items[i] == str(name):
1894 #                       self.structurebox.SetSelection(i)
1895 #                       break
1896 #                   
1897 #       if hasattr(model, "p_model"):
1898 #           class_name = model.p_model.__class__
1899 #           name = model.p_model.name
1900 #           self.formfactorbox.Clear()
1901 #           
1902 #           for k, list in self.model_list_box.iteritems():
1903 #               if k in["P(Q)*S(Q)", "Shapes"] and \
1904 #                   class_name in self.model_list_box["Shapes"]:
1905 #                   self.shape_rbutton.SetValue(True)
1906 #                   ## fill the form factor list with new model
1907 #                   self._populate_box(self.formfactorbox,
1908 #                                      self.model_list_box["Shapes"])
1909 #                   items = self.formfactorbox.GetItems()
1910 #                   ## set comboxbox to the selected item
1911 #                   for i in range(len(items)):
1912 #                       if items[i] == str(name):
1913 #                           self.formfactorbox.SetSelection(i)
1914 #                           break
1915 #                   return
1916 #               elif k == "Shape-Independent":
1917 #                   self.shape_indep_rbutton.SetValue(True)
1918 #               elif k == "Structure Factors":
1919 #                   self.struct_rbutton.SetValue(True)
1920 #               elif k == "Multi-Functions":
1921 #                   continue
1922 #               else:
1923 #                   self.plugin_rbutton.SetValue(True)
1924 #             
1925 #               if class_name in list:
1926 #                   ## fill the form factor list with new model
1927 #                   self._populate_box(self.formfactorbox, list)
1928 #                   items = self.formfactorbox.GetItems()
1929 #                   ## set comboxbox to the selected item
1930 #                   for i in range(len(items)):
1931 #                       if items[i] == str(name):
1932 #                           self.formfactorbox.SetSelection(i)
1933 #                           break
1934 #                   break
1935 #       else:
[cdbe88e]1936            ## Select the model from the menu
[116e1a7]1937#            class_name = model.__class__
1938#            name = model.name
1939#            self.formfactorbox.Clear()
1940#            items = self.formfactorbox.GetItems()
1941#   
1942#            for k, list in self.model_list_box.iteritems():
1943#                if k in["P(Q)*S(Q)", "Shapes"] and \
1944#                    class_name in self.model_list_box["Shapes"]:
1945#                    if class_name in self.model_list_box["P(Q)*S(Q)"]:
1946#                        self.structurebox.Show()
1947#                        self.text2.Show()
1948#                       self.structurebox.Enable()
1949#                       self.structurebox.SetSelection(0)
1950#                       self.text2.Enable()
1951#                   else:
1952#                        self.structurebox.Hide()
1953#                        self.text2.Hide()
1954#                        self.structurebox.Disable()
1955#                        self.structurebox.SetSelection(0)
1956#                        self.text2.Disable()
1957#                       
1958#                    self.shape_rbutton.SetValue(True)
[376916c]1959                    ## fill the form factor list with new model
[116e1a7]1960#                    self._populate_box(self.formfactorbox,
1961#                                       self.model_list_box["Shapes"])
1962#                    items = self.formfactorbox.GetItems()
1963#                    ## set comboxbox to the selected item
1964#                    for i in range(len(items)):
1965#                        if items[i] == str(name):
1966#                            self.formfactorbox.SetSelection(i)
1967#                            break
1968#                    return
1969#                elif k == "Shape-Independent":
1970#                    self.shape_indep_rbutton.SetValue(True)
1971#                elif k == "Structure Factors":
1972#                    self.struct_rbutton.SetValue(True)
1973#                elif k == "Multi-Functions":
1974#                    continue
1975#                else:
1976#                    self.plugin_rbutton.SetValue(True)
1977#                if class_name in list:
1978#                    self.structurebox.SetSelection(0)
1979#                    self.structurebox.Disable()
1980#                    self.text2.Disable()
[376916c]1981                    ## fill the form factor list with new model
[116e1a7]1982#                    self._populate_box(self.formfactorbox, list)
1983#                    items = self.formfactorbox.GetItems()
[c77d859]1984                    ## set comboxbox to the selected item
[116e1a7]1985#                    for i in range(len(items)):
1986#                        if items[i] == str(name):
1987#                            self.formfactorbox.SetSelection(i)
1988#                            break
1989#                    break
[7fd4afd]1990               
[e3f6ef5]1991    def _draw_model(self, update_chisqr=True, source='model'):
[c77d859]1992        """
[5062bbf]1993        Method to draw or refresh a plotted model.
1994        The method will use the data member from the model page
1995        to build a call to the fitting perspective manager.
[2296316]1996       
1997        :param chisqr: update chisqr value [bool]
[c77d859]1998        """
[7fd4afd]1999        wx.CallAfter(self._draw_model_after, update_chisqr, source)
2000       
2001    def _draw_model_after(self, update_chisqr=True, source='model'):
2002        """
2003        Method to draw or refresh a plotted model.
2004        The method will use the data member from the model page
2005        to build a call to the fitting perspective manager.
2006       
2007        :param chisqr: update chisqr value [bool]
2008        """
[6bbeacd4]2009        #if self.check_invalid_panel():
2010        #    return
[ef26c83]2011        if self.model != None:
2012            temp_smear = None
[fca9cbd9]2013            if hasattr(self, "enable_smearer"):
[7609f1a]2014                if not self.disable_smearer.GetValue():
[ef26c83]2015                    temp_smear = self.current_smearer
[f7ef313]2016            # compute weight for the current data
[b9a5f0e]2017            from sas.perspectives.fitting.utils import get_weight
[f7ef313]2018            flag = self.get_weight_flag()
2019            weight = get_weight(data=self.data, is2d=self._is_2D(), flag=flag)
[fa65e99]2020            toggle_mode_on = self.model_view.IsEnabled()
[01642fec]2021            is_2d = self._is_2D()
[ef26c83]2022            self._manager.draw_model(self.model,
[f72333f]2023                                    data=self.data,
[ef26c83]2024                                    smearer=temp_smear,
2025                                    qmin=float(self.qmin_x),
[484faf7]2026                                    qmax=float(self.qmax_x),
[66ff250]2027                                    page_id=self.uid,
[ef26c83]2028                                    toggle_mode_on=toggle_mode_on,
2029                                    state=self.state,
[01642fec]2030                                    enable2D=is_2d,
[55bb249c]2031                                    update_chisqr=update_chisqr,
[e3f6ef5]2032                                    source='model',
[55bb249c]2033                                    weight=weight)
[0b477f6]2034       
[a1b2471]2035    def _on_show_sld(self, event=None):
2036        """
2037        Plot SLD profile
2038        """
2039        # get profile data
[ef26c83]2040        x, y = self.model.getProfile()
[a1b2471]2041
[79492222]2042        from sas.plottools import Data1D as pf_data1d
2043        #from sas.perspectives.theory.profile_dialog import SLDPanel
2044        from sas.guiframe.local_perspectives.plotting.profile_dialog \
[da9ac4e6]2045        import SLDPanel
[be1ec9f]2046        sld_data = pf_data1d(x, y)
[a1b2471]2047        sld_data.name = 'SLD'
[fb59ed9]2048        sld_data.axes = self.sld_axes
[ef26c83]2049        self.panel = SLDPanel(self, data=sld_data, axes=self.sld_axes, id=-1)
2050        self.panel.ShowModal()
[a1b2471]2051       
[ef26c83]2052    def _set_multfactor_combobox(self, multiplicity=10):
[4523b68]2053        """
2054        Set comboBox for muitfactor of CoreMultiShellModel
[fb59ed9]2055        :param multiplicit: no. of multi-functionality
[4523b68]2056        """
[fb59ed9]2057        # build content of the combobox
[ef26c83]2058        for idx in range(0, multiplicity):
2059            self.multifactorbox.Append(str(idx), int(idx))
[4523b68]2060        self._hide_multfactor_combobox()
2061       
[ef26c83]2062    def _show_multfactor_combobox(self):
[4523b68]2063        """
2064        Show the comboBox of muitfactor of CoreMultiShellModel
[ef26c83]2065        """
[4523b68]2066        if not self.mutifactor_text.IsShown():
2067            self.mutifactor_text.Show(True)
[fb59ed9]2068            self.mutifactor_text1.Show(True)
[4523b68]2069        if not self.multifactorbox.IsShown():
[ef26c83]2070            self.multifactorbox.Show(True)
[4523b68]2071             
[ef26c83]2072    def _hide_multfactor_combobox(self):
[4523b68]2073        """
2074        Hide the comboBox of muitfactor of CoreMultiShellModel
[ef26c83]2075        """
[4523b68]2076        if self.mutifactor_text.IsShown():
2077            self.mutifactor_text.Hide()
[fb59ed9]2078            self.mutifactor_text1.Hide()
[4523b68]2079        if self.multifactorbox.IsShown():
[ef26c83]2080            self.multifactorbox.Hide()
[ea5fa58]2081   
2082    def formfactor_combo_init(self):
2083        """
2084        First time calls _show_combox_helper
2085        """
2086        self._show_combox(None)
2087               
[0b12abb5]2088    def _show_combox_helper(self):
[c77d859]2089        """
[0b12abb5]2090        Fill panel's combo box according to the type of model selected
[c77d859]2091        """
[ea5fa58]2092        custom_model = 'Customized Models'
2093        mod_cat = self.categorybox.GetStringSelection()
2094        self.structurebox.SetSelection(0)
2095        self.structurebox.Disable()
2096        self.formfactorbox.Clear()
2097        if mod_cat == None:
2098            return
2099        m_list = []
2100        try:
2101            if mod_cat == custom_model:
2102                for model in self.model_list_box[mod_cat]:
2103                    str_m = str(model).split(".")[0]
2104                    #self.model_box.Append(str_m)
2105                    m_list.append(self.model_dict[str_m])
2106            else:
[ae4c139]2107                cat_dic = self.master_category_dict[mod_cat]
2108                for (model, enabled) in cat_dic:
[ea5fa58]2109                    if enabled:
2110                        m_list.append(self.model_dict[model])
[ae4c139]2111                    #else:
2112                    #    msg = "This model is disabled by Category Manager."
2113                    #    wx.PostEvent(self.parent.parent,
2114                    #                 StatusEvent(status=msg, info="error"))
[ea5fa58]2115        except:
2116            msg = "%s\n" % (sys.exc_value)
[ae84427]2117            wx.PostEvent(self._manager.parent,
[ea5fa58]2118                         StatusEvent(status=msg, info="error"))
2119        self._populate_box(self.formfactorbox, m_list)
[ef67145]2120   
2121    def _on_modify_cat(self, event=None): 
2122        self._manager.parent.on_category_panel(event) 
[3595309d]2123       
[0b12abb5]2124    def _show_combox(self, event=None):
2125        """
2126        Show combox box associate with type of model selected
2127        """
[dbbdf11]2128        self.Show(False)
[0b12abb5]2129        self._show_combox_helper()
[77e23a2]2130        self._on_select_model(event=None)
[dbbdf11]2131        self.Show(True)
[3595309d]2132        self._save_typeOfmodel()
[3b605bb]2133        self.sizer4_4.Layout()
[9853ad0]2134        self.sizer4.Layout()
[3b605bb]2135        self.Layout()
2136        self.Refresh()
[340c2b3]2137 
[ea5fa58]2138    def _populate_box(self, combobox, list):
[c77d859]2139        """
[5062bbf]2140        fill combox box with dict item
2141       
2142        :param list: contains item to fill the combox
[c77d859]2143            item must model class
2144        """
[f74673c]2145        mlist = []
[ea5fa58]2146        for models in list:
[ef26c83]2147            model = models()
[c77d859]2148            name = model.__class__.__name__
[ef26c83]2149            if models.__name__ != "NoStructure":
[0a518e4c]2150                if hasattr(model, "name"):
2151                    name = model.name
[ef26c83]2152                mlist.append((name, models))
[f74673c]2153               
2154        # Sort the models
[8df5faa]2155        mlist_sorted = sorted(mlist)
[f74673c]2156        for item in mlist_sorted:
[ef26c83]2157            combobox.Append(item[0], item[1])
[c77d859]2158        return 0
[6bbeacd4]2159   
[6e9976b]2160    def _onQrangeEnter(self, event):
2161        """
[5062bbf]2162        Check validity of value enter in the Q range field
[6bbeacd4]2163       
2164        """
2165        tcrtl = event.GetEventObject()
2166        #Clear msg if previously shown.
2167        msg = ""
2168        wx.PostEvent(self.parent, StatusEvent(status=msg))
2169        # Flag to register when a parameter has changed.
[be1ec9f]2170        #is_modified = False
[6bbeacd4]2171        if tcrtl.GetValue().lstrip().rstrip() != "":
2172            try:
[be1ec9f]2173                float(tcrtl.GetValue())
[6bbeacd4]2174                tcrtl.SetBackgroundColour(wx.WHITE)
2175                # If qmin and qmax have been modified, update qmin and qmax
[f95301b]2176                if self._validate_qrange(self.qmin, self.qmax):
2177                    tempmin = float(self.qmin.GetValue())
[6bbeacd4]2178                    if tempmin != self.qmin_x:
2179                        self.qmin_x = tempmin
2180                    tempmax = float(self.qmax.GetValue())
2181                    if tempmax != self.qmax_x:
2182                        self.qmax_x = tempmax
2183                else:
2184                    tcrtl.SetBackgroundColour("pink")
[6fe5100]2185                    msg = "Model Error: wrong value entered: %s" % sys.exc_value
[6bbeacd4]2186                    wx.PostEvent(self.parent, StatusEvent(status=msg))
[ef26c83]2187                    return
[6bbeacd4]2188            except:
2189                tcrtl.SetBackgroundColour("pink")
[6fe5100]2190                msg = "Model Error: wrong value entered: %s" % sys.exc_value
[6bbeacd4]2191                wx.PostEvent(self.parent, StatusEvent(status=msg))
[ef26c83]2192                return
[6bbeacd4]2193            #Check if # of points for theory model are valid(>0).
2194            if self.npts != None:
2195                if check_float(self.npts):
2196                    temp_npts = float(self.npts.GetValue())
[ef26c83]2197                    if temp_npts != self.num_points:
[6bbeacd4]2198                        self.num_points = temp_npts
[be1ec9f]2199                        #is_modified = True
[6bbeacd4]2200                else:
[6fe5100]2201                    msg = "Cannot plot: No points in Q range!!!  "
[6bbeacd4]2202                    wx.PostEvent(self.parent, StatusEvent(status=msg))
2203        else:
[ef26c83]2204            tcrtl.SetBackgroundColour("pink")
[6fe5100]2205            msg = "Model Error: wrong value entered!!!"
[ef26c83]2206            wx.PostEvent(self.parent, StatusEvent(status=msg))
[6bbeacd4]2207        self.save_current_state()
2208        event = PageInfoEvent(page=self)
2209        wx.PostEvent(self.parent, event)
2210        self.state_change = False
2211        #Draw the model for a different range
[b582d6bc]2212        if not self.data.is_data:
2213            self.create_default_data()
[6bbeacd4]2214        self._draw_model()
2215                   
2216    def _theory_qrange_enter(self, event):
2217        """
2218        Check validity of value enter in the Q range field
[6e9976b]2219        """
2220       
[ef26c83]2221        tcrtl = event.GetEventObject()
[6e9976b]2222        #Clear msg if previously shown.
[ef26c83]2223        msg = ""
[ae84427]2224        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[6e9976b]2225        # Flag to register when a parameter has changed.
2226        is_modified = False
[ef26c83]2227        if tcrtl.GetValue().lstrip().rstrip() != "":
[6e9976b]2228            try:
2229                value = float(tcrtl.GetValue())
2230                tcrtl.SetBackgroundColour(wx.WHITE)
2231
2232                # If qmin and qmax have been modified, update qmin and qmax
[6bbeacd4]2233                if self._validate_qrange(self.theory_qmin, self.theory_qmax):
2234                    tempmin = float(self.theory_qmin.GetValue())
2235                    if tempmin != self.theory_qmin_x:
2236                        self.theory_qmin_x = tempmin
2237                    tempmax = float(self.theory_qmax.GetValue())
[6e9976b]2238                    if tempmax != self.qmax_x:
[6bbeacd4]2239                        self.theory_qmax_x = tempmax
[6e9976b]2240                else:
2241                    tcrtl.SetBackgroundColour("pink")
[6fe5100]2242                    msg = "Model Error: wrong value entered: %s" % sys.exc_value
[ef26c83]2243                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2244                    return
[6e9976b]2245            except:
2246                tcrtl.SetBackgroundColour("pink")
[6fe5100]2247                msg = "Model Error: wrong value entered: %s" % sys.exc_value
[ef26c83]2248                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2249                return
[6e9976b]2250            #Check if # of points for theory model are valid(>0).
[ef26c83]2251            if self.Npts_total.IsEditable():
[0cf97c5]2252                if check_float(self.Npts_total):
2253                    temp_npts = float(self.Npts_total.GetValue())
[ef26c83]2254                    if temp_npts != self.num_points:
[6e9976b]2255                        self.num_points = temp_npts
2256                        is_modified = True
2257                else:
[6fe5100]2258                    msg = "Cannot Plot: No points in Q range!!!  "
[ae84427]2259                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[6e9976b]2260        else:
[ef26c83]2261            tcrtl.SetBackgroundColour("pink")
[6fe5100]2262            msg = "Model Error: wrong value entered!!!"
[ae84427]2263            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[6e9976b]2264        self.save_current_state()
[ef26c83]2265        event = PageInfoEvent(page=self)
[6e9976b]2266        wx.PostEvent(self.parent, event)
[ef26c83]2267        self.state_change = False
[484faf7]2268        #Draw the model for a different range
[ecf26e1]2269        self.create_default_data()
[484faf7]2270        self._draw_model()
[6e9976b]2271                   
[ef26c83]2272    def _on_select_model_helper(self):
[c77d859]2273        """
[5062bbf]2274        call back for model selection
[c77d859]2275        """
[376916c]2276        ## reset dictionary containing reference to dispersion
2277        self._disp_obj_dict = {}
[ef26c83]2278        self.disp_cb_dict = {}
[8960479]2279        self.temp_multi_functional = False
[ea5fa58]2280        f_id = self.formfactorbox.GetCurrentSelection()
2281        #For MAC
2282        form_factor = None
2283        if f_id >= 0:
2284            form_factor = self.formfactorbox.GetClientData(f_id)
[9170547]2285
[376916c]2286        if not form_factor in  self.model_list_box["multiplication"]:
[6dc9ad8]2287            self.structurebox.Hide()
[ef26c83]2288            self.text2.Hide()
[3b605bb]2289            self.structurebox.Disable()
2290            self.structurebox.SetSelection(0)
[c097f02]2291            self.text2.Disable()
[87fbc60]2292        else:
[6dc9ad8]2293            self.structurebox.Show()
2294            self.text2.Show()
[87fbc60]2295            self.structurebox.Enable()
[c097f02]2296            self.text2.Enable()
[4523b68]2297           
[ef26c83]2298        if form_factor != None:
2299            # set multifactor for Mutifunctional models
[be1ec9f]2300            if form_factor().__class__ in \
2301                                        self.model_list_box["Multi-Functions"]:
[4523b68]2302                m_id = self.multifactorbox.GetCurrentSelection()
[fb59ed9]2303                multiplicity = form_factor().multiplicity_info[0]
2304                self.multifactorbox.Clear()
2305                self._set_multfactor_combobox(multiplicity)
2306                self._show_multfactor_combobox()
[ef26c83]2307                #ToDo:  this info should be called directly from the model
2308                text = form_factor().multiplicity_info[1]  # 'No. of Shells: '
[fb59ed9]2309
2310                self.mutifactor_text.SetLabel(text)
[ef26c83]2311                if m_id > multiplicity - 1:
[fb59ed9]2312                    # default value
2313                    m_id = 1
2314                   
[4523b68]2315                self.multi_factor = self.multifactorbox.GetClientData(m_id)
[ef26c83]2316                if self.multi_factor == None:
2317                    self.multi_factor = 0
[4523b68]2318                form_factor = form_factor(int(self.multi_factor))
[fb59ed9]2319                self.multifactorbox.SetSelection(m_id)
2320                # Check len of the text1 and max_multiplicity
2321                text = ''
[be1ec9f]2322                if form_factor.multiplicity_info[0] == \
2323                                        len(form_factor.multiplicity_info[2]):
[fb59ed9]2324                    text = form_factor.multiplicity_info[2][self.multi_factor]
2325                self.mutifactor_text1.SetLabel(text)
2326                # Check if model has  get sld profile.
2327                if len(form_factor.multiplicity_info[3]) > 0:
2328                    self.sld_axes = form_factor.multiplicity_info[3]
2329                    self.show_sld_button.Show(True)
2330                else:
2331                    self.sld_axes = ""
2332
[4523b68]2333            else:
2334                self._hide_multfactor_combobox()
[a1b2471]2335                self.show_sld_button.Hide()
[4523b68]2336                form_factor = form_factor()
2337                self.multi_factor = None
2338        else:
2339            self._hide_multfactor_combobox()
[a1b2471]2340            self.show_sld_button.Hide()
[ef26c83]2341            self.multi_factor = None
[4523b68]2342             
[3b605bb]2343        s_id = self.structurebox.GetCurrentSelection()
[ef26c83]2344        struct_factor = self.structurebox.GetClientData(s_id)
[4523b68]2345       
[ef26c83]2346        if  struct_factor != None:
[79492222]2347            from sas.models.MultiplicationModel import MultiplicationModel
[ef26c83]2348            self.model = MultiplicationModel(form_factor, struct_factor())
[8960479]2349            # multifunctional form factor
2350            if len(form_factor.non_fittable) > 0:
2351                self.temp_multi_functional = True
[c77d859]2352        else:
[fbf4bf8]2353            if form_factor != None:
[ef26c83]2354                self.model = form_factor
[fbf4bf8]2355            else:
2356                self.model = None
2357                return self.model
[318b5bbb]2358        # check if model has magnetic parameters
2359        if len(self.model.magnetic_params) > 0:
2360            self._has_magnetic = True 
2361        else:
2362            self._has_magnetic = False 
[cfc0913]2363        ## post state to fit panel
[ef26c83]2364        self.state.parameters = []
2365        self.state.model = self.model
[4523b68]2366        self.state.qmin = self.qmin_x
2367        self.state.multi_factor = self.multi_factor
[ef26c83]2368        self.disp_list = self.model.getDispParamList()
[f20767b]2369        self.state.disp_list = self.disp_list
[fadf925]2370        self.on_set_focus(None)
[ef26c83]2371        self.Layout()
[c99a6c5]2372       
[85b3971]2373    def _validate_qrange(self, qmin_ctrl, qmax_ctrl):
2374        """
[5062bbf]2375        Verify that the Q range controls have valid values
2376        and that Qmin < Qmax.
2377       
2378        :param qmin_ctrl: text control for Qmin
2379        :param qmax_ctrl: text control for Qmax
2380       
[ef26c83]2381        :return: True is the Q range is value, False otherwise
[5062bbf]2382       
[85b3971]2383        """
2384        qmin_validity = check_float(qmin_ctrl)
2385        qmax_validity = check_float(qmax_ctrl)
2386        if not (qmin_validity and qmax_validity):
2387            return False
2388        else:
2389            qmin = float(qmin_ctrl.GetValue())
2390            qmax = float(qmax_ctrl.GetValue())
[e0e22f2c]2391            if qmin < qmax:
[ef26c83]2392                #Make sure to set both colours white.
[85b3971]2393                qmin_ctrl.SetBackgroundColour(wx.WHITE)
2394                qmin_ctrl.Refresh()
2395                qmax_ctrl.SetBackgroundColour(wx.WHITE)
2396                qmax_ctrl.Refresh()
2397            else:
2398                qmin_ctrl.SetBackgroundColour("pink")
2399                qmin_ctrl.Refresh()
2400                qmax_ctrl.SetBackgroundColour("pink")
2401                qmax_ctrl.Refresh()
[ef26c83]2402                msg = "Invalid Q range: Q min must be smaller than Q max"
[ae84427]2403                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[85b3971]2404                return False
2405        return True
[51a71a3]2406   
[ef26c83]2407    def _validate_Npts(self):
[51a71a3]2408        """
[5062bbf]2409        Validate the number of points for fitting is more than 10 points.
2410        If valid, setvalues Npts_fit otherwise post msg.
[51a71a3]2411        """
2412        #default flag
2413        flag = True
[1a74523]2414        # Theory
2415        if self.data == None and self.enable2D:
2416            return flag
[166f2f8]2417        for data in self.data_list:
2418            # q value from qx and qy
[ef26c83]2419            radius = numpy.sqrt(data.qx_data * data.qx_data +
2420                                data.qy_data * data.qy_data)
[166f2f8]2421            #get unmasked index
2422            index_data = (float(self.qmin.GetValue()) <= radius) & \
2423                            (radius <= float(self.qmax.GetValue()))
[ef26c83]2424            index_data = (index_data) & (data.mask)
[166f2f8]2425            index_data = (index_data) & (numpy.isfinite(data.data))
[7609f1a]2426
[166f2f8]2427            if len(index_data[index_data]) < 10:
2428                # change the color pink.
2429                self.qmin.SetBackgroundColour("pink")
2430                self.qmin.Refresh()
2431                self.qmax.SetBackgroundColour("pink")
2432                self.qmax.Refresh()
[6fe5100]2433                msg = "Data Error: "
2434                msg += "Too few points in %s." % data.name
[ae84427]2435                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[166f2f8]2436                self.fitrange = False
2437                flag = False
2438            else:
[ef26c83]2439                self.Npts_fit.SetValue(str(len(index_data[index_data == True])))
[166f2f8]2440                self.fitrange = True
[51a71a3]2441           
2442        return flag
[94078a8]2443
[ef26c83]2444    def _validate_Npts_1D(self):
[94078a8]2445        """
2446        Validate the number of points for fitting is more than 5 points.
2447        If valid, setvalues Npts_fit otherwise post msg.
2448        """
2449        #default flag
2450        flag = True
2451        # Theory
2452        if self.data == None:
2453            return flag
2454        for data in self.data_list:
2455            # q value from qx and qy
[ef26c83]2456            radius = data.x
[94078a8]2457            #get unmasked index
2458            index_data = (float(self.qmin.GetValue()) <= radius) & \
2459                            (radius <= float(self.qmax.GetValue()))
2460            index_data = (index_data) & (numpy.isfinite(data.y))
2461
2462            if len(index_data[index_data]) < 5:
2463                # change the color pink.
2464                self.qmin.SetBackgroundColour("pink")
2465                self.qmin.Refresh()
2466                self.qmax.SetBackgroundColour("pink")
2467                self.qmax.Refresh()
[6fe5100]2468                msg = "Data Error: "
2469                msg += "Too few points in %s." % data.name
[ae84427]2470                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[94078a8]2471                self.fitrange = False
2472                flag = False
2473            else:
[ef26c83]2474                self.Npts_fit.SetValue(str(len(index_data[index_data == True])))
[94078a8]2475                self.fitrange = True
2476           
2477        return flag
[51a71a3]2478   
[ea5fa58]2479    def _check_value_enter(self, list, modified):
[c77d859]2480        """
[ea5fa58]2481        :param list: model parameter and panel info
2482        :Note: each item of the list should be as follow:
[5062bbf]2483            item=[check button state, parameter's name,
[ef26c83]2484                paramater's value, string="+/-",
2485                parameter's error of fit,
2486                parameter's minimum value,
2487                parrameter's maximum value ,
[5062bbf]2488                parameter's units]
[ef26c83]2489        """
2490        is_modified = modified
[ea5fa58]2491        if len(list) == 0:
[c99a6c5]2492            return is_modified
[ea5fa58]2493        for item in list:
[edd166b]2494            #skip angle parameters for 1D
[ef26c83]2495            if not self.enable2D:
[edd166b]2496                if item in self.orientation_params:
2497                    continue
2498            #try:
2499            name = str(item[1])
2500           
[ef26c83]2501            if string.find(name, ".npts") == -1 and \
2502                                        string.find(name, ".nsigmas") == -1:
2503                ## check model parameters range
2504                param_min = None
2505                param_max = None
[7975f2b]2506               
[c985bef]2507                ## check minimun value
[ef26c83]2508                if item[5] != None and item[5] != "":
2509                    if item[5].GetValue().lstrip().rstrip() != "":
[edd166b]2510                        try:
2511                            param_min = float(item[5].GetValue())
[ef26c83]2512                            if not self._validate_qrange(item[5], item[2]):
[7975f2b]2513                                if numpy.isfinite(param_min):
2514                                    item[2].SetValue(format_number(param_min))
[6e9976b]2515                           
2516                            item[5].SetBackgroundColour(wx.WHITE)
2517                            item[2].SetBackgroundColour(wx.WHITE)
2518                                           
[edd166b]2519                        except:
[6fe5100]2520                            msg = "Wrong fit parameter range entered"
[ae84427]2521                            wx.PostEvent(self._manager.parent,
[ef26c83]2522                                         StatusEvent(status=msg))
[edd166b]2523                            raise ValueError, msg
[c985bef]2524                        is_modified = True
[77e23a2]2525                ## check maximum value
[ef26c83]2526                if item[6] != None and item[6] != "":
2527                    if item[6].GetValue().lstrip().rstrip() != "":
2528                        try:
[edd166b]2529                            param_max = float(item[6].GetValue())
[ef26c83]2530                            if not self._validate_qrange(item[2], item[6]):
[7975f2b]2531                                if numpy.isfinite(param_max):
[ef26c83]2532                                    item[2].SetValue(format_number(param_max))
[6e9976b]2533                           
2534                            item[6].SetBackgroundColour(wx.WHITE)
2535                            item[2].SetBackgroundColour(wx.WHITE)
[edd166b]2536                        except:
2537                            msg = "Wrong Fit parameter range entered "
[ae84427]2538                            wx.PostEvent(self._manager.parent,
[ef26c83]2539                                         StatusEvent(status=msg))
[edd166b]2540                            raise ValueError, msg
[c985bef]2541                        is_modified = True
[7975f2b]2542               
[ef26c83]2543                if param_min != None and param_max != None:
[85b3971]2544                    if not self._validate_qrange(item[5], item[6]):
[ef26c83]2545                        msg = "Wrong Fit range entered for parameter "
2546                        msg += "name %s of model %s " % (name, self.model.name)
[ae84427]2547                        wx.PostEvent(self._manager.parent,
[ef26c83]2548                                     StatusEvent(status=msg))
[7975f2b]2549               
[ef26c83]2550                if name in self.model.details.keys():
[be1ec9f]2551                    self.model.details[name][1:3] = param_min, param_max
2552                    is_modified = True
[edd166b]2553                else:
[be1ec9f]2554                    self.model.details[name] = ["", param_min, param_max]
2555                    is_modified = True
[ef26c83]2556            try:
[2296316]2557                # Check if the textctr is enabled
2558                if item[2].IsEnabled():
[ef26c83]2559                    value = float(item[2].GetValue())
[2296316]2560                    item[2].SetBackgroundColour("white")
2561                    # If the value of the parameter has changed,
2562                    # +update the model and set the is_modified flag
2563                    if value != self.model.getParam(name) and \
2564                                                numpy.isfinite(value):
2565                        self.model.setParam(name, value)
[6e9976b]2566            except:
[7987962]2567                item[2].SetBackgroundColour("pink")
[6e9976b]2568                msg = "Wrong Fit parameter value entered "
[ae84427]2569                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[7975f2b]2570               
[ef26c83]2571        return is_modified
[c77d859]2572       
2573    def _set_dipers_Param(self, event):
2574        """
[5062bbf]2575        respond to self.enable_disp and self.disable_disp radio box.
[ef26c83]2576        The dispersity object is reset inside the model into Gaussian.
2577        When the user select yes , this method display a combo box for
2578        more selection when the user selects No,the combo box disappears.
[5062bbf]2579        Redraw the model with the default dispersity (Gaussian)
[c77d859]2580        """
[4470b10]2581        ## On selction if no model exists.
[ef26c83]2582        if self.model == None:
[4470b10]2583            self.disable_disp.SetValue(True)
[ef26c83]2584            msg = "Please select a Model first..."
[4470b10]2585            wx.MessageBox(msg, 'Info')
[ef26c83]2586            wx.PostEvent(self._manager.parent,
2587                         StatusEvent(status="Polydispersion: %s" % msg))
[4470b10]2588            return
2589
[1c1436d]2590        self._reset_dispersity()
[1467e1a6]2591   
[ef26c83]2592        if self.model == None:
[70c57ebf]2593            self.model_disp.Hide()
2594            self.sizer4_4.Clear(True)
2595            return
[b421b1a]2596
[1c1436d]2597        if self.enable_disp.GetValue():
2598            ## layout for model containing no dispersity parameters
[f20767b]2599           
[ef26c83]2600            self.disp_list = self.model.getDispParamList()
[f20767b]2601             
[ef26c83]2602            if len(self.disp_list) == 0 and len(self.disp_cb_dict) == 0:
2603                self._layout_sizer_noDipers()
[c77d859]2604            else:
[ef26c83]2605                ## set gaussian sizer
[1c1436d]2606                self._on_select_Disp(event=None)
2607        else:
2608            self.sizer4_4.Clear(True)
[f20767b]2609           
[ef26c83]2610        ## post state to fit panel
[1c1436d]2611        self.save_current_state()
[ef26c83]2612        if event != None:
2613            event = PageInfoEvent(page=self)
[240b9966]2614            wx.PostEvent(self.parent, event)
[1467e1a6]2615        #draw the model with the current dispersity
[f20767b]2616        self._draw_model()
[f1aa385]2617        self.sizer4_4.Layout()
2618        self.sizer5.Layout()
[71f0373]2619        self.Layout()
[ef26c83]2620        self.Refresh()
[3b605bb]2621         
[c77d859]2622    def _layout_sizer_noDipers(self):
2623        """
[5062bbf]2624        Draw a sizer with no dispersity info
[c77d859]2625        """
[ef26c83]2626        ix = 0
2627        iy = 1
2628        self.fittable_param = []
2629        self.fixed_param = []
2630        self.orientation_params_disp = []
[1c1436d]2631       
[c77d859]2632        self.sizer4_4.Clear(True)
[01b6bd0]2633        text = "No polydispersity available for this model"
2634        model_disp = wx.StaticText(self, -1, text)
[ef26c83]2635        self.sizer4_4.Add(model_disp, (iy, ix), (1, 1),
2636                          wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
[dcf29d7]2637        self.sizer4_4.Layout()
[c77d859]2638        self.sizer4.Layout()
[340c2b3]2639   
[c77d859]2640    def _reset_dispersity(self):
2641        """
[5062bbf]2642        put gaussian dispersity into current model
[c77d859]2643        """
[ef26c83]2644        if len(self.param_toFit) > 0:
[1c1436d]2645            for item in self.fittable_param:
[513115c]2646                if item in self.param_toFit:
[1c1436d]2647                    self.param_toFit.remove(item)
[edd166b]2648
[1c1436d]2649            for item in self.orientation_params_disp:
[513115c]2650                if item in self.param_toFit:
[1c1436d]2651                    self.param_toFit.remove(item)
[513115c]2652         
[ef26c83]2653        self.fittable_param = []
2654        self.fixed_param = []
2655        self.orientation_params_disp = []
2656        self.values = {}
2657        self.weights = {}
[f20767b]2658     
[0e4e554]2659        #from sas.models.dispersion_models import GaussianDispersion
2660        from sasmodels.weights import GaussianDispersion
[ef26c83]2661        if len(self.disp_cb_dict) == 0:
[e2f7b92]2662            self.save_current_state()
[3b605bb]2663            self.sizer4_4.Clear(True)
2664            self.Layout()
[ef26c83]2665            return
2666        if (len(self.disp_cb_dict) > 0):
[f20767b]2667            for p in self.disp_cb_dict:
[ef26c83]2668                # The parameter was un-selected.
2669                # Go back to Gaussian model (with 0 pts)
[f20767b]2670                disp_model = GaussianDispersion()
2671               
[ff8f99b]2672                self._disp_obj_dict[p] = disp_model
[ef26c83]2673                # Set the new model as the dispersion object
2674                # for the selected parameter
[f20767b]2675                try:
[ef26c83]2676                    self.model.set_dispersion(p, disp_model)
[f20767b]2677                except:
[c985bef]2678
[f20767b]2679                    pass
[7975f2b]2680
[240b9966]2681        ## save state into
2682        self.save_current_state()
[ef26c83]2683        self.Layout()
[c985bef]2684        self.Refresh()
[7975f2b]2685                 
[ef26c83]2686    def _on_select_Disp(self, event):
[c77d859]2687        """
[5062bbf]2688        allow selecting different dispersion
2689        self.disp_list should change type later .now only gaussian
[c77d859]2690        """
[2296316]2691        self._set_sizer_dispersion()
2692
[6e9150d]2693        ## Redraw the model
[ef26c83]2694        self._draw_model()
[3a37fe0]2695        #self._undo.Enable(True)
[ef26c83]2696        event = PageInfoEvent(page=self)
[3b9e023]2697        wx.PostEvent(self.parent, event)
2698       
[7975f2b]2699        self.sizer4_4.Layout()
2700        self.sizer4.Layout()
[36cb4d2f]2701        self.SetupScrolling()
[340c2b3]2702   
[ef26c83]2703    def _on_disp_func(self, event=None):
[c77d859]2704        """
[2296316]2705        Select a distribution function for the polydispersion
[f20767b]2706       
[ef26c83]2707        :Param event: ComboBox event
[2296316]2708        """
2709        # get ready for new event
2710        if event != None:
2711            event.Skip()
2712        # Get event object
[ef26c83]2713        disp_box = event.GetEventObject()
[2296316]2714
2715        # Try to select a Distr. function
[ef26c83]2716        try:
[2296316]2717            disp_box.SetBackgroundColour("white")
2718            selection = disp_box.GetCurrentSelection()
2719            param_name = disp_box.Name.split('.')[0]
2720            disp_name = disp_box.GetValue()
[ef26c83]2721            dispersity = disp_box.GetClientData(selection)
[2296316]2722   
2723            #disp_model =  GaussianDispersion()
2724            disp_model = dispersity()
2725            # Get param names to reset the values of the param
2726            name1 = param_name + ".width"
2727            name2 = param_name + ".npts"
2728            name3 = param_name + ".nsigmas"
2729            # Check Disp. function whether or not it is 'array'
2730            if disp_name.lower() == "array":
[ef26c83]2731                value2 = ""
2732                value3 = ""
[2296316]2733                value1 = self._set_array_disp(name=name1, disp=disp_model)
2734            else:
2735                self._del_array_values(name1)
2736                #self._reset_array_disp(param_name)
2737                self._disp_obj_dict[name1] = disp_model
2738                self.model.set_dispersion(param_name, disp_model)
[ef26c83]2739                self.state._disp_obj_dict[name1] = disp_model
[2296316]2740 
[ef26c83]2741                value1 = str(format_number(self.model.getParam(name1), True))
2742                value2 = str(format_number(self.model.getParam(name2)))
2743                value3 = str(format_number(self.model.getParam(name3)))
[2296316]2744            # Reset fittable polydispersin parameter value
[513115c]2745            for item in self.fittable_param:
[ef26c83]2746                if item[1] == name1:
2747                    item[2].SetValue(value1)
[2296316]2748                    item[5].SetValue("")
2749                    item[6].SetValue("")
2750                    # Disable for array
2751                    if disp_name.lower() == "array":
2752                        item[0].SetValue(False)
2753                        item[0].Disable()
2754                        item[2].Disable()
[ace0e33]2755                        item[3].Show(False)
2756                        item[4].Show(False)
[2296316]2757                        item[5].Disable()
2758                        item[6].Disable()
2759                    else:
2760                        item[0].Enable()
2761                        item[2].Enable()
2762                        item[5].Enable()
[ef26c83]2763                        item[6].Enable()
[2296316]2764                    break
2765            # Reset fixed polydispersion params
2766            for item in self.fixed_param:
2767                if item[1] == name2:
2768                    item[2].SetValue(value2) 
2769                    # Disable Npts for array
2770                    if disp_name.lower() == "array":
2771                        item[2].Disable()
2772                    else:
2773                        item[2].Enable()
2774                if item[1] == name3:
[ef26c83]2775                    item[2].SetValue(value3)
[2296316]2776                    # Disable Nsigs for array
2777                    if disp_name.lower() == "array":
2778                        item[2].Disable()
2779                    else:
2780                        item[2].Enable()
2781               
2782            # Make sure the check box updated when all checked
2783            if self.cb1.GetValue():
[fc1761b]2784                #self.select_all_param(None)
2785                self.get_all_checked_params()
[2296316]2786
2787            # update params
[ef26c83]2788            self._update_paramv_on_fit()
[2296316]2789            # draw
2790            self._draw_model()
2791            self.Refresh()
2792        except:
2793            # Error msg
2794            msg = "Error occurred:"
2795            msg += " Could not select the distribution function..."
2796            msg += " Please select another distribution function."
2797            disp_box.SetBackgroundColour("pink")
2798            # Focus on Fit button so that users can see the pinky box
2799            self.btFit.SetFocus()
[ae84427]2800            wx.PostEvent(self._manager.parent,
[2296316]2801                         StatusEvent(status=msg, info="error"))
2802       
2803    def _set_array_disp(self, name=None, disp=None):
2804        """
2805        Set array dispersion
2806       
2807        :param name: name of the parameter for the dispersion to be set
2808        :param disp: the polydisperion object
2809        """
[ef26c83]2810        # The user wants this parameter to be averaged.
[2296316]2811        # Pop up the file selection dialog.
2812        path = self._selectDlg()
2813        # Array data
2814        values = []
2815        weights = []
2816        # If nothing was selected, just return
2817        if path is None:
2818            self.disp_cb_dict[name].SetValue(False)
2819            #self.noDisper_rbox.SetValue(True)
2820            return
2821        self._default_save_location = os.path.dirname(path)
[ae84427]2822        if self._manager != None:
2823            self._manager.parent._default_save_location =\
[baf1ef3]2824                             self._default_save_location
[f20767b]2825
[ef26c83]2826        basename = os.path.basename(path)
2827        values, weights = self.read_file(path)
[3b9e023]2828       
[2296316]2829        # If any of the two arrays is empty, notify the user that we won't
2830        # proceed
[ef26c83]2831        if len(self.param_toFit) > 0:
[2296316]2832            if name in self.param_toFit:
2833                self.param_toFit.remove(name)
2834
2835        # Tell the user that we are about to apply the distribution
2836        msg = "Applying loaded %s distribution: %s" % (name, path)
[ae84427]2837        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[6b39d58]2838        self._set_array_disp_model(name=name, disp=disp,
2839                                    values=values, weights=weights)
2840        return basename
2841   
[ef26c83]2842    def _set_array_disp_model(self, name=None, disp=None,
[6b39d58]2843                              values=[], weights=[]):
2844        """
2845        Set array dispersion model
2846       
2847        :param name: name of the parameter for the dispersion to be set
2848        :param disp: the polydisperion object
2849        """
[2296316]2850        disp.set_weights(values, weights)
2851        self._disp_obj_dict[name] = disp
2852        self.model.set_dispersion(name.split('.')[0], disp)
[ef26c83]2853        self.state._disp_obj_dict[name] = disp
[2296316]2854        self.values[name] = values
2855        self.weights[name] = weights
2856        # Store the object to make it persist outside the
2857        # scope of this method
2858        #TODO: refactor model to clean this up?
2859        self.state.values = {}
2860        self.state.weights = {}
2861        self.state.values = copy.deepcopy(self.values)
2862        self.state.weights = copy.deepcopy(self.weights)
2863
[ef26c83]2864        # Set the new model as the dispersion object for the
[2296316]2865        #selected parameter
2866        #self.model.set_dispersion(p, disp_model)
[ef26c83]2867        # Store a reference to the weights in the model object
[2296316]2868        #so that
2869        # it's not lost when we use the model within another thread.
[ef26c83]2870        self.state.model = self.model.clone()
[2296316]2871        self.model._persistency_dict[name.split('.')[0]] = \
2872                                        [values, weights]
2873        self.state.model._persistency_dict[name.split('.')[0]] = \
[ef26c83]2874                                        [values, weights]
[6b39d58]2875                                       
[ef26c83]2876    def _del_array_values(self, name=None):
[2296316]2877        """
2878        Reset array dispersion
[f20767b]2879       
[ef26c83]2880        :param name: name of the parameter for the dispersion to be set
[2296316]2881        """
2882        # Try to delete values and weight of the names array dic if exists
2883        try:
2884            del self.values[name]
2885            del self.weights[name]
2886            # delete all other dic
2887            del self.state.values[name]
2888            del self.state.weights[name]
[ef26c83]2889            del self.model._persistency_dict[name.split('.')[0]]
[2296316]2890            del self.state.model._persistency_dict[name.split('.')[0]]
2891        except:
2892            pass
2893                                           
[7975f2b]2894    def _lay_out(self):
2895        """
[5062bbf]2896        returns self.Layout
2897       
2898        :Note: Mac seems to like this better when self.
2899            Layout is called after fitting.
[7975f2b]2900        """
2901        self._sleep4sec()
2902        self.Layout()
[ef26c83]2903        return
[7975f2b]2904   
2905    def _sleep4sec(self):
2906        """
[12eac73]2907            sleep for 1 sec only applied on Mac
[ef26c83]2908            Note: This 1sec helps for Mac not to crash on self.
2909            Layout after self._draw_model
[7975f2b]2910        """
2911        if ON_MAC == True:
[12eac73]2912            time.sleep(1)
[f72333f]2913           
[ef26c83]2914    def _find_polyfunc_selection(self, disp_func=None):
[2296316]2915        """
[ef26c83]2916        FInd Comboox selection from disp_func
[2296316]2917       
2918        :param disp_function: dispersion distr. function
2919        """
2920        # List of the poly_model name in the combobox
[ef26c83]2921        list = ["RectangleDispersion", "ArrayDispersion",
2922                "LogNormalDispersion", "GaussianDispersion",
2923                "SchulzDispersion"]
[2296316]2924
2925        # Find the selection
2926        try:
2927            selection = list.index(disp_func.__class__.__name__)
2928            return selection
2929        except:
[ef26c83]2930            return 3
[2296316]2931                           
[ef26c83]2932    def on_reset_clicked(self, event):
[904168e1]2933        """
[5062bbf]2934        On 'Reset' button  for Q range clicked
[904168e1]2935        """
[7609f1a]2936        flag = True
[904168e1]2937        ##For 3 different cases: Data2D, Data1D, and theory
[06aa2eeb]2938        if self.model == None:
[ef26c83]2939            msg = "Please select a model first..."
[06aa2eeb]2940            wx.MessageBox(msg, 'Info')
2941            flag = False
2942            return
2943           
2944        elif self.data.__class__.__name__ == "Data2D":
[ef26c83]2945            data_min = 0
2946            x = max(math.fabs(self.data.xmin), math.fabs(self.data.xmax))
2947            y = max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
[904168e1]2948            self.qmin_x = data_min
2949            self.qmax_x = math.sqrt(x*x + y*y)
[3b70cc7]2950            #self.data.mask = numpy.ones(len(self.data.data),dtype=bool)
[f72333f]2951            # check smearing
2952            if not self.disable_smearer.GetValue():
[ef26c83]2953                ## set smearing value whether or
2954                # not the data contain the smearing info
[f72333f]2955                if self.pinhole_smearer.GetValue():
2956                    flag = self.update_pinhole_smear()
2957                else:
2958                    flag = True
[06aa2eeb]2959                   
2960        elif self.data == None:
2961            self.qmin_x = _QMIN_DEFAULT
2962            self.qmax_x = _QMAX_DEFAULT
[ef26c83]2963            self.num_points = _NPTS_DEFAULT
[06aa2eeb]2964            self.state.npts = self.num_points
2965           
[6318298]2966        elif self.data.__class__.__name__ != "Data2D":
[904168e1]2967            self.qmin_x = min(self.data.x)
2968            self.qmax_x = max(self.data.x)
[7609f1a]2969            # check smearing
2970            if not self.disable_smearer.GetValue():
[ef26c83]2971                ## set smearing value whether or
2972                # not the data contain the smearing info
[7609f1a]2973                if self.slit_smearer.GetValue():
2974                    flag = self.update_slit_smear()
2975                elif self.pinhole_smearer.GetValue():
2976                    flag = self.update_pinhole_smear()
2977                else:
2978                    flag = True
[904168e1]2979        else:
[06aa2eeb]2980            flag = False
[7975f2b]2981           
[7609f1a]2982        if flag == False:
[ef26c83]2983            msg = "Cannot Plot :Must enter a number!!!  "
[ae84427]2984            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
[51a71a3]2985        else:
2986            # set relative text ctrs.
[f95301b]2987            self.qmin.SetValue(str(self.qmin_x))
[51a71a3]2988            self.qmax.SetValue(str(self.qmax_x))
[bf5e985]2989            self.show_npts2fit()
[ef26c83]2990            # At this point, some button and variables satatus (disabled?)
2991            # should be checked such as color that should be reset to
2992            # white in case that it was pink.
[51a71a3]2993            self._onparamEnter_helper()
2994
[7609f1a]2995        self.save_current_state()
[904168e1]2996        self.state.qmin = self.qmin_x
2997        self.state.qmax = self.qmax_x
[00c3aac]2998       
[904168e1]2999        #reset the q range values
3000        self._reset_plotting_range(self.state)
3001        self._draw_model()
[2296316]3002       
[cb270ad2]3003    def select_log(self, event):
3004        """
3005        Log checked to generate log spaced points for theory model
3006        """
3007
[2296316]3008    def get_images(self):
3009        """
3010        Get the images of the plots corresponding this panel for report
3011       
3012        : return graphs: list of figures
[be1ec9f]3013        : Need Move to guiframe
[2296316]3014        """
3015        # set list of graphs
3016        graphs = []
3017        canvases = []
[1c6c1b7]3018        res_item = None
[2296316]3019        # call gui_manager
[ae84427]3020        gui_manager = self._manager.parent
[2296316]3021        # loops through the panels [dic]
[be1ec9f]3022        for _, item2 in gui_manager.plot_panels.iteritems():
[ef26c83]3023            data_title = self.data.group_id
[2296316]3024            # try to get all plots belonging to this control panel
[ef26c83]3025            try:
[1c6c1b7]3026                g_id = item2.group_id
3027                if g_id == data_title or \
3028                        str(g_id).count("res" + str(self.graph_id)) or \
3029                        str(g_id).count(str(self.uid)) > 0:
3030                    if str(g_id).count("res" + str(self.graph_id)) > 0:
3031                        res_item = [item2.figure, item2.canvas]
3032                    else:
3033                        # append to the list
3034                        graphs.append(item2.figure)
3035                        canvases.append(item2.canvas) 
[ef26c83]3036            except:
3037                # Not for control panels
3038                pass
[1c6c1b7]3039        # Make sure the resduals plot goes to the last
3040        if res_item != None:
3041            graphs.append(res_item[0])
3042            canvases.append(res_item[1])
[2296316]3043        # return the list of graphs
3044        return graphs, canvases
[904168e1]3045
[ef26c83]3046    def on_model_help_clicked(self, event):
[7ad6ff5]3047        """
[5062bbf]3048        on 'More details' button
[7ad6ff5]3049        """
[79492222]3050        from sas.perspectives.fitting.help_panel import  HelpWindow
3051        from sas.models import get_data_path
[c77d859]3052       
[2296316]3053        # Get models help model_function path
[70b760da]3054        path = get_data_path(media='media')
[ef26c83]3055        model_path = os.path.join(path, "model_functions.html")
[7ad6ff5]3056        if self.model == None:
3057            name = 'FuncHelp'
[ea5fa58]3058        else:
3059            name = self.formfactorbox.GetValue()
[ef26c83]3060        frame = HelpWindow(None, -1, pageToOpen=model_path)
[318b5bbb]3061        # If model name exists and model is not a custom model
3062        #mod_cat = self.categorybox.GetStringSelection()
[ea5fa58]3063        if frame.rhelp.HasAnchor(name):
3064            frame.Show(True)
3065            frame.rhelp.ScrollToAnchor(name)
3066        else:
3067            if self.model != None:
3068                frame.Destroy()
3069                msg = 'Model description:\n'
3070                if str(self.model.description).rstrip().lstrip() == '':
3071                    msg += "Sorry, no information is available for this model."
3072                else:
3073                    msg += self.model.description + '\n'
3074                info = "Info"
3075                wx.MessageBox(msg, info)
3076            else:
3077                frame.Show(True)
3078
[318b5bbb]3079    def _on_mag_help(self, event):   
3080        """
3081        Magnetic angles help panel
3082        """
[79492222]3083        from sas.perspectives.fitting.help_panel import  HelpWindow
[318b5bbb]3084        # Get models help model_function path
[79492222]3085        #import sas.perspectives.fitting as fitmedia
3086        from sas.models import get_data_path
[318b5bbb]3087
3088        media = get_data_path(media='media')
[5eb663a]3089        path = os.path.join(media, "mag_pic.html") 
[318b5bbb]3090        name = "Polar/Magnetic Angles"
3091        frame = HelpWindow(None, -1, 
3092                           title=' Help: Polarization/Magnetization Angles', 
3093                           pageToOpen=path, size=(865, 450))   
3094        try: 
3095            frame.splitter.DetachWindow(frame.lpanel)
3096            # Display only the right side one
3097            frame.lpanel.Hide() 
3098            frame.Show(True)
3099        except:
3100            frame.Destroy() 
3101            msg = 'Display Error\n'
3102            info = "Info"
3103            wx.MessageBox(msg, info)
3104
3105    def _on_mag_on(self, event):   
3106        """
3107        Magnetic Parameters ON/OFF
3108        """
3109        button = event.GetEventObject()
3110
3111        if button.GetLabel().count('ON') > 0:
3112            self.magnetic_on = True
3113            button.SetLabel("Magnetic OFF")
3114            m_value = 1.0e-06
3115            for key in self.model.magnetic_params:
3116                if key.count('M0') > 0:
3117                    self.model.setParam(key, m_value)
3118                    m_value += 0.5e-06
3119        else:
3120            self.magnetic_on = False
3121            button.SetLabel("Magnetic ON")
3122            for key in self.model.magnetic_params:
3123                if key.count('M0') > 0:
3124                    #reset mag value to zero fo safety
3125                    self.model.setParam(key, 0.0)
3126                   
3127        self.Show(False)   
3128        self.set_model_param_sizer(self.model)
3129        #self._set_sizer_dispersion()
3130        self.state.magnetic_on = self.magnetic_on
3131        self.SetupScrolling()
3132        self.Show(True)
[ea5fa58]3133           
[2296316]3134    def on_pd_help_clicked(self, event):
3135        """
3136        Button event for PD help
3137        """
3138        from help_panel import  HelpWindow
[b9a5f0e]3139        import sas.models as models
[2296316]3140       
3141        # Get models help model_function path
3142        path = models.get_data_path(media='media')
[ef26c83]3143        pd_path = os.path.join(path, "pd_help.html")
[2296316]3144
[ef26c83]3145        frame = HelpWindow(None, -1, pageToOpen=pd_path)
[2296316]3146        frame.Show(True)
3147       
3148    def on_left_down(self, event):
3149        """
3150        Get key stroke event
3151        """
3152        # Figuring out key combo: Cmd for copy, Alt for paste
3153        if event.CmdDown() and event.ShiftDown():
[be1ec9f]3154            self.get_paste()
[2296316]3155        elif event.CmdDown():
[be1ec9f]3156            self.get_copy()
[2296316]3157        else:
3158            event.Skip()
3159            return
3160        # make event free
3161        event.Skip()
3162       
[951a2f5]3163    def get_copy(self):
3164        """
3165        Get copy params to clipboard
3166        """
[ef26c83]3167        content = self.get_copy_params()
[951a2f5]3168        flag = self.set_clipboard(content)
[ef26c83]3169        self._copy_info(flag)
3170        return flag
[2296316]3171           
[ef26c83]3172    def get_copy_params(self):
[2296316]3173        """
3174        Get the string copies of the param names and values in the tap
[ef26c83]3175        """
[b9a5f0e]3176        content = 'sasview_parameter_values:'
[ef26c83]3177        # Do it if params exist
3178        if  self.parameters != []:
[2296316]3179           
[ef26c83]3180            # go through the parameters
[be1ec9f]3181            strings = self._get_copy_helper(self.parameters,
[2296316]3182                                           self.orientation_params)
[be1ec9f]3183            content += strings
[2296316]3184           
3185            # go through the fittables
[be1ec9f]3186            strings = self._get_copy_helper(self.fittable_param,
[2296316]3187                                           self.orientation_params_disp)
[be1ec9f]3188            content += strings
[2296316]3189
3190            # go through the fixed params
[be1ec9f]3191            strings = self._get_copy_helper(self.fixed_param,
[2296316]3192                                           self.orientation_params_disp)
[be1ec9f]3193            content += strings
[2296316]3194               
3195            # go through the str params
[be1ec9f]3196            strings = self._get_copy_helper(self.str_parameters,
[2296316]3197                                           self.orientation_params)
[be1ec9f]3198            content += strings
[951a2f5]3199            return content
3200        else:
3201            return False
[34dbaf4]3202
3203    def get_copy_excel(self):
3204        """
3205        Get copy params to clipboard
3206        """
3207        content = self.get_copy_params_excel()
3208        flag = self.set_clipboard(content)
3209        self._copy_info(flag)
3210        return flag
3211
3212    def get_copy_params_excel(self):
3213        """
3214        Get the string copies of the param names and values in the tap
3215        """
3216        content = ''
3217
3218        crlf = chr(13) + chr(10)
3219        tab = chr(9)
3220
3221        # Do it if params exist
3222        if  self.parameters != []:
3223
3224            for param in self.parameters:
3225                content += param[1] #parameter name
3226                content += tab
3227                content += param[1]+"_err"
3228                content += tab
3229
3230            content += crlf
3231
3232            #row of values and errors...
3233            for param in self.parameters:
3234                content += param[2].GetValue() #value
3235                content +=tab
3236                content += param[4].GetValue() #error
3237                content +=tab
3238
3239            return content
3240        else:
3241            return False
3242
3243
3244    def get_copy_latex(self):
3245        """
3246        Get copy params to clipboard
3247        """
3248        content = self.get_copy_params_latex()
3249        flag = self.set_clipboard(content)
3250        self._copy_info(flag)
3251        return flag
3252
3253    def get_copy_params_latex(self):
3254        """
3255        Get the string copies of the param names and values in the tap
3256        """
3257        content = '\\begin{table}'
3258        content += '\\begin{tabular}[h]'
3259
3260        crlf = chr(13) + chr(10)
3261        tab = chr(9)
3262
3263        # Do it if params exist
3264        if  self.parameters != []:
3265
3266            content += '{|'
3267            for param in self.parameters:
3268                content += 'l|l|'
3269            content += '}\hline'
3270            content += crlf
3271
3272            for index, param in enumerate(self.parameters):
3273                content += param[1].replace('_','\_') #parameter name
3274                content += ' & '
3275                content += param[1].replace('_','\_')+"\_err"
3276                if index < len(self.parameters)-1:
3277                    content += ' & '
3278            content += '\\\\ \\hline'
3279            content += crlf
3280
3281            #row of values and errors...
3282            for index, param in enumerate(self.parameters):
3283                content += param[2].GetValue() #parameter value
3284                content += ' & '
3285                content += param[4].GetValue() #parameter error
3286                if index < len(self.parameters)-1:
3287                    content += ' & '
3288            content += '\\\\ \\hline'
3289            content += crlf
3290
3291            content += '\\end{tabular}'
3292            content += '\\end{table}'
3293            return content
3294        else:
3295            return False
3296
3297
[ef26c83]3298    def set_clipboard(self, content=None):
[951a2f5]3299        """
3300        Put the string to the clipboard
[ef26c83]3301        """
[951a2f5]3302        if not content:
3303            return False
[2296316]3304        if wx.TheClipboard.Open():
3305            wx.TheClipboard.SetData(wx.TextDataObject(str(content)))
3306            wx.TheClipboard.Close()
[951a2f5]3307            return True
[2296316]3308        return None
3309   
3310    def _get_copy_helper(self, param, orient_param):
3311        """
3312        Helping get value and name of the params
3313       
3314        : param param:  parameters
3315        : param orient_param = oritational params
3316        : return content: strings [list] [name,value:....]
3317        """
3318        content = ''
3319        # go through the str params
[ef26c83]3320        for item in param:
[1ac202f]3321            # copy only the params shown
3322            if not item[2].IsShown():
3323                continue
[68a921f]3324            disfunc = ''
3325            try:
3326                if item[7].__class__.__name__ == 'ComboBox':
[706667b]3327                    disfunc = str(item[7].GetValue())
[68a921f]3328            except:
3329                pass
[706667b]3330           
[2296316]3331            # 2D
[25c0def]3332            if self.data.__class__.__name__ == "Data2D":
[fc1761b]3333                try:
3334                    check = item[0].GetValue()
3335                except:
3336                    check = None
[2296316]3337                name = item[1]
3338                value = item[2].GetValue()
3339            # 1D
3340            else:
3341                ## for 1D all parameters except orientation
3342                if not item[1] in orient_param:
[fc1761b]3343                    try:
3344                        check = item[0].GetValue()
3345                    except:
3346                        check = None
[2296316]3347                    name = item[1]
3348                    value = item[2].GetValue()
[706667b]3349
[2296316]3350            # add to the content
[68a921f]3351            if disfunc != '':
[706667b]3352               
[68a921f]3353                disfunc = ',' + disfunc
[be1ec9f]3354            # Need to support array func for copy/paste
[ace0e33]3355            try:
3356                if disfunc.count('array') > 0:
3357                    disfunc += ','
3358                    for val in self.values[name]:
3359                        disfunc += ' ' + str(val)
3360                    disfunc += ','
3361                    for weight in self.weights[name]:
3362                        disfunc += ' ' + str(weight)
3363            except:
3364                pass
[ef26c83]3365            content += name + ',' + str(check) + ',' + value + disfunc + ':'
[68a921f]3366
[2296316]3367        return content
[951a2f5]3368   
[ef26c83]3369    def get_clipboard(self):
[951a2f5]3370        """
3371        Get strings in the clipboard
3372        """
[ef26c83]3373        text = ""
3374        # Get text from the clip board
[951a2f5]3375        if wx.TheClipboard.Open():
[25c0def]3376            if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
3377                data = wx.TextDataObject()
3378                # get wx dataobject
[2a66329]3379                success = wx.TheClipboard.GetData(data)
[25c0def]3380                # get text
[2a66329]3381                if success:
3382                    text = data.GetText()
3383                else:
3384                    text = ''
[25c0def]3385            # close clipboard
3386            wx.TheClipboard.Close()
[951a2f5]3387        return text
[2296316]3388   
[951a2f5]3389    def get_paste(self):
3390        """
3391        Paste params from the clipboard
3392        """
3393        text = self.get_clipboard()
[817991b]3394        flag = self.get_paste_params(text)
3395        self._copy_info(flag)
3396        return flag
[951a2f5]3397       
[ef26c83]3398    def get_paste_params(self, text=''):
[2296316]3399        """
3400        Get the string copies of the param names and values in the tap
[ef26c83]3401        """
3402        context = {}
3403        # put the text into dictionary
[2296316]3404        lines = text.split(':')
[b9a5f0e]3405        if lines[0] != 'sasview_parameter_values':
[977a965]3406            self._copy_info(False)
[2296316]3407            return False
3408        for line in lines[1:-1]:
3409            if len(line) != 0:
[25c0def]3410                item = line.split(',')
[fc1761b]3411                check = item[1]
[2296316]3412                name = item[0]
[fc1761b]3413                value = item[2]
[2296316]3414                # Transfer the text to content[dictionary]
[fc1761b]3415                context[name] = [check, value]
[68a921f]3416            # ToDo: PlugIn this poly disp function for pasting
[706667b]3417            try:
[fc1761b]3418                poly_func = item[3]
[ace0e33]3419                context[name].append(poly_func)
3420                try:
[ef26c83]3421                    # take the vals and weights for  array
[fc1761b]3422                    array_values = item[4].split(' ')
3423                    array_weights = item[5].split(' ')
[ace0e33]3424                    val = [float(a_val) for a_val in array_values[1:]]
3425                    weit = [float(a_weit) for a_weit in array_weights[1:]]
3426                   
3427                    context[name].append(val)
3428                    context[name].append(weit)
3429                except:
3430                    raise
[706667b]3431            except:
[ace0e33]3432                poly_func = ''
3433                context[name].append(poly_func)
[706667b]3434
[ef26c83]3435        # Do it if params exist
[2296316]3436        if  self.parameters != []:
[ef26c83]3437            # go through the parameters
3438            self._get_paste_helper(self.parameters,
[2296316]3439                                   self.orientation_params, context)
3440
3441            # go through the fittables
[ef26c83]3442            self._get_paste_helper(self.fittable_param,
3443                                   self.orientation_params_disp,
[706667b]3444                                   context)
[2296316]3445
3446            # go through the fixed params
[ef26c83]3447            self._get_paste_helper(self.fixed_param,
[2296316]3448                                   self.orientation_params_disp, context)
3449           
3450            # go through the str params
[ef26c83]3451            self._get_paste_helper(self.str_parameters,
[2296316]3452                                   self.orientation_params, context)
[6b39d58]3453               
[817991b]3454            return True
3455        return None
[2296316]3456   
3457    def _get_paste_helper(self, param, orient_param, content):
3458        """
3459        Helping set values of the params
3460       
3461        : param param:  parameters
3462        : param orient_param: oritational params
[ef26c83]3463        : param content: dictionary [ name, value: name1.value1,...]
[2296316]3464        """
3465        # go through the str params
[ef26c83]3466        for item in param:
[2296316]3467            # 2D
[25c0def]3468            if self.data.__class__.__name__ == "Data2D":
[2296316]3469                name = item[1]
3470                if name in content.keys():
[fc1761b]3471                    check = content[name][0]
3472                    pd = content[name][1]
[706667b]3473                    if name.count('.') > 0:
3474                        try:
[ace0e33]3475                            float(pd)
[706667b]3476                        except:
[01642fec]3477                            #continue
3478                            if not pd and pd != '':
3479                                continue
[ace0e33]3480                    item[2].SetValue(str(pd))
[01642fec]3481                    if item in self.fixed_param and pd == '':
3482                        # Only array func has pd == '' case.
3483                        item[2].Enable(False)
[706667b]3484                    if item[2].__class__.__name__ == "ComboBox":
[ef26c83]3485                        if content[name][1] in self.model.fun_list:
[fc1761b]3486                            fun_val = self.model.fun_list[content[name][1]]
[25c0def]3487                            self.model.setParam(name, fun_val)
[706667b]3488                   
[fc1761b]3489                    value = content[name][1:]
[ace0e33]3490                    self._paste_poly_help(item, value)
[fc1761b]3491                    if check == 'True':
3492                        is_true = True
3493                    elif check == 'False':
3494                        is_true = False
3495                    else:
3496                        is_true = None
3497                    if is_true != None:
3498                        item[0].SetValue(is_true)
3499            # 1D
[2296316]3500            else:
3501                ## for 1D all parameters except orientation
3502                if not item[1] in orient_param:
3503                    name = item[1]
3504                    if name in content.keys():
[fc1761b]3505                        check = content[name][0]
[ef26c83]3506                        # Avoid changing combox content
[fc1761b]3507                        value = content[name][1:]
[ace0e33]3508                        pd = value[0]
[706667b]3509                        if name.count('.') > 0:
3510                            try:
[ace0e33]3511                                pd = float(pd)
[706667b]3512                            except:
[01642fec]3513                                #continue
3514                                if not pd and pd != '':
3515                                    continue
[ace0e33]3516                        item[2].SetValue(str(pd))
3517                        if item in self.fixed_param and pd == '':
3518                            # Only array func has pd == '' case.
3519                            item[2].Enable(False)
[d8c54ead]3520                        if item[2].__class__.__name__ == "ComboBox":
[ef26c83]3521                            if value[0] in self.model.fun_list:
[706667b]3522                                fun_val = self.model.fun_list[value[0]]
[25c0def]3523                                self.model.setParam(name, fun_val)
[d8c54ead]3524                                # save state
[ace0e33]3525                        self._paste_poly_help(item, value)
[fc1761b]3526                        if check == 'True':
3527                            is_true = True
3528                        elif check == 'False':
3529                            is_true = False
3530                        else:
3531                            is_true = None
3532                        if is_true != None:
3533                            item[0].SetValue(is_true)
[ace0e33]3534                       
3535    def _paste_poly_help(self, item, value):
3536        """
3537        Helps get paste for poly function
3538       
3539        :param item: Gui param items
3540        :param value: the values for parameter ctrols
3541        """
[6b39d58]3542        is_array = False
[ace0e33]3543        if len(value[1]) > 0:
3544            # Only for dispersion func.s
3545            try:
3546                item[7].SetValue(value[1])
3547                selection = item[7].GetCurrentSelection()
[01642fec]3548                name = item[7].Name
3549                param_name = name.split('.')[0]
[25c0def]3550                dispersity = item[7].GetClientData(selection)
[ace0e33]3551                disp_model = dispersity()
3552                # Only for array disp
3553                try:
3554                    pd_vals = numpy.array(value[2])
3555                    pd_weights = numpy.array(value[3])
3556                    if len(pd_vals) > 0 and len(pd_vals) > 0:
3557                        if len(pd_vals) == len(pd_weights):
[6b39d58]3558                            self._set_disp_array_cb(item=item)
[ef26c83]3559                            self._set_array_disp_model(name=name,
[6b39d58]3560                                                       disp=disp_model,
[ef26c83]3561                                                       values=pd_vals,
[6b39d58]3562                                                       weights=pd_weights)
3563                            is_array = True
[ace0e33]3564                except:
[ef26c83]3565                    pass
[6b39d58]3566                if not is_array:
3567                    self._disp_obj_dict[name] = disp_model
[ef26c83]3568                    self.model.set_dispersion(name,
[6b39d58]3569                                              disp_model)
3570                    self.state._disp_obj_dict[name] = \
3571                                              disp_model
3572                    self.model.set_dispersion(param_name, disp_model)
3573                    self.state.values = self.values
[ef26c83]3574                    self.state.weights = self.weights
[6b39d58]3575                    self.model._persistency_dict[param_name] = \
[ef26c83]3576                                            [self.state.values,
[25c0def]3577                                             self.state.weights]
[6b39d58]3578                         
[ace0e33]3579            except:
[ef26c83]3580                print "Error in BasePage._paste_poly_help: %s" % sys.exc_value
[6b39d58]3581   
3582    def _set_disp_array_cb(self, item):
3583        """
3584        Set cb for array disp
3585        """
3586        item[0].SetValue(False)
3587        item[0].Enable(False)
3588        item[2].Enable(False)
3589        item[3].Show(False)
3590        item[4].Show(False)
3591        item[5].SetValue('')
3592        item[5].Enable(False)
3593        item[6].SetValue('')
3594        item[6].Enable(False)
[25c0def]3595       
3596    def update_pinhole_smear(self):
3597        """
3598            Method to be called by sub-classes
[be1ec9f]3599            Moveit; This method doesn't belong here
[25c0def]3600        """
3601        print "BasicPage.update_pinhole_smear was called: skipping"
3602        return
[0b477f6]3603
[ea5fa58]3604
3605
3606
[df7a7e3]3607    def _read_category_info(self):
3608        """
3609        Reads the categories in from file
3610        """
3611
3612        # # ILL mod starts here - July 2012 kieranrcampbell@gmail.com
3613        self.master_category_dict = defaultdict(list)
3614        self.by_model_dict = defaultdict(list)
3615        self.model_enabled_dict = defaultdict(bool)
3616
3617        try:
[ea5fa58]3618            categorization_file = CategoryInstaller.get_user_file()
3619            if not os.path.isfile(categorization_file):
3620                categorization_file = CategoryInstaller.get_default_file()
[27b7acc]3621            cat_file = open(categorization_file, 'rb')                           
3622            self.master_category_dict = json.load(cat_file)
[df7a7e3]3623            self._regenerate_model_dict()
[657e52c]3624            cat_file.close()
[df7a7e3]3625
3626        except IOError:
[ea5fa58]3627            raise
[df7a7e3]3628            print 'Problem reading in category file.'
3629            print 'We even looked for it, made sure it was there.'
3630            print 'An existential crisis if there ever was one.'
3631
3632    def _regenerate_model_dict(self):
3633        """
3634        regenerates self.by_model_dict which has each model name as the
3635        key and the list of categories belonging to that model
3636        along with the enabled mapping
3637        """
3638
3639        self.by_model_dict = defaultdict(list)
3640        for category in self.master_category_dict:
[ea5fa58]3641            for (model, enabled) in self.master_category_dict[category]:
[df7a7e3]3642                self.by_model_dict[model].append(category)
3643                self.model_enabled_dict[model] = enabled
3644   
3645    def _populate_listbox(self):
3646        """
3647        fills out the category list box
3648        """
[ea5fa58]3649        uncat_str = 'Customized Models'
[df7a7e3]3650        self._read_category_info()
3651
[ea5fa58]3652        self.categorybox.Clear()
[df7a7e3]3653        cat_list = sorted(self.master_category_dict.keys())
[ea5fa58]3654        if not uncat_str in cat_list:
3655            cat_list.append(uncat_str)
3656       
[df7a7e3]3657        for category in cat_list:
3658            if category != '':
[ea5fa58]3659                self.categorybox.Append(category)
[df7a7e3]3660
[ea5fa58]3661        if self.categorybox.GetSelection() == wx.NOT_FOUND:
3662            self.categorybox.SetSelection(0)
[df7a7e3]3663        else:
[ea5fa58]3664            self.categorybox.SetSelection( \
3665                self.categorybox.GetSelection())
[df7a7e3]3666
[ea5fa58]3667        #self._on_change_cat(None)
[df7a7e3]3668
3669
3670    def _on_change_cat(self, event):
3671        """
3672        Callback for category change action
3673        """
3674        self.model_name = None
[ea5fa58]3675        category = self.categorybox.GetStringSelection()
[df7a7e3]3676        if category == None:
3677            return
3678        self.model_box.Clear()
3679
[ea5fa58]3680        if category == 'Customized Models':
3681            for model in self.model_list_box[category]:
[df7a7e3]3682                str_m = str(model).split(".")[0]
3683                self.model_box.Append(str_m)
3684
3685        else:
3686            for (model,enabled) in sorted(self.master_category_dict[category],
3687                                      key = lambda name: name[0]):
3688                if(enabled):
3689                    self.model_box.Append(model)
3690
[ea5fa58]3691
3692
3693
[0b477f6]3694    def _fill_model_sizer(self, sizer):
3695        """
3696        fill sizer containing model info
3697        """
3698        ##Add model function Details button in fitpanel.
3699        ##The following 3 lines are for Mac. Let JHC know before modifying...
3700        title = "Model"
3701        self.formfactorbox = None
3702        self.multifactorbox = None
3703        self.mbox_description = wx.StaticBox(self, -1, str(title))
3704        boxsizer1 = wx.StaticBoxSizer(self.mbox_description, wx.VERTICAL)
[ea5fa58]3705        sizer_cat = wx.BoxSizer(wx.HORIZONTAL)
[0b477f6]3706        self.mbox_description.SetForegroundColour(wx.RED)
3707        id = wx.NewId()
3708        self.model_help = wx.Button(self, id, 'Details', size=(80, 23))
3709        self.model_help.Bind(wx.EVT_BUTTON, self.on_model_help_clicked, id=id)
3710        self.model_help.SetToolTipString("Model Function Help")
3711        id = wx.NewId()
3712        self.model_view = wx.Button(self, id, "Show 2D", size=(80, 23))
3713        self.model_view.Bind(wx.EVT_BUTTON, self._onModel2D, id=id)
3714        hint = "toggle view of model from 1D to 2D  or 2D to 1D"
3715        self.model_view.SetToolTipString(hint)
3716       
[ea5fa58]3717        cat_set_box = wx.StaticBox(self, -1, 'Category')
3718        sizer_cat_box = wx.StaticBoxSizer(cat_set_box, wx.HORIZONTAL)
3719        sizer_cat_box.SetMinSize((200, 50))
3720        self.categorybox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
[ae4c139]3721        self.categorybox.SetToolTip( wx.ToolTip("Select a Category/Type") )
[ea5fa58]3722        self._populate_listbox()
3723        wx.EVT_COMBOBOX(self.categorybox, -1, self._show_combox)
3724        #self.shape_rbutton = wx.RadioButton(self, -1, 'Shapes',
3725        #                                     style=wx.RB_GROUP)
3726        #self.shape_indep_rbutton = wx.RadioButton(self, -1,
3727        #                                          "Shape-Independent")
3728        #self.struct_rbutton = wx.RadioButton(self, -1, "Structure Factor ")
3729        #self.plugin_rbutton = wx.RadioButton(self, -1, "Uncategorized")
3730               
3731        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3732        #                   id=self.shape_rbutton.GetId())
3733        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3734        #                    id=self.shape_indep_rbutton.GetId())
3735        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3736        #                    id=self.struct_rbutton.GetId())
3737        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3738        #                    id=self.plugin_rbutton.GetId())
3739        #MAC needs SetValue
[ef67145]3740       
3741        show_cat_button = wx.Button(self, -1, "Modify")
3742        cat_tip = "Modify model categories \n"
3743        cat_tip += "(also accessible from the menu bar)."
3744        show_cat_button.SetToolTip( wx.ToolTip(cat_tip) )
3745        show_cat_button.Bind(wx.EVT_BUTTON, self._on_modify_cat)
3746        sizer_cat_box.Add(self.categorybox, 1, wx.RIGHT, 3)
3747        sizer_cat_box.Add((10,10))
3748        sizer_cat_box.Add(show_cat_button)
[ea5fa58]3749        #self.shape_rbutton.SetValue(True)
3750     
3751        sizer_radiobutton = wx.GridSizer(2, 2, 5, 5)
3752
3753        #sizer_radiobutton.Add(self.shape_rbutton)
3754        #sizer_radiobutton.Add(self.shape_indep_rbutton)
3755        sizer_radiobutton.Add((5,5))
3756        sizer_radiobutton.Add(self.model_view, 1, wx.RIGHT, 15)
3757        #sizer_radiobutton.Add(self.plugin_rbutton)
3758        #sizer_radiobutton.Add(self.struct_rbutton)
3759        sizer_radiobutton.Add((5,5))
3760        sizer_radiobutton.Add(self.model_help, 1, wx.RIGHT, 15)
3761        sizer_cat.Add(sizer_cat_box, 1, wx.LEFT, 2.5)
3762        sizer_cat.Add(sizer_radiobutton)
[0b477f6]3763        sizer_selection = wx.BoxSizer(wx.HORIZONTAL)
3764        mutifactor_selection = wx.BoxSizer(wx.HORIZONTAL)
3765       
3766        self.text1 = wx.StaticText(self, -1, "")
[ea5fa58]3767        self.text2 = wx.StaticText(self, -1, "P(Q)*S(Q)")
[0b477f6]3768        self.mutifactor_text = wx.StaticText(self, -1, "No. of Shells: ")
3769        self.mutifactor_text1 = wx.StaticText(self, -1, "")
3770        self.show_sld_button = wx.Button(self, -1, "Show SLD Profile")
3771        self.show_sld_button.Bind(wx.EVT_BUTTON, self._on_show_sld)
3772
[ea5fa58]3773        self.formfactorbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
[ae4c139]3774        self.formfactorbox.SetToolTip( wx.ToolTip("Select a Model") )
[ea5fa58]3775        if self.model != None:
3776            self.formfactorbox.SetValue(self.model.name)
[0b477f6]3777        self.structurebox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
3778        self.multifactorbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
3779        self.initialize_combox()
[ea5fa58]3780        wx.EVT_COMBOBOX(self.formfactorbox, -1, self._on_select_model)
[0b477f6]3781
3782        wx.EVT_COMBOBOX(self.structurebox, -1, self._on_select_model)
3783        wx.EVT_COMBOBOX(self.multifactorbox, -1, self._on_select_model)
3784        ## check model type to show sizer
3785        if self.model != None:
[ea5fa58]3786            print "_set_model_sizer_selection: disabled."
3787            #self._set_model_sizer_selection(self.model)
3788       
3789        sizer_selection.Add(self.text1)
3790        sizer_selection.Add((10, 5))
3791        sizer_selection.Add(self.formfactorbox)
3792        sizer_selection.Add((5, 5))
3793        sizer_selection.Add(self.text2)
3794        sizer_selection.Add((5, 5))
3795        sizer_selection.Add(self.structurebox)
[0b477f6]3796       
[ea5fa58]3797        mutifactor_selection.Add((13, 5))
[0b477f6]3798        mutifactor_selection.Add(self.mutifactor_text)
3799        mutifactor_selection.Add(self.multifactorbox)
3800        mutifactor_selection.Add((5, 5))
3801        mutifactor_selection.Add(self.mutifactor_text1)
3802        mutifactor_selection.Add((10, 5))
3803        mutifactor_selection.Add(self.show_sld_button)
3804
[ea5fa58]3805        boxsizer1.Add(sizer_cat)
3806        boxsizer1.Add((10, 10))
3807        boxsizer1.Add(sizer_selection)
[0b477f6]3808        boxsizer1.Add((10, 10))
3809        boxsizer1.Add(mutifactor_selection)
3810       
3811        self._set_multfactor_combobox()
3812        self.multifactorbox.SetSelection(1)
3813        self.show_sld_button.Hide()
3814        sizer.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
3815        sizer.Layout()
[fcd6c6a]3816       
3817    def on_smear_helper(self, update=False):
3818        """
3819        Help for onSmear if implemented
3820       
3821        :param update: force or not to update
3822        """
3823    def reset_page(self, state, first=False):
3824        """
3825        reset the state  if implemented
3826        """
3827    def onSmear(self, event):
3828        """
3829        Create a smear object if implemented
3830        """
3831    def onPinholeSmear(self, event):
3832        """
3833        Create a custom pinhole smear object if implemented
3834        """
3835    def onSlitSmear(self, event):
3836        """
3837        Create a custom slit smear object if implemented
3838        """
3839    def update_slit_smear(self):
3840        """
3841        called by kill_focus on pinhole TextCntrl
3842        to update the changes if implemented
3843        """
3844    def select_param(self, event):
3845        """
3846        Select TextCtrl  checked if implemented
3847        """
3848    def set_data(self, data=None):
3849        """
3850        Sets data if implemented
3851        """
3852    def _is_2D(self):
3853        """
3854        Check if data_name is Data2D if implemented
3855        """
3856    def _on_select_model(self, event=None):
3857        """
3858        call back for model selection if implemented
3859        """
3860    def select_all_param(self, event):
3861        """
3862        set to true or false all checkBox if implemented
3863        """
3864    def get_weight_flag(self):
3865        """
3866        Get flag corresponding to a given weighting dI data if implemented
3867        """
3868    def _set_sizer_dispersion(self):
3869        """
3870        draw sizer for dispersity if implemented
3871        """
3872    def get_all_checked_params(self):
3873        """
3874        Found all parameters current check and add them to list of parameters
3875        to fit if implemented
3876        """
[bf5e985]3877    def show_npts2fit(self):
[fcd6c6a]3878        """
3879        setValue Npts for fitting if implemented
3880        """
3881    def _onModel2D(self, event):
3882        """
3883        toggle view of model from 1D to 2D  or 2D from 1D if implemented
[6fe5100]3884        """
Note: See TracBrowser for help on using the repository browser.