source: sasview/fittingview/src/sans/perspectives/fitting/basepage.py @ 54d6c3e

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 54d6c3e was 318b5bbb, checked in by Jae Cho <jhjcho@…>, 12 years ago

Added polarization and magnetic stuffs

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