source: sasview/src/sans/perspectives/fitting/basepage.py @ 34dbaf4

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 34dbaf4 was 34dbaf4, checked in by ajj, 10 years ago

Added options to copy parameters from a single fit panel as tab delimited for pasting into Excel, Igor etc and as a latex table.

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