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

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 e1bc51d was b582d6bc, checked in by Jae Cho <jhjcho@…>, 13 years ago

fixed a bug that generated a new theory plot on qrange enter

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