source: sasview/fittingview/src/sans/perspectives/fitting/basepage.py @ 334c50d

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 334c50d was 0d795bf, checked in by Jae Cho <jhjcho@…>, 12 years ago

more fixes in saving custom slit information

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