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

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 eddb6ec was eddb6ec, checked in by Tobias Richter <tobias.richter@…>, 10 years ago

refs #57 Clean up warnings in Python code

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