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

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 a4340d1 was b9a5f0e, checked in by krzywon, 10 years ago

90% complete with the conversion.

  • Property mode set to 100644
File size: 152.2 KB
Line 
1"""
2Base Page for fitting
3"""
4import sys
5import os
6import wx
7import numpy
8import time
9import copy
10import math
11import string
12import 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 clipboad..."
835            infor = "warning"
836        else:
837            msg = "Error occured: "
838            msg += "No valid parameter values to paste from the clipboard..."
839            infor = "error"
840            wx.PostEvent(self._manager.parent,
841                    StatusEvent(status=msg, info=infor))
842        # inform msg to wx
843        wx.PostEvent(self._manager.parent,
844                    StatusEvent(status=msg, info=infor))
845       
846    def _get_time_stamp(self):
847        """
848        return time and date stings
849        """
850        # date and time
851        year, month, day, hour, minute, second, _, _, _ = time.localtime()
852        current_time = str(hour) + ":" + str(minute) + ":" + str(second)
853        current_date = str(month) + "/" + str(day) + "/" + str(year)
854        return current_time, current_date
855     
856    def on_bookmark(self, event):
857        """
858        save history of the data and model
859        """
860        if self.model == None:
861            msg = "Can not bookmark; Please select Data and Model first..."
862            wx.MessageBox(msg, 'Info')
863            return
864        self.save_current_state()
865        new_state = self.state.clone()
866        ##Add model state on context menu
867        self.number_saved_state += 1
868        current_time, current_date = self._get_time_stamp()
869        #name= self.model.name+"[%g]"%self.number_saved_state
870        name = "Fitting: %g]" % self.number_saved_state
871        name += self.model.__class__.__name__
872        name += "bookmarked at %s on %s" % (current_time, current_date)
873        self.saved_states[name] = new_state
874       
875        ## Add item in the context menu
876        msg = "Model saved at %s on %s" % (current_time, current_date)
877        ## post help message for the selected model
878        msg += " Saved! right click on this page to retrieve this model"
879        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
880       
881        id = wx.NewId()
882        self.popUpMenu.Append(id, name, str(msg))
883        wx.EVT_MENU(self, id, self.onResetModel)
884        wx.PostEvent(self._manager.parent,
885                     AppendBookmarkEvent(title=name,
886                                         hint=str(msg),
887                                         handler=self._back_to_bookmark))
888   
889    def _back_to_bookmark(self, event):
890        """
891        Back to bookmark
892        """
893        self._manager.on_perspective(event)
894        self.onResetModel(event)
895        self._draw_model()
896               
897    def onSetFocus(self, evt):
898        """
899        highlight the current textcrtl and hide the error text control shown
900        after fitting
901        """
902        return
903   
904    def read_file(self, path):
905        """
906        Read two columns file
907       
908        :param path: the path to the file to read
909       
910        """
911        try:
912            if path == None:
913                wx.PostEvent(self._manager.parent,
914                            StatusEvent(status= \
915                            " Selected Distribution was not loaded: %s" % path))
916                return None, None
917            input_f = open(path, 'r')
918            buff = input_f.read()
919            lines = buff.split('\n')
920            input_f.close()
921            angles = []
922            weights = []
923            for line in lines:
924                toks = line.split()
925                try:
926                    angle = float(toks[0])
927                    weight = float(toks[1])
928                    angles.append(angle)
929                    weights.append(weight)
930                except:
931                    # Skip non-data lines
932                    pass
933            return numpy.array(angles), numpy.array(weights)
934        except:
935            raise
936
937    def createMemento(self):
938        """
939        return the current state of the page
940        """
941        return self.state.clone()
942   
943    def save_current_state(self):
944        """
945        Store current state
946        """
947        self.state.engine_type = copy.deepcopy(self.engine_type)
948        ## save model option
949        if self.model != None:
950            self.disp_list = self.model.getDispParamList()
951            self.state.disp_list = copy.deepcopy(self.disp_list)
952            self.state.model = self.model.clone()
953           
954            #model combobox: complex code because of mac's silent error
955            if self.structurebox != None:
956                if self.structurebox.IsShown():
957                    self.state.structurecombobox = 'None'
958                    s_select = self.structurebox.GetSelection()
959                    if s_select > 0:
960                        self.state.structurecombobox = self.structurebox.\
961                        GetString(s_select)
962            if self.formfactorbox != None:
963                f_select = self.formfactorbox.GetSelection()
964                if f_select > 0:
965                    self.state.formfactorcombobox = self.formfactorbox.\
966                    GetString(f_select)
967        if self.categorybox != None:
968            cb_select = self.categorybox.GetSelection()
969            if cb_select > 0:
970                self.state.categorycombobox = self.categorybox.\
971                GetString(cb_select)
972       
973        self.state.enable2D = copy.deepcopy(self.enable2D)
974        self.state.values = copy.deepcopy(self.values)
975        self.state.weights = copy.deepcopy(self.weights)
976        ## save data
977        self.state.data = copy.deepcopy(self.data)
978        self.state.qmax_x = self.qmax_x
979        self.state.qmin_x = self.qmin_x
980        self.state.dI_noweight = copy.deepcopy(self.dI_noweight.GetValue())
981        self.state.dI_didata = copy.deepcopy(self.dI_didata.GetValue())
982        self.state.dI_sqrdata = copy.deepcopy(self.dI_sqrdata.GetValue())
983        self.state.dI_idata = copy.deepcopy(self.dI_idata.GetValue())
984        self.state.dq_l = self.dq_l
985        self.state.dq_r = self.dq_r
986        if hasattr(self, "enable_disp"):
987            self.state.enable_disp = self.enable_disp.GetValue()
988            self.state.disable_disp = self.disable_disp.GetValue()
989           
990        self.state.smearer = copy.deepcopy(self.current_smearer)
991        if hasattr(self, "enable_smearer"):
992            self.state.enable_smearer = \
993                                copy.deepcopy(self.enable_smearer.GetValue())
994            self.state.disable_smearer = \
995                                copy.deepcopy(self.disable_smearer.GetValue())
996
997        self.state.pinhole_smearer = \
998                                copy.deepcopy(self.pinhole_smearer.GetValue())
999        self.state.dx_max = copy.deepcopy(self.dx_max)
1000        self.state.dx_min = copy.deepcopy(self.dx_min)
1001        self.state.dxl = copy.deepcopy(self.dxl)
1002        self.state.dxw = copy.deepcopy(self.dxw)
1003        self.state.slit_smearer = copy.deepcopy(self.slit_smearer.GetValue())
1004                 
1005        if len(self._disp_obj_dict) > 0:
1006            for k, v in self._disp_obj_dict.iteritems():
1007                self.state._disp_obj_dict[k] = v
1008
1009            self.state.values = copy.deepcopy(self.values)
1010            self.state.weights = copy.deepcopy(self.weights)
1011        ## save plotting range
1012        self._save_plotting_range()
1013       
1014        self.state.orientation_params = []
1015        self.state.orientation_params_disp = []
1016        self.state.parameters = []
1017        self.state.fittable_param = []
1018        self.state.fixed_param = []
1019        self.state.str_parameters = []
1020
1021        ## save checkbutton state and txtcrtl values
1022        self._copy_parameters_state(self.str_parameters,
1023                                    self.state.str_parameters)
1024        self._copy_parameters_state(self.orientation_params,
1025                                     self.state.orientation_params)
1026        self._copy_parameters_state(self.orientation_params_disp,
1027                                     self.state.orientation_params_disp)
1028       
1029        self._copy_parameters_state(self.parameters, self.state.parameters)
1030        self._copy_parameters_state(self.fittable_param,
1031                                     self.state.fittable_param)
1032        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
1033        #save chisqr
1034        self.state.tcChi = self.tcChi.GetValue()
1035       
1036    def save_current_state_fit(self):
1037        """
1038        Store current state for fit_page
1039        """
1040        ## save model option
1041        if self.model != None:
1042            self.disp_list = self.model.getDispParamList()
1043            self.state.disp_list = copy.deepcopy(self.disp_list)
1044            self.state.model = self.model.clone()
1045        if hasattr(self, "engine_type"):
1046            self.state.engine_type = copy.deepcopy(self.engine_type)
1047           
1048        self.state.enable2D = copy.deepcopy(self.enable2D)
1049        self.state.values = copy.deepcopy(self.values)
1050        self.state.weights = copy.deepcopy(self.weights)
1051        ## save data
1052        self.state.data = copy.deepcopy(self.data)
1053       
1054        if hasattr(self, "enable_disp"):
1055            self.state.enable_disp = self.enable_disp.GetValue()
1056            self.state.disable_disp = self.disable_disp.GetValue()
1057           
1058        self.state.smearer = copy.deepcopy(self.current_smearer)
1059        if hasattr(self, "enable_smearer"):
1060            self.state.enable_smearer = \
1061                                copy.deepcopy(self.enable_smearer.GetValue())
1062            self.state.disable_smearer = \
1063                                copy.deepcopy(self.disable_smearer.GetValue())
1064           
1065        self.state.pinhole_smearer = \
1066                                copy.deepcopy(self.pinhole_smearer.GetValue())
1067        self.state.slit_smearer = copy.deepcopy(self.slit_smearer.GetValue())
1068        self.state.dI_noweight = copy.deepcopy(self.dI_noweight.GetValue())
1069        self.state.dI_didata = copy.deepcopy(self.dI_didata.GetValue())
1070        self.state.dI_sqrdata = copy.deepcopy(self.dI_sqrdata.GetValue())
1071        self.state.dI_idata = copy.deepcopy(self.dI_idata.GetValue())
1072        if hasattr(self, "disp_box") and self.disp_box != None:
1073            self.state.disp_box = self.disp_box.GetCurrentSelection()
1074
1075            if len(self.disp_cb_dict) > 0:
1076                for k, v in self.disp_cb_dict.iteritems():
1077                    if v == None:
1078                        self.state.disp_cb_dict[k] = v
1079                    else:
1080                        try:
1081                            self.state.disp_cb_dict[k] = v.GetValue()
1082                        except:
1083                            self.state.disp_cb_dict[k] = None
1084            if len(self._disp_obj_dict) > 0:
1085                for k, v in self._disp_obj_dict.iteritems():
1086                    self.state._disp_obj_dict[k] = v
1087                       
1088            self.state.values = copy.deepcopy(self.values)
1089            self.state.weights = copy.deepcopy(self.weights)
1090           
1091        ## save plotting range
1092        self._save_plotting_range()
1093       
1094        ## save checkbutton state and txtcrtl values
1095        self._copy_parameters_state(self.orientation_params,
1096                                     self.state.orientation_params)
1097        self._copy_parameters_state(self.orientation_params_disp,
1098                                     self.state.orientation_params_disp)
1099        self._copy_parameters_state(self.parameters, self.state.parameters)
1100        self._copy_parameters_state(self.fittable_param,
1101                                             self.state.fittable_param)
1102        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
1103   
1104    def check_invalid_panel(self):
1105        """
1106        check if the user can already perform some action with this panel
1107        """
1108        if self.data is None:
1109            self.disable_smearer.SetValue(True)
1110            self.disable_disp.SetValue(True)
1111            msg = "Please load Data and select Model to start..."
1112            wx.MessageBox(msg, 'Info')
1113            return  True
1114       
1115    def set_model_state(self, state):
1116        """
1117        reset page given a model state
1118        """
1119        self.disp_cb_dict = state.disp_cb_dict
1120        self.disp_list = state.disp_list
1121     
1122        ## set the state of the radio box
1123        #self.shape_rbutton.SetValue(state.shape_rbutton)
1124        #self.shape_indep_rbutton.SetValue(state.shape_indep_rbutton)
1125        #self.struct_rbutton.SetValue(state.struct_rbutton)
1126        #self.plugin_rbutton.SetValue(state.plugin_rbutton)
1127       
1128        ## fill model combobox
1129        self._show_combox_helper()
1130        #select the current model
1131        try:
1132            # to support older version
1133            category_pos = int(state.categorycombobox)
1134        except:
1135            category_pos = 0
1136            for ind_cat in range(self.categorybox.GetCount()):
1137                if self.categorycombobox.GetString(ind_form) == \
1138                                        state.categorycombobox:
1139                    category_pos = int(ind_cat)
1140                    break
1141           
1142        self.categorybox.Select(category_pos)
1143        try:
1144            # to support older version
1145            formfactor_pos = int(state.formfactorcombobox)
1146        except:
1147            formfactor_pos = 0
1148            for ind_form in range(self.formfactorbox.GetCount()):
1149                if self.formfactorbox.GetString(ind_form) == \
1150                                        state.formfactorcombobox:
1151                    formfactor_pos = int(ind_form)
1152                    break
1153           
1154        self.formfactorbox.Select(formfactor_pos)
1155       
1156        try:
1157            # to support older version
1158            structfactor_pos = int(state.structurecombobox)
1159        except:
1160            structfactor_pos = 0
1161            for ind_struct in range(self.structurebox.GetCount()):
1162                if self.structurebox.GetString(ind_struct) == \
1163                                        state.structurecombobox:
1164                    structfactor_pos = int(ind_struct)
1165                    break
1166               
1167        self.structurebox.SetSelection(structfactor_pos)
1168       
1169        if state.multi_factor != None:
1170            self.multifactorbox.SetSelection(state.multi_factor)
1171           
1172        ## reset state of checkbox,textcrtl  and  regular parameters value
1173        self._reset_parameters_state(self.orientation_params_disp,
1174                                     state.orientation_params_disp)
1175        self._reset_parameters_state(self.orientation_params,
1176                                     state.orientation_params)
1177        self._reset_parameters_state(self.str_parameters,
1178                                     state.str_parameters)
1179        self._reset_parameters_state(self.parameters, state.parameters)
1180        ## display dispersion info layer
1181        self.enable_disp.SetValue(state.enable_disp)
1182        self.disable_disp.SetValue(state.disable_disp)
1183       
1184        if hasattr(self, "disp_box") and self.disp_box != None:
1185            self.disp_box.SetSelection(state.disp_box)
1186            n = self.disp_box.GetCurrentSelection()
1187            dispersity = self.disp_box.GetClientData(n)
1188            name = dispersity.__name__
1189
1190            self._set_dipers_Param(event=None)
1191       
1192            if name == "ArrayDispersion":
1193               
1194                for item in self.disp_cb_dict.keys():
1195                   
1196                    if hasattr(self.disp_cb_dict[item], "SetValue"):
1197                        self.disp_cb_dict[item].SetValue(\
1198                                                    state.disp_cb_dict[item])
1199                        # Create the dispersion objects
1200                        from sas.models.dispersion_models import ArrayDispersion
1201                        disp_model = ArrayDispersion()
1202                        if hasattr(state, "values") and \
1203                                 self.disp_cb_dict[item].GetValue() == True:
1204                            if len(state.values) > 0:
1205                                self.values = state.values
1206                                self.weights = state.weights
1207                                disp_model.set_weights(self.values,
1208                                                       state.weights)
1209                            else:
1210                                self._reset_dispersity()
1211                       
1212                        self._disp_obj_dict[item] = disp_model
1213                        # Set the new model as the dispersion object
1214                        #for the selected parameter
1215                        self.model.set_dispersion(item, disp_model)
1216                   
1217                        self.model._persistency_dict[item] = \
1218                                                [state.values, state.weights]
1219                   
1220            else:
1221                keys = self.model.getParamList()
1222                for item in keys:
1223                    if item in self.disp_list and \
1224                        not item in self.model.details:
1225                        self.model.details[item] = ["", None, None]
1226                self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
1227                self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
1228        ## smearing info  restore
1229        if hasattr(self, "enable_smearer"):
1230            ## set smearing value whether or not the data
1231            #contain the smearing info
1232            self.enable_smearer.SetValue(state.enable_smearer)
1233            self.disable_smearer.SetValue(state.disable_smearer)
1234            self.onSmear(event=None)
1235        self.pinhole_smearer.SetValue(state.pinhole_smearer)
1236        self.slit_smearer.SetValue(state.slit_smearer)
1237       
1238        self.dI_noweight.SetValue(state.dI_noweight)
1239        self.dI_didata.SetValue(state.dI_didata)
1240        self.dI_sqrdata.SetValue(state.dI_sqrdata)
1241        self.dI_idata.SetValue(state.dI_idata)
1242       
1243        ## we have two more options for smearing
1244        if self.pinhole_smearer.GetValue():
1245            self.onPinholeSmear(event=None)
1246        elif self.slit_smearer.GetValue():
1247            self.onSlitSmear(event=None)
1248       
1249        ## reset state of checkbox,textcrtl  and dispersity parameters value
1250        self._reset_parameters_state(self.fittable_param, state.fittable_param)
1251        self._reset_parameters_state(self.fixed_param, state.fixed_param)
1252       
1253        ## draw the model with previous parameters value
1254        self._onparamEnter_helper()
1255        self.select_param(event=None)
1256        #Save state_fit
1257        self.save_current_state_fit()
1258        self._lay_out()
1259        self.Refresh()
1260       
1261    def reset_page_helper(self, state):
1262        """
1263        Use page_state and change the state of existing page
1264       
1265        :precondition: the page is already drawn or created
1266       
1267        :postcondition: the state of the underlying data change as well as the
1268            state of the graphic interface
1269        """
1270        if state == None:
1271            return
1272        # set data, etc. from the state
1273        # reset page between theory and fitting from bookmarking
1274        #if state.data == None:
1275        #    data = None
1276        #else:
1277        data = state.data
1278
1279        if data == None:
1280            data_min = state.qmin
1281            data_max = state.qmax
1282            self.qmin_x = data_min
1283            self.qmax_x = data_max
1284            self.qmin.SetValue(str(data_min))
1285            self.qmax.SetValue(str(data_max))
1286
1287            self.state.data = data
1288            self.state.qmin = self.qmin_x
1289            self.state.qmax = self.qmax_x
1290        else:
1291            self.set_data(data)
1292           
1293        self.enable2D = state.enable2D
1294        try:
1295            self.magnetic_on = state.magnetic_on
1296        except:
1297            # Backward compatibility (for older state files)
1298            self.magnetic_on = False
1299        self.engine_type = state.engine_type
1300
1301        self.disp_cb_dict = state.disp_cb_dict
1302        self.disp_list = state.disp_list
1303     
1304        ## set the state of the radio box
1305        #self.shape_rbutton.SetValue(state.shape_rbutton)
1306        #self.shape_indep_rbutton.SetValue(state.shape_indep_rbutton)
1307        #self.struct_rbutton.SetValue(state.struct_rbutton)
1308        #self.plugin_rbutton.SetValue(state.plugin_rbutton)
1309       
1310        ## fill model combobox
1311        self._show_combox_helper()
1312        #select the current model
1313        try:
1314            # to support older version
1315            category_pos = int(state.categorycombobox)
1316        except:
1317            category_pos = 0
1318            for ind_cat in range(self.categorybox.GetCount()):
1319                if self.categorybox.GetString(ind_cat) == \
1320                                        state.categorycombobox:
1321                    category_pos = int(ind_cat)
1322                    break
1323           
1324        self.categorybox.Select(category_pos)
1325        self._show_combox(None)
1326        try:
1327            # to support older version
1328            formfactor_pos = int(state.formfactorcombobox)
1329        except:
1330            formfactor_pos = 0
1331            for ind_form in range(self.formfactorbox.GetCount()):
1332                if self.formfactorbox.GetString(ind_form) == \
1333                                                    (state.formfactorcombobox):
1334                    formfactor_pos = int(ind_form)
1335                    break
1336           
1337        self.formfactorbox.Select(formfactor_pos)
1338       
1339        try:
1340            # to support older version
1341            structfactor_pos = int(state.structurecombobox)
1342        except:
1343            structfactor_pos = 0
1344            for ind_struct in range(self.structurebox.GetCount()):
1345                if self.structurebox.GetString(ind_struct) == \
1346                                                    (state.structurecombobox):
1347                    structfactor_pos = int(ind_struct)
1348                    break
1349           
1350        self.structurebox.SetSelection(structfactor_pos)
1351
1352        if state.multi_factor != None:
1353            self.multifactorbox.SetSelection(state.multi_factor)
1354
1355        #reset the fitting engine type
1356        self.engine_type = state.engine_type
1357        #draw the pnael according to the new model parameter
1358        self._on_select_model(event=None)
1359           
1360        # take care of 2D button
1361        if data == None and self.model_view.IsEnabled():
1362            if self.enable2D:
1363                self.model_view.SetLabel("2D Mode")
1364            else:
1365                self.model_view.SetLabel("1D Mode")
1366        # else:
1367               
1368        if self._manager != None and self.engine_type != None:
1369            self._manager._on_change_engine(engine=self.engine_type)
1370        ## set the select all check box to the a given state
1371        self.cb1.SetValue(state.cb1)
1372     
1373        ## reset state of checkbox,textcrtl  and  regular parameters value
1374        self._reset_parameters_state(self.orientation_params_disp,
1375                                     state.orientation_params_disp)
1376        self._reset_parameters_state(self.orientation_params,
1377                                     state.orientation_params)
1378        self._reset_parameters_state(self.str_parameters,
1379                                     state.str_parameters)
1380        self._reset_parameters_state(self.parameters, state.parameters)
1381        ## display dispersion info layer
1382        self.enable_disp.SetValue(state.enable_disp)
1383        self.disable_disp.SetValue(state.disable_disp)
1384        # If the polydispersion is ON
1385        if state.enable_disp:
1386            # reset dispersion according the state
1387            self._set_dipers_Param(event=None)
1388            self._reset_page_disp_helper(state)
1389        ##plotting range restore
1390        self._reset_plotting_range(state)
1391        ## smearing info  restore
1392        if hasattr(self, "enable_smearer"):
1393            ## set smearing value whether or not the data
1394            #contain the smearing info
1395            self.enable_smearer.SetValue(state.enable_smearer)
1396            self.disable_smearer.SetValue(state.disable_smearer)
1397            self.onSmear(event=None)
1398        self.pinhole_smearer.SetValue(state.pinhole_smearer)
1399        self.slit_smearer.SetValue(state.slit_smearer)
1400        try:
1401            self.dI_noweight.SetValue(state.dI_noweight)
1402            self.dI_didata.SetValue(state.dI_didata)
1403            self.dI_sqrdata.SetValue(state.dI_sqrdata)
1404            self.dI_idata.SetValue(state.dI_idata)
1405        except:
1406            # to support older state file formats
1407            self.dI_noweight.SetValue(False)
1408            self.dI_didata.SetValue(True)
1409            self.dI_sqrdata.SetValue(False)
1410            self.dI_idata.SetValue(False)
1411 
1412        ## we have two more options for smearing
1413        if self.pinhole_smearer.GetValue():
1414            self.dx_min = state.dx_min
1415            self.dx_max = state.dx_max
1416            if self.dx_min != None:
1417                self.smear_pinhole_min.SetValue(str(self.dx_min))
1418            if self.dx_max != None:
1419                self.smear_pinhole_max.SetValue(str(self.dx_max))
1420            self.onPinholeSmear(event=None)
1421        elif self.slit_smearer.GetValue():
1422            self.dxl = state.dxl
1423            self.dxw = state.dxw
1424            if self.dxl != None:
1425                self.smear_slit_height.SetValue(str(self.dxl))
1426            if self.dxw != None:
1427                self.smear_slit_width.SetValue(str(self.dxw)) 
1428            else:
1429                self.smear_slit_width.SetValue('') 
1430            self.onSlitSmear(event=None)
1431       
1432        ## reset state of checkbox,textcrtl  and dispersity parameters value
1433        self._reset_parameters_state(self.fittable_param, state.fittable_param)
1434        self._reset_parameters_state(self.fixed_param, state.fixed_param)
1435       
1436        ## draw the model with previous parameters value
1437        self._onparamEnter_helper()
1438        #reset the value of chisqr when not consistent with the value computed
1439        self.tcChi.SetValue(str(self.state.tcChi))
1440        ## reset context menu items
1441        self._reset_context_menu()
1442       
1443        ## set the value of the current state to the state given as parameter
1444        self.state = state.clone()
1445        self.state.m_name = self.m_name
1446   
1447    def _reset_page_disp_helper(self, state):
1448        """
1449        Help to rest page for dispersions
1450        """
1451        keys = self.model.getParamList()
1452        for item in keys:
1453            if item in self.disp_list and \
1454                not item in self.model.details:
1455                self.model.details[item] = ["", None, None]
1456        #for k,v in self.state.disp_cb_dict.iteritems():
1457        self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
1458        self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
1459        self.values = copy.deepcopy(state.values)
1460        self.weights = copy.deepcopy(state.weights)
1461       
1462        for key, disp in state._disp_obj_dict.iteritems():
1463            # From saved file, disp_model can not be sent in model obj.
1464            # it will be sent as a string here, then converted to model object.
1465            if disp.__class__.__name__ == 'str':
1466                disp_model = None
1467                com_str = "from sas.models.dispersion_models "
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, "name"):
2151                    name = model.name
2152                mlist.append((name, models))
2153               
2154        # Sort the models
2155        mlist_sorted = sorted(mlist)
2156        for item in mlist_sorted:
2157            combobox.Append(item[0], item[1])
2158        return 0
2159   
2160    def _onQrangeEnter(self, event):
2161        """
2162        Check validity of value enter in the Q range field
2163       
2164        """
2165        tcrtl = event.GetEventObject()
2166        #Clear msg if previously shown.
2167        msg = ""
2168        wx.PostEvent(self.parent, StatusEvent(status=msg))
2169        # Flag to register when a parameter has changed.
2170        #is_modified = False
2171        if tcrtl.GetValue().lstrip().rstrip() != "":
2172            try:
2173                float(tcrtl.GetValue())
2174                tcrtl.SetBackgroundColour(wx.WHITE)
2175                # If qmin and qmax have been modified, update qmin and qmax
2176                if self._validate_qrange(self.qmin, self.qmax):
2177                    tempmin = float(self.qmin.GetValue())
2178                    if tempmin != self.qmin_x:
2179                        self.qmin_x = tempmin
2180                    tempmax = float(self.qmax.GetValue())
2181                    if tempmax != self.qmax_x:
2182                        self.qmax_x = tempmax
2183                else:
2184                    tcrtl.SetBackgroundColour("pink")
2185                    msg = "Model Error: wrong value entered: %s" % sys.exc_value
2186                    wx.PostEvent(self.parent, StatusEvent(status=msg))
2187                    return
2188            except:
2189                tcrtl.SetBackgroundColour("pink")
2190                msg = "Model Error: wrong value entered: %s" % sys.exc_value
2191                wx.PostEvent(self.parent, StatusEvent(status=msg))
2192                return
2193            #Check if # of points for theory model are valid(>0).
2194            if self.npts != None:
2195                if check_float(self.npts):
2196                    temp_npts = float(self.npts.GetValue())
2197                    if temp_npts != self.num_points:
2198                        self.num_points = temp_npts
2199                        #is_modified = True
2200                else:
2201                    msg = "Cannot plot: No points in Q range!!!  "
2202                    wx.PostEvent(self.parent, StatusEvent(status=msg))
2203        else:
2204            tcrtl.SetBackgroundColour("pink")
2205            msg = "Model Error: wrong value entered!!!"
2206            wx.PostEvent(self.parent, StatusEvent(status=msg))
2207        self.save_current_state()
2208        event = PageInfoEvent(page=self)
2209        wx.PostEvent(self.parent, event)
2210        self.state_change = False
2211        #Draw the model for a different range
2212        if not self.data.is_data:
2213            self.create_default_data()
2214        self._draw_model()
2215                   
2216    def _theory_qrange_enter(self, event):
2217        """
2218        Check validity of value enter in the Q range field
2219        """
2220       
2221        tcrtl = event.GetEventObject()
2222        #Clear msg if previously shown.
2223        msg = ""
2224        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2225        # Flag to register when a parameter has changed.
2226        is_modified = False
2227        if tcrtl.GetValue().lstrip().rstrip() != "":
2228            try:
2229                value = float(tcrtl.GetValue())
2230                tcrtl.SetBackgroundColour(wx.WHITE)
2231
2232                # If qmin and qmax have been modified, update qmin and qmax
2233                if self._validate_qrange(self.theory_qmin, self.theory_qmax):
2234                    tempmin = float(self.theory_qmin.GetValue())
2235                    if tempmin != self.theory_qmin_x:
2236                        self.theory_qmin_x = tempmin
2237                    tempmax = float(self.theory_qmax.GetValue())
2238                    if tempmax != self.qmax_x:
2239                        self.theory_qmax_x = tempmax
2240                else:
2241                    tcrtl.SetBackgroundColour("pink")
2242                    msg = "Model Error: wrong value entered: %s" % sys.exc_value
2243                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2244                    return
2245            except:
2246                tcrtl.SetBackgroundColour("pink")
2247                msg = "Model Error: wrong value entered: %s" % sys.exc_value
2248                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2249                return
2250            #Check if # of points for theory model are valid(>0).
2251            if self.Npts_total.IsEditable():
2252                if check_float(self.Npts_total):
2253                    temp_npts = float(self.Npts_total.GetValue())
2254                    if temp_npts != self.num_points:
2255                        self.num_points = temp_npts
2256                        is_modified = True
2257                else:
2258                    msg = "Cannot Plot: No points in Q range!!!  "
2259                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2260        else:
2261            tcrtl.SetBackgroundColour("pink")
2262            msg = "Model Error: wrong value entered!!!"
2263            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2264        self.save_current_state()
2265        event = PageInfoEvent(page=self)
2266        wx.PostEvent(self.parent, event)
2267        self.state_change = False
2268        #Draw the model for a different range
2269        self.create_default_data()
2270        self._draw_model()
2271                   
2272    def _on_select_model_helper(self):
2273        """
2274        call back for model selection
2275        """
2276        ## reset dictionary containing reference to dispersion
2277        self._disp_obj_dict = {}
2278        self.disp_cb_dict = {}
2279        self.temp_multi_functional = False
2280        f_id = self.formfactorbox.GetCurrentSelection()
2281        #For MAC
2282        form_factor = None
2283        if f_id >= 0:
2284            form_factor = self.formfactorbox.GetClientData(f_id)
2285
2286        if not form_factor in  self.model_list_box["multiplication"]:
2287            self.structurebox.Hide()
2288            self.text2.Hide()
2289            self.structurebox.Disable()
2290            self.structurebox.SetSelection(0)
2291            self.text2.Disable()
2292        else:
2293            self.structurebox.Show()
2294            self.text2.Show()
2295            self.structurebox.Enable()
2296            self.text2.Enable()
2297           
2298        if form_factor != None:
2299            # set multifactor for Mutifunctional models
2300            if form_factor().__class__ in \
2301                                        self.model_list_box["Multi-Functions"]:
2302                m_id = self.multifactorbox.GetCurrentSelection()
2303                multiplicity = form_factor().multiplicity_info[0]
2304                self.multifactorbox.Clear()
2305                self._set_multfactor_combobox(multiplicity)
2306                self._show_multfactor_combobox()
2307                #ToDo:  this info should be called directly from the model
2308                text = form_factor().multiplicity_info[1]  # 'No. of Shells: '
2309
2310                self.mutifactor_text.SetLabel(text)
2311                if m_id > multiplicity - 1:
2312                    # default value
2313                    m_id = 1
2314                   
2315                self.multi_factor = self.multifactorbox.GetClientData(m_id)
2316                if self.multi_factor == None:
2317                    self.multi_factor = 0
2318                form_factor = form_factor(int(self.multi_factor))
2319                self.multifactorbox.SetSelection(m_id)
2320                # Check len of the text1 and max_multiplicity
2321                text = ''
2322                if form_factor.multiplicity_info[0] == \
2323                                        len(form_factor.multiplicity_info[2]):
2324                    text = form_factor.multiplicity_info[2][self.multi_factor]
2325                self.mutifactor_text1.SetLabel(text)
2326                # Check if model has  get sld profile.
2327                if len(form_factor.multiplicity_info[3]) > 0:
2328                    self.sld_axes = form_factor.multiplicity_info[3]
2329                    self.show_sld_button.Show(True)
2330                else:
2331                    self.sld_axes = ""
2332
2333            else:
2334                self._hide_multfactor_combobox()
2335                self.show_sld_button.Hide()
2336                form_factor = form_factor()
2337                self.multi_factor = None
2338        else:
2339            self._hide_multfactor_combobox()
2340            self.show_sld_button.Hide()
2341            self.multi_factor = None
2342             
2343        s_id = self.structurebox.GetCurrentSelection()
2344        struct_factor = self.structurebox.GetClientData(s_id)
2345       
2346        if  struct_factor != None:
2347            from sas.models.MultiplicationModel import MultiplicationModel
2348            self.model = MultiplicationModel(form_factor, struct_factor())
2349            # multifunctional form factor
2350            if len(form_factor.non_fittable) > 0:
2351                self.temp_multi_functional = True
2352        else:
2353            if form_factor != None:
2354                self.model = form_factor
2355            else:
2356                self.model = None
2357                return self.model
2358        # check if model has magnetic parameters
2359        if len(self.model.magnetic_params) > 0:
2360            self._has_magnetic = True 
2361        else:
2362            self._has_magnetic = False 
2363        ## post state to fit panel
2364        self.state.parameters = []
2365        self.state.model = self.model
2366        self.state.qmin = self.qmin_x
2367        self.state.multi_factor = self.multi_factor
2368        self.disp_list = self.model.getDispParamList()
2369        self.state.disp_list = self.disp_list
2370        self.on_set_focus(None)
2371        self.Layout()
2372       
2373    def _validate_qrange(self, qmin_ctrl, qmax_ctrl):
2374        """
2375        Verify that the Q range controls have valid values
2376        and that Qmin < Qmax.
2377       
2378        :param qmin_ctrl: text control for Qmin
2379        :param qmax_ctrl: text control for Qmax
2380       
2381        :return: True is the Q range is value, False otherwise
2382       
2383        """
2384        qmin_validity = check_float(qmin_ctrl)
2385        qmax_validity = check_float(qmax_ctrl)
2386        if not (qmin_validity and qmax_validity):
2387            return False
2388        else:
2389            qmin = float(qmin_ctrl.GetValue())
2390            qmax = float(qmax_ctrl.GetValue())
2391            if qmin < qmax:
2392                #Make sure to set both colours white.
2393                qmin_ctrl.SetBackgroundColour(wx.WHITE)
2394                qmin_ctrl.Refresh()
2395                qmax_ctrl.SetBackgroundColour(wx.WHITE)
2396                qmax_ctrl.Refresh()
2397            else:
2398                qmin_ctrl.SetBackgroundColour("pink")
2399                qmin_ctrl.Refresh()
2400                qmax_ctrl.SetBackgroundColour("pink")
2401                qmax_ctrl.Refresh()
2402                msg = "Invalid Q range: Q min must be smaller than Q max"
2403                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2404                return False
2405        return True
2406   
2407    def _validate_Npts(self):
2408        """
2409        Validate the number of points for fitting is more than 10 points.
2410        If valid, setvalues Npts_fit otherwise post msg.
2411        """
2412        #default flag
2413        flag = True
2414        # Theory
2415        if self.data == None and self.enable2D:
2416            return flag
2417        for data in self.data_list:
2418            # q value from qx and qy
2419            radius = numpy.sqrt(data.qx_data * data.qx_data +
2420                                data.qy_data * data.qy_data)
2421            #get unmasked index
2422            index_data = (float(self.qmin.GetValue()) <= radius) & \
2423                            (radius <= float(self.qmax.GetValue()))
2424            index_data = (index_data) & (data.mask)
2425            index_data = (index_data) & (numpy.isfinite(data.data))
2426
2427            if len(index_data[index_data]) < 10:
2428                # change the color pink.
2429                self.qmin.SetBackgroundColour("pink")
2430                self.qmin.Refresh()
2431                self.qmax.SetBackgroundColour("pink")
2432                self.qmax.Refresh()
2433                msg = "Data Error: "
2434                msg += "Too few points in %s." % data.name
2435                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2436                self.fitrange = False
2437                flag = False
2438            else:
2439                self.Npts_fit.SetValue(str(len(index_data[index_data == True])))
2440                self.fitrange = True
2441           
2442        return flag
2443
2444    def _validate_Npts_1D(self):
2445        """
2446        Validate the number of points for fitting is more than 5 points.
2447        If valid, setvalues Npts_fit otherwise post msg.
2448        """
2449        #default flag
2450        flag = True
2451        # Theory
2452        if self.data == None:
2453            return flag
2454        for data in self.data_list:
2455            # q value from qx and qy
2456            radius = data.x
2457            #get unmasked index
2458            index_data = (float(self.qmin.GetValue()) <= radius) & \
2459                            (radius <= float(self.qmax.GetValue()))
2460            index_data = (index_data) & (numpy.isfinite(data.y))
2461
2462            if len(index_data[index_data]) < 5:
2463                # change the color pink.
2464                self.qmin.SetBackgroundColour("pink")
2465                self.qmin.Refresh()
2466                self.qmax.SetBackgroundColour("pink")
2467                self.qmax.Refresh()
2468                msg = "Data Error: "
2469                msg += "Too few points in %s." % data.name
2470                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2471                self.fitrange = False
2472                flag = False
2473            else:
2474                self.Npts_fit.SetValue(str(len(index_data[index_data == True])))
2475                self.fitrange = True
2476           
2477        return flag
2478   
2479    def _check_value_enter(self, list, modified):
2480        """
2481        :param list: model parameter and panel info
2482        :Note: each item of the list should be as follow:
2483            item=[check button state, parameter's name,
2484                paramater's value, string="+/-",
2485                parameter's error of fit,
2486                parameter's minimum value,
2487                parrameter's maximum value ,
2488                parameter's units]
2489        """
2490        is_modified = modified
2491        if len(list) == 0:
2492            return is_modified
2493        for item in list:
2494            #skip angle parameters for 1D
2495            if not self.enable2D:
2496                if item in self.orientation_params:
2497                    continue
2498            #try:
2499            name = str(item[1])
2500           
2501            if string.find(name, ".npts") == -1 and \
2502                                        string.find(name, ".nsigmas") == -1:
2503                ## check model parameters range
2504                param_min = None
2505                param_max = None
2506               
2507                ## check minimun value
2508                if item[5] != None and item[5] != "":
2509                    if item[5].GetValue().lstrip().rstrip() != "":
2510                        try:
2511                            param_min = float(item[5].GetValue())
2512                            if not self._validate_qrange(item[5], item[2]):
2513                                if numpy.isfinite(param_min):
2514                                    item[2].SetValue(format_number(param_min))
2515                           
2516                            item[5].SetBackgroundColour(wx.WHITE)
2517                            item[2].SetBackgroundColour(wx.WHITE)
2518                                           
2519                        except:
2520                            msg = "Wrong fit parameter range entered"
2521                            wx.PostEvent(self._manager.parent,
2522                                         StatusEvent(status=msg))
2523                            raise ValueError, msg
2524                        is_modified = True
2525                ## check maximum value
2526                if item[6] != None and item[6] != "":
2527                    if item[6].GetValue().lstrip().rstrip() != "":
2528                        try:
2529                            param_max = float(item[6].GetValue())
2530                            if not self._validate_qrange(item[2], item[6]):
2531                                if numpy.isfinite(param_max):
2532                                    item[2].SetValue(format_number(param_max))
2533                           
2534                            item[6].SetBackgroundColour(wx.WHITE)
2535                            item[2].SetBackgroundColour(wx.WHITE)
2536                        except:
2537                            msg = "Wrong Fit parameter range entered "
2538                            wx.PostEvent(self._manager.parent,
2539                                         StatusEvent(status=msg))
2540                            raise ValueError, msg
2541                        is_modified = True
2542               
2543                if param_min != None and param_max != None:
2544                    if not self._validate_qrange(item[5], item[6]):
2545                        msg = "Wrong Fit range entered for parameter "
2546                        msg += "name %s of model %s " % (name, self.model.name)
2547                        wx.PostEvent(self._manager.parent,
2548                                     StatusEvent(status=msg))
2549               
2550                if name in self.model.details.keys():
2551                    self.model.details[name][1:3] = param_min, param_max
2552                    is_modified = True
2553                else:
2554                    self.model.details[name] = ["", param_min, param_max]
2555                    is_modified = True
2556            try:
2557                # Check if the textctr is enabled
2558                if item[2].IsEnabled():
2559                    value = float(item[2].GetValue())
2560                    item[2].SetBackgroundColour("white")
2561                    # If the value of the parameter has changed,
2562                    # +update the model and set the is_modified flag
2563                    if value != self.model.getParam(name) and \
2564                                                numpy.isfinite(value):
2565                        self.model.setParam(name, value)
2566            except:
2567                item[2].SetBackgroundColour("pink")
2568                msg = "Wrong Fit parameter value entered "
2569                wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2570               
2571        return is_modified
2572       
2573    def _set_dipers_Param(self, event):
2574        """
2575        respond to self.enable_disp and self.disable_disp radio box.
2576        The dispersity object is reset inside the model into Gaussian.
2577        When the user select yes , this method display a combo box for
2578        more selection when the user selects No,the combo box disappears.
2579        Redraw the model with the default dispersity (Gaussian)
2580        """
2581        ## On selction if no model exists.
2582        if self.model == None:
2583            self.disable_disp.SetValue(True)
2584            msg = "Please select a Model first..."
2585            wx.MessageBox(msg, 'Info')
2586            wx.PostEvent(self._manager.parent,
2587                         StatusEvent(status="Polydispersion: %s" % msg))
2588            return
2589
2590        self._reset_dispersity()
2591   
2592        if self.model == None:
2593            self.model_disp.Hide()
2594            self.sizer4_4.Clear(True)
2595            return
2596
2597        if self.enable_disp.GetValue():
2598            ## layout for model containing no dispersity parameters
2599           
2600            self.disp_list = self.model.getDispParamList()
2601             
2602            if len(self.disp_list) == 0 and len(self.disp_cb_dict) == 0:
2603                self._layout_sizer_noDipers()
2604            else:
2605                ## set gaussian sizer
2606                self._on_select_Disp(event=None)
2607        else:
2608            self.sizer4_4.Clear(True)
2609           
2610        ## post state to fit panel
2611        self.save_current_state()
2612        if event != None:
2613            event = PageInfoEvent(page=self)
2614            wx.PostEvent(self.parent, event)
2615        #draw the model with the current dispersity
2616        self._draw_model()
2617        self.sizer4_4.Layout()
2618        self.sizer5.Layout()
2619        self.Layout()
2620        self.Refresh()
2621         
2622    def _layout_sizer_noDipers(self):
2623        """
2624        Draw a sizer with no dispersity info
2625        """
2626        ix = 0
2627        iy = 1
2628        self.fittable_param = []
2629        self.fixed_param = []
2630        self.orientation_params_disp = []
2631       
2632        self.sizer4_4.Clear(True)
2633        text = "No polydispersity available for this model"
2634        model_disp = wx.StaticText(self, -1, text)
2635        self.sizer4_4.Add(model_disp, (iy, ix), (1, 1),
2636                          wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
2637        self.sizer4_4.Layout()
2638        self.sizer4.Layout()
2639   
2640    def _reset_dispersity(self):
2641        """
2642        put gaussian dispersity into current model
2643        """
2644        if len(self.param_toFit) > 0:
2645            for item in self.fittable_param:
2646                if item in self.param_toFit:
2647                    self.param_toFit.remove(item)
2648
2649            for item in self.orientation_params_disp:
2650                if item in self.param_toFit:
2651                    self.param_toFit.remove(item)
2652         
2653        self.fittable_param = []
2654        self.fixed_param = []
2655        self.orientation_params_disp = []
2656        self.values = {}
2657        self.weights = {}
2658     
2659        from sas.models.dispersion_models import GaussianDispersion
2660        if len(self.disp_cb_dict) == 0:
2661            self.save_current_state()
2662            self.sizer4_4.Clear(True)
2663            self.Layout()
2664            return
2665        if (len(self.disp_cb_dict) > 0):
2666            for p in self.disp_cb_dict:
2667                # The parameter was un-selected.
2668                # Go back to Gaussian model (with 0 pts)
2669                disp_model = GaussianDispersion()
2670               
2671                self._disp_obj_dict[p] = disp_model
2672                # Set the new model as the dispersion object
2673                # for the selected parameter
2674                try:
2675                    self.model.set_dispersion(p, disp_model)
2676                except:
2677
2678                    pass
2679
2680        ## save state into
2681        self.save_current_state()
2682        self.Layout()
2683        self.Refresh()
2684                 
2685    def _on_select_Disp(self, event):
2686        """
2687        allow selecting different dispersion
2688        self.disp_list should change type later .now only gaussian
2689        """
2690        self._set_sizer_dispersion()
2691
2692        ## Redraw the model
2693        self._draw_model()
2694        #self._undo.Enable(True)
2695        event = PageInfoEvent(page=self)
2696        wx.PostEvent(self.parent, event)
2697       
2698        self.sizer4_4.Layout()
2699        self.sizer4.Layout()
2700        self.SetupScrolling()
2701   
2702    def _on_disp_func(self, event=None):
2703        """
2704        Select a distribution function for the polydispersion
2705       
2706        :Param event: ComboBox event
2707        """
2708        # get ready for new event
2709        if event != None:
2710            event.Skip()
2711        # Get event object
2712        disp_box = event.GetEventObject()
2713
2714        # Try to select a Distr. function
2715        try:
2716            disp_box.SetBackgroundColour("white")
2717            selection = disp_box.GetCurrentSelection()
2718            param_name = disp_box.Name.split('.')[0]
2719            disp_name = disp_box.GetValue()
2720            dispersity = disp_box.GetClientData(selection)
2721   
2722            #disp_model =  GaussianDispersion()
2723            disp_model = dispersity()
2724            # Get param names to reset the values of the param
2725            name1 = param_name + ".width"
2726            name2 = param_name + ".npts"
2727            name3 = param_name + ".nsigmas"
2728            # Check Disp. function whether or not it is 'array'
2729            if disp_name.lower() == "array":
2730                value2 = ""
2731                value3 = ""
2732                value1 = self._set_array_disp(name=name1, disp=disp_model)
2733            else:
2734                self._del_array_values(name1)
2735                #self._reset_array_disp(param_name)
2736                self._disp_obj_dict[name1] = disp_model
2737                self.model.set_dispersion(param_name, disp_model)
2738                self.state._disp_obj_dict[name1] = disp_model
2739 
2740                value1 = str(format_number(self.model.getParam(name1), True))
2741                value2 = str(format_number(self.model.getParam(name2)))
2742                value3 = str(format_number(self.model.getParam(name3)))
2743            # Reset fittable polydispersin parameter value
2744            for item in self.fittable_param:
2745                if item[1] == name1:
2746                    item[2].SetValue(value1)
2747                    item[5].SetValue("")
2748                    item[6].SetValue("")
2749                    # Disable for array
2750                    if disp_name.lower() == "array":
2751                        item[0].SetValue(False)
2752                        item[0].Disable()
2753                        item[2].Disable()
2754                        item[3].Show(False)
2755                        item[4].Show(False)
2756                        item[5].Disable()
2757                        item[6].Disable()
2758                    else:
2759                        item[0].Enable()
2760                        item[2].Enable()
2761                        item[5].Enable()
2762                        item[6].Enable()
2763                    break
2764            # Reset fixed polydispersion params
2765            for item in self.fixed_param:
2766                if item[1] == name2:
2767                    item[2].SetValue(value2) 
2768                    # Disable Npts for array
2769                    if disp_name.lower() == "array":
2770                        item[2].Disable()
2771                    else:
2772                        item[2].Enable()
2773                if item[1] == name3:
2774                    item[2].SetValue(value3)
2775                    # Disable Nsigs for array
2776                    if disp_name.lower() == "array":
2777                        item[2].Disable()
2778                    else:
2779                        item[2].Enable()
2780               
2781            # Make sure the check box updated when all checked
2782            if self.cb1.GetValue():
2783                #self.select_all_param(None)
2784                self.get_all_checked_params()
2785
2786            # update params
2787            self._update_paramv_on_fit()
2788            # draw
2789            self._draw_model()
2790            self.Refresh()
2791        except:
2792            # Error msg
2793            msg = "Error occurred:"
2794            msg += " Could not select the distribution function..."
2795            msg += " Please select another distribution function."
2796            disp_box.SetBackgroundColour("pink")
2797            # Focus on Fit button so that users can see the pinky box
2798            self.btFit.SetFocus()
2799            wx.PostEvent(self._manager.parent,
2800                         StatusEvent(status=msg, info="error"))
2801       
2802    def _set_array_disp(self, name=None, disp=None):
2803        """
2804        Set array dispersion
2805       
2806        :param name: name of the parameter for the dispersion to be set
2807        :param disp: the polydisperion object
2808        """
2809        # The user wants this parameter to be averaged.
2810        # Pop up the file selection dialog.
2811        path = self._selectDlg()
2812        # Array data
2813        values = []
2814        weights = []
2815        # If nothing was selected, just return
2816        if path is None:
2817            self.disp_cb_dict[name].SetValue(False)
2818            #self.noDisper_rbox.SetValue(True)
2819            return
2820        self._default_save_location = os.path.dirname(path)
2821        if self._manager != None:
2822            self._manager.parent._default_save_location =\
2823                             self._default_save_location
2824
2825        basename = os.path.basename(path)
2826        values, weights = self.read_file(path)
2827       
2828        # If any of the two arrays is empty, notify the user that we won't
2829        # proceed
2830        if len(self.param_toFit) > 0:
2831            if name in self.param_toFit:
2832                self.param_toFit.remove(name)
2833
2834        # Tell the user that we are about to apply the distribution
2835        msg = "Applying loaded %s distribution: %s" % (name, path)
2836        wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2837        self._set_array_disp_model(name=name, disp=disp,
2838                                    values=values, weights=weights)
2839        return basename
2840   
2841    def _set_array_disp_model(self, name=None, disp=None,
2842                              values=[], weights=[]):
2843        """
2844        Set array dispersion model
2845       
2846        :param name: name of the parameter for the dispersion to be set
2847        :param disp: the polydisperion object
2848        """
2849        disp.set_weights(values, weights)
2850        self._disp_obj_dict[name] = disp
2851        self.model.set_dispersion(name.split('.')[0], disp)
2852        self.state._disp_obj_dict[name] = disp
2853        self.values[name] = values
2854        self.weights[name] = weights
2855        # Store the object to make it persist outside the
2856        # scope of this method
2857        #TODO: refactor model to clean this up?
2858        self.state.values = {}
2859        self.state.weights = {}
2860        self.state.values = copy.deepcopy(self.values)
2861        self.state.weights = copy.deepcopy(self.weights)
2862
2863        # Set the new model as the dispersion object for the
2864        #selected parameter
2865        #self.model.set_dispersion(p, disp_model)
2866        # Store a reference to the weights in the model object
2867        #so that
2868        # it's not lost when we use the model within another thread.
2869        self.state.model = self.model.clone()
2870        self.model._persistency_dict[name.split('.')[0]] = \
2871                                        [values, weights]
2872        self.state.model._persistency_dict[name.split('.')[0]] = \
2873                                        [values, weights]
2874                                       
2875    def _del_array_values(self, name=None):
2876        """
2877        Reset array dispersion
2878       
2879        :param name: name of the parameter for the dispersion to be set
2880        """
2881        # Try to delete values and weight of the names array dic if exists
2882        try:
2883            del self.values[name]
2884            del self.weights[name]
2885            # delete all other dic
2886            del self.state.values[name]
2887            del self.state.weights[name]
2888            del self.model._persistency_dict[name.split('.')[0]]
2889            del self.state.model._persistency_dict[name.split('.')[0]]
2890        except:
2891            pass
2892                                           
2893    def _lay_out(self):
2894        """
2895        returns self.Layout
2896       
2897        :Note: Mac seems to like this better when self.
2898            Layout is called after fitting.
2899        """
2900        self._sleep4sec()
2901        self.Layout()
2902        return
2903   
2904    def _sleep4sec(self):
2905        """
2906            sleep for 1 sec only applied on Mac
2907            Note: This 1sec helps for Mac not to crash on self.
2908            Layout after self._draw_model
2909        """
2910        if ON_MAC == True:
2911            time.sleep(1)
2912           
2913    def _find_polyfunc_selection(self, disp_func=None):
2914        """
2915        FInd Comboox selection from disp_func
2916       
2917        :param disp_function: dispersion distr. function
2918        """
2919        # List of the poly_model name in the combobox
2920        list = ["RectangleDispersion", "ArrayDispersion",
2921                "LogNormalDispersion", "GaussianDispersion",
2922                "SchulzDispersion"]
2923
2924        # Find the selection
2925        try:
2926            selection = list.index(disp_func.__class__.__name__)
2927            return selection
2928        except:
2929            return 3
2930                           
2931    def on_reset_clicked(self, event):
2932        """
2933        On 'Reset' button  for Q range clicked
2934        """
2935        flag = True
2936        ##For 3 different cases: Data2D, Data1D, and theory
2937        if self.model == None:
2938            msg = "Please select a model first..."
2939            wx.MessageBox(msg, 'Info')
2940            flag = False
2941            return
2942           
2943        elif self.data.__class__.__name__ == "Data2D":
2944            data_min = 0
2945            x = max(math.fabs(self.data.xmin), math.fabs(self.data.xmax))
2946            y = max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
2947            self.qmin_x = data_min
2948            self.qmax_x = math.sqrt(x*x + y*y)
2949            #self.data.mask = numpy.ones(len(self.data.data),dtype=bool)
2950            # check smearing
2951            if not self.disable_smearer.GetValue():
2952                ## set smearing value whether or
2953                # not the data contain the smearing info
2954                if self.pinhole_smearer.GetValue():
2955                    flag = self.update_pinhole_smear()
2956                else:
2957                    flag = True
2958                   
2959        elif self.data == None:
2960            self.qmin_x = _QMIN_DEFAULT
2961            self.qmax_x = _QMAX_DEFAULT
2962            self.num_points = _NPTS_DEFAULT
2963            self.state.npts = self.num_points
2964           
2965        elif self.data.__class__.__name__ != "Data2D":
2966            self.qmin_x = min(self.data.x)
2967            self.qmax_x = max(self.data.x)
2968            # check smearing
2969            if not self.disable_smearer.GetValue():
2970                ## set smearing value whether or
2971                # not the data contain the smearing info
2972                if self.slit_smearer.GetValue():
2973                    flag = self.update_slit_smear()
2974                elif self.pinhole_smearer.GetValue():
2975                    flag = self.update_pinhole_smear()
2976                else:
2977                    flag = True
2978        else:
2979            flag = False
2980           
2981        if flag == False:
2982            msg = "Cannot Plot :Must enter a number!!!  "
2983            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2984        else:
2985            # set relative text ctrs.
2986            self.qmin.SetValue(str(self.qmin_x))
2987            self.qmax.SetValue(str(self.qmax_x))
2988            self.show_npts2fit()
2989            # At this point, some button and variables satatus (disabled?)
2990            # should be checked such as color that should be reset to
2991            # white in case that it was pink.
2992            self._onparamEnter_helper()
2993
2994        self.save_current_state()
2995        self.state.qmin = self.qmin_x
2996        self.state.qmax = self.qmax_x
2997       
2998        #reset the q range values
2999        self._reset_plotting_range(self.state)
3000        self._draw_model()
3001       
3002    def select_log(self, event):
3003        """
3004        Log checked to generate log spaced points for theory model
3005        """
3006
3007    def get_images(self):
3008        """
3009        Get the images of the plots corresponding this panel for report
3010       
3011        : return graphs: list of figures
3012        : Need Move to guiframe
3013        """
3014        # set list of graphs
3015        graphs = []
3016        canvases = []
3017        res_item = None
3018        # call gui_manager
3019        gui_manager = self._manager.parent
3020        # loops through the panels [dic]
3021        for _, item2 in gui_manager.plot_panels.iteritems():
3022            data_title = self.data.group_id
3023            # try to get all plots belonging to this control panel
3024            try:
3025                g_id = item2.group_id
3026                if g_id == data_title or \
3027                        str(g_id).count("res" + str(self.graph_id)) or \
3028                        str(g_id).count(str(self.uid)) > 0:
3029                    if str(g_id).count("res" + str(self.graph_id)) > 0:
3030                        res_item = [item2.figure, item2.canvas]
3031                    else:
3032                        # append to the list
3033                        graphs.append(item2.figure)
3034                        canvases.append(item2.canvas) 
3035            except:
3036                # Not for control panels
3037                pass
3038        # Make sure the resduals plot goes to the last
3039        if res_item != None:
3040            graphs.append(res_item[0])
3041            canvases.append(res_item[1])
3042        # return the list of graphs
3043        return graphs, canvases
3044
3045    def on_model_help_clicked(self, event):
3046        """
3047        on 'More details' button
3048        """
3049        from sas.perspectives.fitting.help_panel import  HelpWindow
3050        from sas.models import get_data_path
3051       
3052        # Get models help model_function path
3053        path = get_data_path(media='media')
3054        model_path = os.path.join(path, "model_functions.html")
3055        if self.model == None:
3056            name = 'FuncHelp'
3057        else:
3058            name = self.formfactorbox.GetValue()
3059        frame = HelpWindow(None, -1, pageToOpen=model_path)
3060        # If model name exists and model is not a custom model
3061        #mod_cat = self.categorybox.GetStringSelection()
3062        if frame.rhelp.HasAnchor(name):
3063            frame.Show(True)
3064            frame.rhelp.ScrollToAnchor(name)
3065        else:
3066            if self.model != None:
3067                frame.Destroy()
3068                msg = 'Model description:\n'
3069                if str(self.model.description).rstrip().lstrip() == '':
3070                    msg += "Sorry, no information is available for this model."
3071                else:
3072                    msg += self.model.description + '\n'
3073                info = "Info"
3074                wx.MessageBox(msg, info)
3075            else:
3076                frame.Show(True)
3077
3078    def _on_mag_help(self, event):   
3079        """
3080        Magnetic angles help panel
3081        """
3082        from sas.perspectives.fitting.help_panel import  HelpWindow
3083        # Get models help model_function path
3084        #import sas.perspectives.fitting as fitmedia
3085        from sas.models import get_data_path
3086
3087        media = get_data_path(media='media')
3088        path = os.path.join(media, "mag_pic.html") 
3089        name = "Polar/Magnetic Angles"
3090        frame = HelpWindow(None, -1, 
3091                           title=' Help: Polarization/Magnetization Angles', 
3092                           pageToOpen=path, size=(865, 450))   
3093        try: 
3094            frame.splitter.DetachWindow(frame.lpanel)
3095            # Display only the right side one
3096            frame.lpanel.Hide() 
3097            frame.Show(True)
3098        except:
3099            frame.Destroy() 
3100            msg = 'Display Error\n'
3101            info = "Info"
3102            wx.MessageBox(msg, info)
3103
3104    def _on_mag_on(self, event):   
3105        """
3106        Magnetic Parameters ON/OFF
3107        """
3108        button = event.GetEventObject()
3109
3110        if button.GetLabel().count('ON') > 0:
3111            self.magnetic_on = True
3112            button.SetLabel("Magnetic OFF")
3113            m_value = 1.0e-06
3114            for key in self.model.magnetic_params:
3115                if key.count('M0') > 0:
3116                    self.model.setParam(key, m_value)
3117                    m_value += 0.5e-06
3118        else:
3119            self.magnetic_on = False
3120            button.SetLabel("Magnetic ON")
3121            for key in self.model.magnetic_params:
3122                if key.count('M0') > 0:
3123                    #reset mag value to zero fo safety
3124                    self.model.setParam(key, 0.0)
3125                   
3126        self.Show(False)   
3127        self.set_model_param_sizer(self.model)
3128        #self._set_sizer_dispersion()
3129        self.state.magnetic_on = self.magnetic_on
3130        self.SetupScrolling()
3131        self.Show(True)
3132           
3133    def on_pd_help_clicked(self, event):
3134        """
3135        Button event for PD help
3136        """
3137        from help_panel import  HelpWindow
3138        import sas.models as models
3139       
3140        # Get models help model_function path
3141        path = models.get_data_path(media='media')
3142        pd_path = os.path.join(path, "pd_help.html")
3143
3144        frame = HelpWindow(None, -1, pageToOpen=pd_path)
3145        frame.Show(True)
3146       
3147    def on_left_down(self, event):
3148        """
3149        Get key stroke event
3150        """
3151        # Figuring out key combo: Cmd for copy, Alt for paste
3152        if event.CmdDown() and event.ShiftDown():
3153            self.get_paste()
3154        elif event.CmdDown():
3155            self.get_copy()
3156        else:
3157            event.Skip()
3158            return
3159        # make event free
3160        event.Skip()
3161       
3162    def get_copy(self):
3163        """
3164        Get copy params to clipboard
3165        """
3166        content = self.get_copy_params()
3167        flag = self.set_clipboard(content)
3168        self._copy_info(flag)
3169        return flag
3170           
3171    def get_copy_params(self):
3172        """
3173        Get the string copies of the param names and values in the tap
3174        """
3175        content = 'sasview_parameter_values:'
3176        # Do it if params exist
3177        if  self.parameters != []:
3178           
3179            # go through the parameters
3180            strings = self._get_copy_helper(self.parameters,
3181                                           self.orientation_params)
3182            content += strings
3183           
3184            # go through the fittables
3185            strings = self._get_copy_helper(self.fittable_param,
3186                                           self.orientation_params_disp)
3187            content += strings
3188
3189            # go through the fixed params
3190            strings = self._get_copy_helper(self.fixed_param,
3191                                           self.orientation_params_disp)
3192            content += strings
3193               
3194            # go through the str params
3195            strings = self._get_copy_helper(self.str_parameters,
3196                                           self.orientation_params)
3197            content += strings
3198            return content
3199        else:
3200            return False
3201
3202    def get_copy_excel(self):
3203        """
3204        Get copy params to clipboard
3205        """
3206        content = self.get_copy_params_excel()
3207        flag = self.set_clipboard(content)
3208        self._copy_info(flag)
3209        return flag
3210
3211    def get_copy_params_excel(self):
3212        """
3213        Get the string copies of the param names and values in the tap
3214        """
3215        content = ''
3216
3217        crlf = chr(13) + chr(10)
3218        tab = chr(9)
3219
3220        # Do it if params exist
3221        if  self.parameters != []:
3222
3223            for param in self.parameters:
3224                content += param[1] #parameter name
3225                content += tab
3226                content += param[1]+"_err"
3227                content += tab
3228
3229            content += crlf
3230
3231            #row of values and errors...
3232            for param in self.parameters:
3233                content += param[2].GetValue() #value
3234                content +=tab
3235                content += param[4].GetValue() #error
3236                content +=tab
3237
3238            return content
3239        else:
3240            return False
3241
3242
3243    def get_copy_latex(self):
3244        """
3245        Get copy params to clipboard
3246        """
3247        content = self.get_copy_params_latex()
3248        flag = self.set_clipboard(content)
3249        self._copy_info(flag)
3250        return flag
3251
3252    def get_copy_params_latex(self):
3253        """
3254        Get the string copies of the param names and values in the tap
3255        """
3256        content = '\\begin{table}'
3257        content += '\\begin{tabular}[h]'
3258
3259        crlf = chr(13) + chr(10)
3260        tab = chr(9)
3261
3262        # Do it if params exist
3263        if  self.parameters != []:
3264
3265            content += '{|'
3266            for param in self.parameters:
3267                content += 'l|l|'
3268            content += '}\hline'
3269            content += crlf
3270
3271            for index, param in enumerate(self.parameters):
3272                content += param[1].replace('_','\_') #parameter name
3273                content += ' & '
3274                content += param[1].replace('_','\_')+"\_err"
3275                if index < len(self.parameters)-1:
3276                    content += ' & '
3277            content += '\\\\ \\hline'
3278            content += crlf
3279
3280            #row of values and errors...
3281            for index, param in enumerate(self.parameters):
3282                content += param[2].GetValue() #parameter value
3283                content += ' & '
3284                content += param[4].GetValue() #parameter error
3285                if index < len(self.parameters)-1:
3286                    content += ' & '
3287            content += '\\\\ \\hline'
3288            content += crlf
3289
3290            content += '\\end{tabular}'
3291            content += '\\end{table}'
3292            return content
3293        else:
3294            return False
3295
3296
3297    def set_clipboard(self, content=None):
3298        """
3299        Put the string to the clipboard
3300        """
3301        if not content:
3302            return False
3303        if wx.TheClipboard.Open():
3304            wx.TheClipboard.SetData(wx.TextDataObject(str(content)))
3305            wx.TheClipboard.Close()
3306            return True
3307        return None
3308   
3309    def _get_copy_helper(self, param, orient_param):
3310        """
3311        Helping get value and name of the params
3312       
3313        : param param:  parameters
3314        : param orient_param = oritational params
3315        : return content: strings [list] [name,value:....]
3316        """
3317        content = ''
3318        # go through the str params
3319        for item in param:
3320            # copy only the params shown
3321            if not item[2].IsShown():
3322                continue
3323            disfunc = ''
3324            try:
3325                if item[7].__class__.__name__ == 'ComboBox':
3326                    disfunc = str(item[7].GetValue())
3327            except:
3328                pass
3329           
3330            # 2D
3331            if self.data.__class__.__name__ == "Data2D":
3332                try:
3333                    check = item[0].GetValue()
3334                except:
3335                    check = None
3336                name = item[1]
3337                value = item[2].GetValue()
3338            # 1D
3339            else:
3340                ## for 1D all parameters except orientation
3341                if not item[1] in orient_param:
3342                    try:
3343                        check = item[0].GetValue()
3344                    except:
3345                        check = None
3346                    name = item[1]
3347                    value = item[2].GetValue()
3348
3349            # add to the content
3350            if disfunc != '':
3351               
3352                disfunc = ',' + disfunc
3353            # Need to support array func for copy/paste
3354            try:
3355                if disfunc.count('array') > 0:
3356                    disfunc += ','
3357                    for val in self.values[name]:
3358                        disfunc += ' ' + str(val)
3359                    disfunc += ','
3360                    for weight in self.weights[name]:
3361                        disfunc += ' ' + str(weight)
3362            except:
3363                pass
3364            content += name + ',' + str(check) + ',' + value + disfunc + ':'
3365
3366        return content
3367   
3368    def get_clipboard(self):
3369        """
3370        Get strings in the clipboard
3371        """
3372        text = ""
3373        # Get text from the clip board
3374        if wx.TheClipboard.Open():
3375            if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
3376                data = wx.TextDataObject()
3377                # get wx dataobject
3378                success = wx.TheClipboard.GetData(data)
3379                # get text
3380                if success:
3381                    text = data.GetText()
3382                else:
3383                    text = ''
3384            # close clipboard
3385            wx.TheClipboard.Close()
3386        return text
3387   
3388    def get_paste(self):
3389        """
3390        Paste params from the clipboard
3391        """
3392        text = self.get_clipboard()
3393        flag = self.get_paste_params(text)
3394        self._copy_info(flag)
3395        return flag
3396       
3397    def get_paste_params(self, text=''):
3398        """
3399        Get the string copies of the param names and values in the tap
3400        """
3401        context = {}
3402        # put the text into dictionary
3403        lines = text.split(':')
3404        if lines[0] != 'sasview_parameter_values':
3405            self._copy_info(False)
3406            return False
3407        for line in lines[1:-1]:
3408            if len(line) != 0:
3409                item = line.split(',')
3410                check = item[1]
3411                name = item[0]
3412                value = item[2]
3413                # Transfer the text to content[dictionary]
3414                context[name] = [check, value]
3415            # ToDo: PlugIn this poly disp function for pasting
3416            try:
3417                poly_func = item[3]
3418                context[name].append(poly_func)
3419                try:
3420                    # take the vals and weights for  array
3421                    array_values = item[4].split(' ')
3422                    array_weights = item[5].split(' ')
3423                    val = [float(a_val) for a_val in array_values[1:]]
3424                    weit = [float(a_weit) for a_weit in array_weights[1:]]
3425                   
3426                    context[name].append(val)
3427                    context[name].append(weit)
3428                except:
3429                    raise
3430            except:
3431                poly_func = ''
3432                context[name].append(poly_func)
3433
3434        # Do it if params exist
3435        if  self.parameters != []:
3436            # go through the parameters
3437            self._get_paste_helper(self.parameters,
3438                                   self.orientation_params, context)
3439
3440            # go through the fittables
3441            self._get_paste_helper(self.fittable_param,
3442                                   self.orientation_params_disp,
3443                                   context)
3444
3445            # go through the fixed params
3446            self._get_paste_helper(self.fixed_param,
3447                                   self.orientation_params_disp, context)
3448           
3449            # go through the str params
3450            self._get_paste_helper(self.str_parameters,
3451                                   self.orientation_params, context)
3452               
3453            return True
3454        return None
3455   
3456    def _get_paste_helper(self, param, orient_param, content):
3457        """
3458        Helping set values of the params
3459       
3460        : param param:  parameters
3461        : param orient_param: oritational params
3462        : param content: dictionary [ name, value: name1.value1,...]
3463        """
3464        # go through the str params
3465        for item in param:
3466            # 2D
3467            if self.data.__class__.__name__ == "Data2D":
3468                name = item[1]
3469                if name in content.keys():
3470                    check = content[name][0]
3471                    pd = content[name][1]
3472                    if name.count('.') > 0:
3473                        try:
3474                            float(pd)
3475                        except:
3476                            #continue
3477                            if not pd and pd != '':
3478                                continue
3479                    item[2].SetValue(str(pd))
3480                    if item in self.fixed_param and pd == '':
3481                        # Only array func has pd == '' case.
3482                        item[2].Enable(False)
3483                    if item[2].__class__.__name__ == "ComboBox":
3484                        if content[name][1] in self.model.fun_list:
3485                            fun_val = self.model.fun_list[content[name][1]]
3486                            self.model.setParam(name, fun_val)
3487                   
3488                    value = content[name][1:]
3489                    self._paste_poly_help(item, value)
3490                    if check == 'True':
3491                        is_true = True
3492                    elif check == 'False':
3493                        is_true = False
3494                    else:
3495                        is_true = None
3496                    if is_true != None:
3497                        item[0].SetValue(is_true)
3498            # 1D
3499            else:
3500                ## for 1D all parameters except orientation
3501                if not item[1] in orient_param:
3502                    name = item[1]
3503                    if name in content.keys():
3504                        check = content[name][0]
3505                        # Avoid changing combox content
3506                        value = content[name][1:]
3507                        pd = value[0]
3508                        if name.count('.') > 0:
3509                            try:
3510                                pd = float(pd)
3511                            except:
3512                                #continue
3513                                if not pd and pd != '':
3514                                    continue
3515                        item[2].SetValue(str(pd))
3516                        if item in self.fixed_param and pd == '':
3517                            # Only array func has pd == '' case.
3518                            item[2].Enable(False)
3519                        if item[2].__class__.__name__ == "ComboBox":
3520                            if value[0] in self.model.fun_list:
3521                                fun_val = self.model.fun_list[value[0]]
3522                                self.model.setParam(name, fun_val)
3523                                # save state
3524                        self._paste_poly_help(item, value)
3525                        if check == 'True':
3526                            is_true = True
3527                        elif check == 'False':
3528                            is_true = False
3529                        else:
3530                            is_true = None
3531                        if is_true != None:
3532                            item[0].SetValue(is_true)
3533                       
3534    def _paste_poly_help(self, item, value):
3535        """
3536        Helps get paste for poly function
3537       
3538        :param item: Gui param items
3539        :param value: the values for parameter ctrols
3540        """
3541        is_array = False
3542        if len(value[1]) > 0:
3543            # Only for dispersion func.s
3544            try:
3545                item[7].SetValue(value[1])
3546                selection = item[7].GetCurrentSelection()
3547                name = item[7].Name
3548                param_name = name.split('.')[0]
3549                dispersity = item[7].GetClientData(selection)
3550                disp_model = dispersity()
3551                # Only for array disp
3552                try:
3553                    pd_vals = numpy.array(value[2])
3554                    pd_weights = numpy.array(value[3])
3555                    if len(pd_vals) > 0 and len(pd_vals) > 0:
3556                        if len(pd_vals) == len(pd_weights):
3557                            self._set_disp_array_cb(item=item)
3558                            self._set_array_disp_model(name=name,
3559                                                       disp=disp_model,
3560                                                       values=pd_vals,
3561                                                       weights=pd_weights)
3562                            is_array = True
3563                except:
3564                    pass
3565                if not is_array:
3566                    self._disp_obj_dict[name] = disp_model
3567                    self.model.set_dispersion(name,
3568                                              disp_model)
3569                    self.state._disp_obj_dict[name] = \
3570                                              disp_model
3571                    self.model.set_dispersion(param_name, disp_model)
3572                    self.state.values = self.values
3573                    self.state.weights = self.weights
3574                    self.model._persistency_dict[param_name] = \
3575                                            [self.state.values,
3576                                             self.state.weights]
3577                         
3578            except:
3579                print "Error in BasePage._paste_poly_help: %s" % sys.exc_value
3580   
3581    def _set_disp_array_cb(self, item):
3582        """
3583        Set cb for array disp
3584        """
3585        item[0].SetValue(False)
3586        item[0].Enable(False)
3587        item[2].Enable(False)
3588        item[3].Show(False)
3589        item[4].Show(False)
3590        item[5].SetValue('')
3591        item[5].Enable(False)
3592        item[6].SetValue('')
3593        item[6].Enable(False)
3594       
3595    def update_pinhole_smear(self):
3596        """
3597            Method to be called by sub-classes
3598            Moveit; This method doesn't belong here
3599        """
3600        print "BasicPage.update_pinhole_smear was called: skipping"
3601        return
3602
3603
3604
3605
3606    def _read_category_info(self):
3607        """
3608        Reads the categories in from file
3609        """
3610
3611        # # ILL mod starts here - July 2012 kieranrcampbell@gmail.com
3612        self.master_category_dict = defaultdict(list)
3613        self.by_model_dict = defaultdict(list)
3614        self.model_enabled_dict = defaultdict(bool)
3615
3616        try:
3617            categorization_file = CategoryInstaller.get_user_file()
3618            if not os.path.isfile(categorization_file):
3619                categorization_file = CategoryInstaller.get_default_file()
3620            cat_file = open(categorization_file, 'rb')                           
3621            self.master_category_dict = json.load(cat_file)
3622            self._regenerate_model_dict()
3623            cat_file.close()
3624
3625        except IOError:
3626            raise
3627            print 'Problem reading in category file.'
3628            print 'We even looked for it, made sure it was there.'
3629            print 'An existential crisis if there ever was one.'
3630
3631    def _regenerate_model_dict(self):
3632        """
3633        regenerates self.by_model_dict which has each model name as the
3634        key and the list of categories belonging to that model
3635        along with the enabled mapping
3636        """
3637
3638        self.by_model_dict = defaultdict(list)
3639        for category in self.master_category_dict:
3640            for (model, enabled) in self.master_category_dict[category]:
3641                self.by_model_dict[model].append(category)
3642                self.model_enabled_dict[model] = enabled
3643   
3644    def _populate_listbox(self):
3645        """
3646        fills out the category list box
3647        """
3648        uncat_str = 'Customized Models'
3649        self._read_category_info()
3650
3651        self.categorybox.Clear()
3652        cat_list = sorted(self.master_category_dict.keys())
3653        if not uncat_str in cat_list:
3654            cat_list.append(uncat_str)
3655       
3656        for category in cat_list:
3657            if category != '':
3658                self.categorybox.Append(category)
3659
3660        if self.categorybox.GetSelection() == wx.NOT_FOUND:
3661            self.categorybox.SetSelection(0)
3662        else:
3663            self.categorybox.SetSelection( \
3664                self.categorybox.GetSelection())
3665
3666        #self._on_change_cat(None)
3667
3668
3669    def _on_change_cat(self, event):
3670        """
3671        Callback for category change action
3672        """
3673        self.model_name = None
3674        category = self.categorybox.GetStringSelection()
3675        if category == None:
3676            return
3677        self.model_box.Clear()
3678
3679        if category == 'Customized Models':
3680            for model in self.model_list_box[category]:
3681                str_m = str(model).split(".")[0]
3682                self.model_box.Append(str_m)
3683
3684        else:
3685            for (model,enabled) in sorted(self.master_category_dict[category],
3686                                      key = lambda name: name[0]):
3687                if(enabled):
3688                    self.model_box.Append(model)
3689
3690
3691
3692
3693    def _fill_model_sizer(self, sizer):
3694        """
3695        fill sizer containing model info
3696        """
3697        ##Add model function Details button in fitpanel.
3698        ##The following 3 lines are for Mac. Let JHC know before modifying...
3699        title = "Model"
3700        self.formfactorbox = None
3701        self.multifactorbox = None
3702        self.mbox_description = wx.StaticBox(self, -1, str(title))
3703        boxsizer1 = wx.StaticBoxSizer(self.mbox_description, wx.VERTICAL)
3704        sizer_cat = wx.BoxSizer(wx.HORIZONTAL)
3705        self.mbox_description.SetForegroundColour(wx.RED)
3706        id = wx.NewId()
3707        self.model_help = wx.Button(self, id, 'Details', size=(80, 23))
3708        self.model_help.Bind(wx.EVT_BUTTON, self.on_model_help_clicked, id=id)
3709        self.model_help.SetToolTipString("Model Function Help")
3710        id = wx.NewId()
3711        self.model_view = wx.Button(self, id, "Show 2D", size=(80, 23))
3712        self.model_view.Bind(wx.EVT_BUTTON, self._onModel2D, id=id)
3713        hint = "toggle view of model from 1D to 2D  or 2D to 1D"
3714        self.model_view.SetToolTipString(hint)
3715       
3716        cat_set_box = wx.StaticBox(self, -1, 'Category')
3717        sizer_cat_box = wx.StaticBoxSizer(cat_set_box, wx.HORIZONTAL)
3718        sizer_cat_box.SetMinSize((200, 50))
3719        self.categorybox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
3720        self.categorybox.SetToolTip( wx.ToolTip("Select a Category/Type") )
3721        self._populate_listbox()
3722        wx.EVT_COMBOBOX(self.categorybox, -1, self._show_combox)
3723        #self.shape_rbutton = wx.RadioButton(self, -1, 'Shapes',
3724        #                                     style=wx.RB_GROUP)
3725        #self.shape_indep_rbutton = wx.RadioButton(self, -1,
3726        #                                          "Shape-Independent")
3727        #self.struct_rbutton = wx.RadioButton(self, -1, "Structure Factor ")
3728        #self.plugin_rbutton = wx.RadioButton(self, -1, "Uncategorized")
3729               
3730        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3731        #                   id=self.shape_rbutton.GetId())
3732        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3733        #                    id=self.shape_indep_rbutton.GetId())
3734        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3735        #                    id=self.struct_rbutton.GetId())
3736        #self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
3737        #                    id=self.plugin_rbutton.GetId())
3738        #MAC needs SetValue
3739       
3740        show_cat_button = wx.Button(self, -1, "Modify")
3741        cat_tip = "Modify model categories \n"
3742        cat_tip += "(also accessible from the menu bar)."
3743        show_cat_button.SetToolTip( wx.ToolTip(cat_tip) )
3744        show_cat_button.Bind(wx.EVT_BUTTON, self._on_modify_cat)
3745        sizer_cat_box.Add(self.categorybox, 1, wx.RIGHT, 3)
3746        sizer_cat_box.Add((10,10))
3747        sizer_cat_box.Add(show_cat_button)
3748        #self.shape_rbutton.SetValue(True)
3749     
3750        sizer_radiobutton = wx.GridSizer(2, 2, 5, 5)
3751
3752        #sizer_radiobutton.Add(self.shape_rbutton)
3753        #sizer_radiobutton.Add(self.shape_indep_rbutton)
3754        sizer_radiobutton.Add((5,5))
3755        sizer_radiobutton.Add(self.model_view, 1, wx.RIGHT, 15)
3756        #sizer_radiobutton.Add(self.plugin_rbutton)
3757        #sizer_radiobutton.Add(self.struct_rbutton)
3758        sizer_radiobutton.Add((5,5))
3759        sizer_radiobutton.Add(self.model_help, 1, wx.RIGHT, 15)
3760        sizer_cat.Add(sizer_cat_box, 1, wx.LEFT, 2.5)
3761        sizer_cat.Add(sizer_radiobutton)
3762        sizer_selection = wx.BoxSizer(wx.HORIZONTAL)
3763        mutifactor_selection = wx.BoxSizer(wx.HORIZONTAL)
3764       
3765        self.text1 = wx.StaticText(self, -1, "")
3766        self.text2 = wx.StaticText(self, -1, "P(Q)*S(Q)")
3767        self.mutifactor_text = wx.StaticText(self, -1, "No. of Shells: ")
3768        self.mutifactor_text1 = wx.StaticText(self, -1, "")
3769        self.show_sld_button = wx.Button(self, -1, "Show SLD Profile")
3770        self.show_sld_button.Bind(wx.EVT_BUTTON, self._on_show_sld)
3771
3772        self.formfactorbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
3773        self.formfactorbox.SetToolTip( wx.ToolTip("Select a Model") )
3774        if self.model != None:
3775            self.formfactorbox.SetValue(self.model.name)
3776        self.structurebox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
3777        self.multifactorbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
3778        self.initialize_combox()
3779        wx.EVT_COMBOBOX(self.formfactorbox, -1, self._on_select_model)
3780
3781        wx.EVT_COMBOBOX(self.structurebox, -1, self._on_select_model)
3782        wx.EVT_COMBOBOX(self.multifactorbox, -1, self._on_select_model)
3783        ## check model type to show sizer
3784        if self.model != None:
3785            print "_set_model_sizer_selection: disabled."
3786            #self._set_model_sizer_selection(self.model)
3787       
3788        sizer_selection.Add(self.text1)
3789        sizer_selection.Add((10, 5))
3790        sizer_selection.Add(self.formfactorbox)
3791        sizer_selection.Add((5, 5))
3792        sizer_selection.Add(self.text2)
3793        sizer_selection.Add((5, 5))
3794        sizer_selection.Add(self.structurebox)
3795       
3796        mutifactor_selection.Add((13, 5))
3797        mutifactor_selection.Add(self.mutifactor_text)
3798        mutifactor_selection.Add(self.multifactorbox)
3799        mutifactor_selection.Add((5, 5))
3800        mutifactor_selection.Add(self.mutifactor_text1)
3801        mutifactor_selection.Add((10, 5))
3802        mutifactor_selection.Add(self.show_sld_button)
3803
3804        boxsizer1.Add(sizer_cat)
3805        boxsizer1.Add((10, 10))
3806        boxsizer1.Add(sizer_selection)
3807        boxsizer1.Add((10, 10))
3808        boxsizer1.Add(mutifactor_selection)
3809       
3810        self._set_multfactor_combobox()
3811        self.multifactorbox.SetSelection(1)
3812        self.show_sld_button.Hide()
3813        sizer.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
3814        sizer.Layout()
3815       
3816    def on_smear_helper(self, update=False):
3817        """
3818        Help for onSmear if implemented
3819       
3820        :param update: force or not to update
3821        """
3822    def reset_page(self, state, first=False):
3823        """
3824        reset the state  if implemented
3825        """
3826    def onSmear(self, event):
3827        """
3828        Create a smear object if implemented
3829        """
3830    def onPinholeSmear(self, event):
3831        """
3832        Create a custom pinhole smear object if implemented
3833        """
3834    def onSlitSmear(self, event):
3835        """
3836        Create a custom slit smear object if implemented
3837        """
3838    def update_slit_smear(self):
3839        """
3840        called by kill_focus on pinhole TextCntrl
3841        to update the changes if implemented
3842        """
3843    def select_param(self, event):
3844        """
3845        Select TextCtrl  checked if implemented
3846        """
3847    def set_data(self, data=None):
3848        """
3849        Sets data if implemented
3850        """
3851    def _is_2D(self):
3852        """
3853        Check if data_name is Data2D if implemented
3854        """
3855    def _on_select_model(self, event=None):
3856        """
3857        call back for model selection if implemented
3858        """
3859    def select_all_param(self, event):
3860        """
3861        set to true or false all checkBox if implemented
3862        """
3863    def get_weight_flag(self):
3864        """
3865        Get flag corresponding to a given weighting dI data if implemented
3866        """
3867    def _set_sizer_dispersion(self):
3868        """
3869        draw sizer for dispersity if implemented
3870        """
3871    def get_all_checked_params(self):
3872        """
3873        Found all parameters current check and add them to list of parameters
3874        to fit if implemented
3875        """
3876    def show_npts2fit(self):
3877        """
3878        setValue Npts for fitting if implemented
3879        """
3880    def _onModel2D(self, event):
3881        """
3882        toggle view of model from 1D to 2D  or 2D from 1D if implemented
3883        """
Note: See TracBrowser for help on using the repository browser.