source: sasview/src/sas/perspectives/fitting/basepage.py @ 5ce7f17

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 5ce7f17 was 5ce7f17, checked in by krzywon, 9 years ago

Fix for ticket #395 - Saving a project now saves all fits and loading a
project no longer throws an error by trying to find deprecated fitting
engines.

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