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

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 f7f6886 was f7ef313, checked in by Gervaise Alina <gervyh@…>, 13 years ago

allow computing the weight of series of data

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