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

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

fixed updating on compute for batch plot

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