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

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

Oops corrected wrong flag

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