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

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

finished implementation of custom model editor unless one finds bugs

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