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

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

fixed problems in custom pinhole and slit states

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