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

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since eddb6ec was eddb6ec, checked in by Tobias Richter <tobias.richter@…>, 10 years ago

refs #57 Clean up warnings in Python code

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