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

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

let users be able to delete default custom models (WIN app only)

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