source: sasview/src/sans/perspectives/fitting/basepage.py @ f468791

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

Move plottools under sans

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