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

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 27b7acc was 27b7acc, checked in by butler, 10 years ago

converted stored category file from pickle to json and a bit of cleanup

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