source: sasview/src/sas/perspectives/fitting/basepage.py @ 231e887

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 231e887 was 231e887, checked in by ajj, 9 years ago

Category lists now generated using oldname from models

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