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

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 0d9401e was 0d9401e, checked in by butler, 8 years ago

Removed a chunck of obsolete code starting at line 1863

The code had been commeted out in April of 2014 as no longer being
called. Since no problems have been noted to this point have cleaned it
up by deleting.

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