source: sasview/src/sas/sasgui/perspectives/fitting/simfitpage.py @ 4ee041f

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 4ee041f was d85c194, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 9 years ago

Remaining modules refactored

  • Property mode set to 100644
File size: 37.8 KB
Line 
1"""
2    Simultaneous fit page
3"""
4import sys
5from collections import namedtuple
6
7import wx
8import wx.lib.newevent
9from wx.lib.scrolledpanel import ScrolledPanel
10
11from sas.sasgui.guiframe.events import StatusEvent
12from sas.sasgui.guiframe.panel_base import PanelBase
13from sas.sasgui.guiframe.events import PanelOnFocusEvent
14from sas.sasgui.guiframe.utils import IdList
15from sas.sasgui.guiframe.documentation_window import DocumentationWindow
16
17#Control panel width
18if sys.platform.count("darwin") == 0:
19    PANEL_WID = 420
20    FONT_VARIANT = 0
21else:
22    PANEL_WID = 490
23    FONT_VARIANT = 1
24
25
26# Each constraint requires five widgets and sizer.  Package them in
27# a named tuple for easy access.
28ConstraintLine = namedtuple('ConstraintLine',
29        'model_cbox param_cbox egal_txt constraint btRemove sizer')
30
31def get_fittableParam(model):
32    """
33    return list of fittable parameters from a model
34
35    :param model: the model used
36
37    """
38    fittable_param = []
39    for item in model.getParamList():
40        if not item  in model.getDispParamList():
41            if not item in model.non_fittable:
42                fittable_param.append(item)
43
44    for item in model.fixed:
45        fittable_param.append(item)
46
47    return fittable_param
48
49class SimultaneousFitPage(ScrolledPanel, PanelBase):
50    """
51    Simultaneous fitting panel
52    All that needs to be defined are the
53    two data members window_name and window_caption
54    """
55    ## Internal name for the AUI manager
56    window_name = "simultaneous Fit page"
57    ## Title to appear on top of the window
58    window_caption = "Simultaneous Fit Page"
59    ID_DOC = wx.NewId()
60    ID_SET_ALL = wx.NewId()
61    ID_FIT = wx.NewId()
62    ID_ADD = wx.NewId()
63    _id_pool = IdList()
64
65    def __init__(self, parent, page_finder={}, id=wx.ID_ANY, batch_on=False,
66                 *args, **kwargs):
67        ScrolledPanel.__init__(self, parent, id=id,
68                               style=wx.FULL_REPAINT_ON_RESIZE,
69                               *args, **kwargs)
70        PanelBase.__init__(self, parent)
71        """
72        Simultaneous page display
73        """
74        self._ids = iter(self._id_pool)
75        self.SetupScrolling()
76        ##Font size
77        self.SetWindowVariant(variant=FONT_VARIANT)
78        self.uid = wx.NewId()
79        self.parent = parent
80        self.batch_on = batch_on
81        ## store page_finder
82        self.page_finder = page_finder
83        ## list containing info to set constraint
84        ## look like self.constraint_dict[page_id]= page
85        self.constraint_dict = {}
86        ## item list
87        ## self.constraints_list=[combobox1, combobox2,=,textcrtl, button ]
88        self.constraints_list = []
89        ## list of current model
90        self.model_list = []
91        ## selected mdoel to fit
92        self.model_toFit = []
93        ## number of constraint
94        self.nb_constraint = 0
95        self.model_cbox_left = None
96        self.model_cbox_right = None
97        ## draw page
98        self.define_page_structure()
99        self.draw_page()
100        self._set_save_flag(False)
101
102    def define_page_structure(self):
103        """
104        Create empty sizers, their hierarchy and set the sizer for the panel
105        """
106        self.vbox = wx.BoxSizer(wx.VERTICAL)
107        self.sizer1 = wx.BoxSizer(wx.VERTICAL)
108        self.sizer2 = wx.BoxSizer(wx.VERTICAL)
109        self.sizer3 = wx.BoxSizer(wx.VERTICAL)
110
111        self.sizer1.SetMinSize((PANEL_WID, -1))
112        self.sizer2.SetMinSize((PANEL_WID, -1))
113        self.sizer3.SetMinSize((PANEL_WID, -1))
114        self.vbox.Add(self.sizer1)
115        self.vbox.Add(self.sizer2)
116        self.vbox.Add(self.sizer3)
117        self.SetSizer(self.vbox)
118        self.Centre()
119
120    def draw_page(self):
121        """
122        Construct the Simultaneous/Constrained fit page. fills the first
123        region (sizer1) with the list of available fit page pairs of data
124        and models.  Then fills sizer2 with the checkbox for adding
125        constraints, and finally fills sizer3 with the fit button and
126        instructions.
127        """
128
129        # create blank list of constraints
130        self.model_list = []
131        self.model_toFit = []
132        self.constraints_list = []
133        self.constraint_dict = {}
134        self.nb_constraint = 0
135        self.model_cbox_left = None
136        self.model_cbox_right = None
137
138        if len(self.model_list) > 0:
139            for item in self.model_list:
140                item[0].SetValue(False)
141                self.manager.schedule_for_fit(value=0, uid=item[2])
142
143        #-------------------------------------------------------
144        ## setup sizer1 (which fitpages to include)
145        self.sizer1.Clear(True)
146        box_description = wx.StaticBox(self, wx.ID_ANY, "Fit Combinations")
147        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
148        sizer_title = wx.BoxSizer(wx.HORIZONTAL)
149        sizer_couples = wx.GridBagSizer(5, 5)
150
151        #This if statement should be obsolete and can be removed in version 4
152        #Leave it here for now as no time to thoroughly test.  However if no
153        #fit page is found the menu item that calls this page is inactive
154        # Nov. 22 2015  --PDB
155        if len(self.page_finder) == 0:
156            msg = " No fit combinations are found! \n\n"
157            msg += " Please load data and set up "
158            msg += "at least one fit panels first..."
159            sizer_title.Add(wx.StaticText(self, wx.ID_ANY, msg))
160        else:
161            ## store model
162            self._store_model()
163
164            self.cb1 = wx.CheckBox(self, wx.ID_ANY, 'Select all')
165            self.cb1.SetValue(False)
166            wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.check_all_model_name)
167
168            sizer_title.Add((10, 10), 0,
169                wx.TOP | wx.BOTTOM | wx.EXPAND | wx.ADJUST_MINSIZE, border=5)
170            sizer_title.Add(self.cb1, 0,
171                wx.TOP | wx.BOTTOM | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, border=5)
172
173            ## draw list of model and data names
174            self._fill_sizer_model_list(sizer_couples)
175
176        boxsizer1.Add(sizer_title, flag=wx.TOP | wx.BOTTOM, border=5)
177        boxsizer1.Add(sizer_couples, 1, flag=wx.TOP | wx.BOTTOM, border=5)
178        self.sizer1.Add(boxsizer1, 1, wx.EXPAND | wx.ALL, 10)
179#        self.sizer1.Layout()
180
181        #--------------------------------------------------------
182        ## set up the other 2 sizers: the constraints list and the
183        ## buttons (fit, help etc) sizer at the bottom of the page.
184        ## Note: the if statement should be removed along with the above
185        ## if statement as soon as it can be properly tested.
186        ## Nov. 22 2015  --PDB
187        if len(self.page_finder) > 0:
188            ## draw the sizer containing constraint info
189            if not self.batch_on:
190                self._fill_sizer_constraint()
191            ## draw fit button sizer
192            self._fill_sizer_fit()
193
194
195    def _fill_sizer_model_list(self, sizer):
196        """
197        Receive a dictionary containing information to display model name
198        """
199        ix = 0
200        iy = 0
201        list = []
202        sizer.Clear(True)
203
204        new_name = wx.StaticText(self, wx.ID_ANY, '  Model Title ',
205                                 style=wx.ALIGN_CENTER)
206        new_name.SetBackgroundColour('orange')
207        new_name.SetForegroundColour(wx.WHITE)
208        sizer.Add(new_name, (iy, ix), (1, 1),
209                            wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
210        ix += 2
211        model_type = wx.StaticText(self, wx.ID_ANY, '  Model ')
212        model_type.SetBackgroundColour('grey')
213        model_type.SetForegroundColour(wx.WHITE)
214        sizer.Add(model_type, (iy, ix), (1, 1),
215                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
216        ix += 1
217        data_used = wx.StaticText(self, wx.ID_ANY, '  Data ')
218        data_used.SetBackgroundColour('grey')
219        data_used.SetForegroundColour(wx.WHITE)
220        sizer.Add(data_used, (iy, ix), (1, 1),
221                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
222        ix += 1
223        tab_used = wx.StaticText(self, wx.ID_ANY, '  FitPage ')
224        tab_used.SetBackgroundColour('grey')
225        tab_used.SetForegroundColour(wx.WHITE)
226        sizer.Add(tab_used, (iy, ix), (1, 1),
227                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
228        for id, value in self.page_finder.iteritems():
229            if id not in self.parent.opened_pages:
230                continue
231
232            if self.batch_on != self.parent.get_page_by_id(id).batch_on:
233                continue
234
235            data_list = []
236            model_list = []
237            # get data name and model objetta
238            for fitproblem in value.get_fit_problem():
239
240                data = fitproblem.get_fit_data()
241                if not data.is_data:
242                    continue
243                name = '-'
244                if data is not None and data.is_data:
245                    name = str(data.name)
246                data_list.append(name)
247
248                model = fitproblem.get_model()
249                if model is None:
250                    continue
251                model_list.append(model)
252
253            if len(model_list) == 0:
254                continue
255            # Draw sizer
256            ix = 0
257            iy += 1
258            model = model_list[0]
259            name = '_'
260            if model is not None:
261                name = str(model.name)
262            cb = wx.CheckBox(self, wx.ID_ANY, name)
263            cb.SetValue(False)
264            cb.Enable(model is not None and data.is_data)
265            sizer.Add(cb, (iy, ix), (1, 1),
266                      wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
267            wx.EVT_CHECKBOX(self, cb.GetId(), self.check_model_name)
268            ix += 2
269            model_type = wx.StaticText(self, wx.ID_ANY,
270                                       model.__class__.__name__)
271            sizer.Add(model_type, (iy, ix), (1, 1),
272                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
273            if self.batch_on:
274                data_used = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
275                data_used.AppendItems(data_list)
276                data_used.SetSelection(0)
277            else:
278                data_used = wx.StaticText(self, wx.ID_ANY, data_list[0])
279
280            ix += 1
281            sizer.Add(data_used, (iy, ix), (1, 1),
282                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
283            ix += 1
284            caption = value.get_fit_tab_caption()
285            tab_caption_used = wx.StaticText(self, wx.ID_ANY, str(caption))
286            sizer.Add(tab_caption_used, (iy, ix), (1, 1),
287                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
288
289            self.model_list.append([cb, value, id, model])
290
291        iy += 1
292        sizer.Add((20, 20), (iy, ix), (1, 1),
293                  wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
294
295    def _fill_sizer_constraint(self):
296        """
297        Fill sizer containing constraint info
298        """
299        msg = "Select at least 1 model to add constraint "
300        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
301
302        self.sizer2.Clear(True)
303        if self.batch_on:
304            if self.sizer2.IsShown():
305                self.sizer2.Show(False)
306            return
307        box_description = wx.StaticBox(self, wx.ID_ANY, "Fit Constraints")
308        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
309        sizer_title = wx.BoxSizer(wx.HORIZONTAL)
310        self.sizer_all_constraints = wx.BoxSizer(wx.HORIZONTAL)
311        self.sizer_constraints = wx.BoxSizer(wx.VERTICAL)
312        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
313
314        self.hide_constraint = wx.RadioButton(self, wx.ID_ANY, 'No', (10, 10),
315                                              style=wx.RB_GROUP)
316        self.show_constraint = wx.RadioButton(self, wx.ID_ANY, 'Yes', (10, 30))
317        self.Bind(wx.EVT_RADIOBUTTON, self._display_constraint,
318                  id=self.hide_constraint.GetId())
319        self.Bind(wx.EVT_RADIOBUTTON, self._display_constraint,
320                  id=self.show_constraint.GetId())
321        if self.batch_on:
322            self.hide_constraint.Enable(False)
323            self.show_constraint.Enable(False)
324        self.hide_constraint.SetValue(True)
325        self.show_constraint.SetValue(False)
326
327        sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Model"))
328        sizer_title.Add((10, 10))
329        sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Parameter"))
330        sizer_title.Add((10, 10))
331        sizer_title.Add(wx.StaticText(self, wx.ID_ANY, " Add Constraint?"))
332        sizer_title.Add((10, 10))
333        sizer_title.Add(self.show_constraint)
334        sizer_title.Add(self.hide_constraint)
335        sizer_title.Add((10, 10))
336
337        self.btAdd = wx.Button(self, self.ID_ADD, 'Add')
338        self.btAdd.Bind(wx.EVT_BUTTON, self._onAdd_constraint,
339                        id=self.btAdd.GetId())
340        self.btAdd.SetToolTipString("Add another constraint?")
341        self.btAdd.Hide()
342
343        text_hint = wx.StaticText(self, wx.ID_ANY,
344                                  "Example: [M0][paramter] = M1.parameter")
345        sizer_button.Add(text_hint, 0,
346                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
347        sizer_button.Add(self.btAdd, 0,
348                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
349
350        boxsizer1.Add(sizer_title, flag=wx.TOP | wx.BOTTOM, border=10)
351        boxsizer1.Add(self.sizer_all_constraints, flag=wx.TOP | wx.BOTTOM,
352                      border=10)
353        boxsizer1.Add(self.sizer_constraints, flag=wx.TOP | wx.BOTTOM,
354                      border=10)
355        boxsizer1.Add(sizer_button, flag=wx.TOP | wx.BOTTOM, border=10)
356
357        self.sizer2.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
358
359
360    def _fill_sizer_fit(self):
361        """
362        Draw fit button
363        """
364        self.sizer3.Clear(True)
365        box_description = wx.StaticBox(self, wx.ID_ANY, "Fit ")
366        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
367        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
368
369        #Fit button
370        self.btFit = wx.Button(self, self.ID_FIT, 'Fit', size=wx.DefaultSize)
371        self.btFit.Bind(wx.EVT_BUTTON, self.onFit, id=self.btFit.GetId())
372        self.btFit.SetToolTipString("Perform fit.")
373
374        #General Help button
375        self.btHelp = wx.Button(self, wx.ID_HELP, 'HELP')
376        self.btHelp.SetToolTipString("Simultaneous/Constrained Fitting help.")
377        self.btHelp.Bind(wx.EVT_BUTTON, self._onHelp)
378
379        #hint text on button line
380        if self.batch_on:
381            text = " Fit in Parallel all Data sets\n"
382            text += "and model selected."
383        else:
384            text = " At least one set of model and data\n"
385            text += " must be selected for fitting."
386        text_hint = wx.StaticText(self, wx.ID_ANY, text)
387
388        sizer_button.Add(text_hint)
389        sizer_button.Add(self.btFit, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
390        sizer_button.Add(self.btHelp, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
391
392        boxsizer1.Add(sizer_button, flag=wx.TOP | wx.BOTTOM, border=10)
393        self.sizer3.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
394
395    def onRemove(self, event):
396        """
397        Remove constraint fields
398        """
399        if len(self.constraints_list) == 1:
400            self.hide_constraint.SetValue(True)
401            self._hide_constraint()
402            return
403        if len(self.constraints_list) == 0:
404            return
405        wx.CallAfter(self._remove_after, event.GetId())
406        #self._onAdd_constraint(None)
407
408    def _remove_after(self, id):
409        for item in self.constraints_list:
410            if id == item.btRemove.GetId():
411                self.sizer_constraints.Hide(item.sizer)
412                item.sizer.Clear(True)
413                self.sizer_constraints.Remove(item.sizer)
414                self.constraints_list.remove(item)
415                self.nb_constraint -= 1
416                self.sizer2.Layout()
417                self.FitInside()
418                break
419
420    def onFit(self, event):
421        """
422        signal for fitting
423
424        """
425        flag = False
426        # check if the current page a simultaneous fit page or a batch page
427        if self == self._manager.sim_page:
428            flag = (self._manager.sim_page.uid == self.uid)
429
430        ## making sure all parameters content a constraint
431        if not self.batch_on and self.show_constraint.GetValue():
432            if not self._set_constraint():
433                return
434        ## model was actually selected from this page to be fit
435        if len(self.model_toFit) >= 1:
436            self.manager._reset_schedule_problem(value=0)
437            for item in self.model_list:
438                if item[0].GetValue():
439                    self.manager.schedule_for_fit(value=1, uid=item[2])
440            try:
441                if not self.manager.onFit(uid=self.uid):
442                    return
443            except:
444                msg = "Select at least one parameter to fit in the FitPages."
445                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
446        else:
447            msg = "Select at least one model check box to fit "
448            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
449
450    def _onHelp(self, event):
451        """
452        Bring up the simultaneous Fitting Documentation whenever the HELP
453        button is clicked.
454
455        Calls DocumentationWindow with the path of the location within the
456        documentation tree (after /doc/ ....".  Note that when using old
457        versions of Wx (before 2.9) and thus not the release version of
458        installers, the help comes up at the top level of the file as
459        webbrowser does not pass anything past the # to the browser when it is
460        running "file:///...."
461
462    :param evt: Triggers on clicking the help button
463    """
464        _TreeLocation = "user/perspectives/fitting/fitting_help.html"
465        _PageAnchor = "#simultaneous-fit-mode"
466        _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation,
467                                          _PageAnchor,
468                                          "Simultaneous/Constrained Fitting Help")
469
470    def set_manager(self, manager):
471        """
472        set panel manager
473
474        :param manager: instance of plugin fitting
475
476        """
477        self.manager = manager
478
479    def check_all_model_name(self, event=None):
480        """
481        check all models names
482        """
483        self.model_toFit = []
484        if self.cb1.GetValue() == True:
485            for item in self.model_list:
486                if item[0].IsEnabled():
487                    item[0].SetValue(True)
488                    self.model_toFit.append(item)
489
490            ## constraint info
491            self._store_model()
492            if not self.batch_on:
493                ## display constraint fields
494                if (self.show_constraint.GetValue() and
495                                 len(self.constraints_list) == 0):
496                    self._show_all_constraint()
497                    self._show_constraint()
498        else:
499            for item in self.model_list:
500                item[0].SetValue(False)
501
502            if not self.batch_on:
503                ##constraint info
504                self._hide_constraint()
505
506        self._update_easy_setup_cb()
507        self.FitInside()
508
509
510    def check_model_name(self, event):
511        """
512        Save information related to checkbox and their states
513        """
514        self.model_toFit = []
515        cbox = event.GetEventObject()
516        for item in self.model_list:
517            if item[0].GetValue() == True:
518                self.model_toFit.append(item)
519            else:
520                if item in self.model_toFit:
521                    self.model_toFit.remove(item)
522                    self.cb1.SetValue(False)
523
524        ## display constraint fields
525        if len(self.model_toFit) >= 1:
526            self._store_model()
527            if not self.batch_on and self.show_constraint.GetValue() and\
528                             len(self.constraints_list) == 0:
529                self._show_all_constraint()
530                self._show_constraint()
531
532        elif len(self.model_toFit) < 1:
533            ##constraint info
534            self._hide_constraint()
535
536        self._update_easy_setup_cb()
537        ## set the value of the main check button
538        if len(self.model_list) == len(self.model_toFit):
539            self.cb1.SetValue(True)
540            self.FitInside()
541            return
542        else:
543            self.cb1.SetValue(False)
544            self.FitInside()
545
546    def _update_easy_setup_cb(self):
547        """
548        Update easy setup combobox on selecting a model
549        """
550        if self.model_cbox_left == None or self.model_cbox_right == None:
551            return
552
553        models = [(item[3].name, item[3]) for item in self.model_toFit]
554        setComboBoxItems(self.model_cbox_left, models)
555        setComboBoxItems(self.model_cbox_right, models)
556        for item in self.constraints_list:
557            setComboBoxItems(item[0], models)
558        if self.model_cbox_left.GetSelection() == wx.NOT_FOUND:
559            self.model_cbox_left.SetSelection(0)
560        self.sizer2.Layout()
561
562    def _store_model(self):
563        """
564         Store selected model
565        """
566        if len(self.model_toFit) < 1:
567            return
568        for item in self.model_toFit:
569            model = item[3]
570            page_id = item[2]
571            self.constraint_dict[page_id] = model
572
573    def _display_constraint(self, event):
574        """
575        Show fields to add constraint
576        """
577        if len(self.model_toFit) < 1:
578            msg = "Select at least 1 model to add constraint "
579            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
580            ## hide button
581            self._hide_constraint()
582            return
583        if self.show_constraint.GetValue():
584            self._show_all_constraint()
585            self._show_constraint()
586            self.FitInside()
587            return
588        else:
589            self._hide_constraint()
590            return
591
592    def _show_all_constraint(self):
593        """
594        Show constraint fields
595        """
596        box_description = wx.StaticBox(self, wx.ID_ANY, "Easy Setup ")
597        boxsizer = wx.StaticBoxSizer(box_description, wx.HORIZONTAL)
598        sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
599        self.model_cbox_left = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
600        self.model_cbox_left.Clear()
601        self.model_cbox_right = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
602        self.model_cbox_right.Clear()
603        wx.EVT_COMBOBOX(self.model_cbox_left, wx.ID_ANY, self._on_select_modelcb)
604        wx.EVT_COMBOBOX(self.model_cbox_right, wx.ID_ANY, self._on_select_modelcb)
605        egal_txt = wx.StaticText(self, wx.ID_ANY, " = ")
606        self.set_button = wx.Button(self, self.ID_SET_ALL, 'Set All')
607        self.set_button.Bind(wx.EVT_BUTTON, self._on_set_all_equal,
608                             id=self.set_button.GetId())
609        set_tip = "Add constraints for all the adjustable parameters "
610        set_tip += "(checked in FitPages) if exist."
611        self.set_button.SetToolTipString(set_tip)
612        self.set_button.Disable()
613
614        for id, model in self.constraint_dict.iteritems():
615            ## check if all parameters have been selected for constraint
616            ## then do not allow add constraint on parameters
617            self.model_cbox_left.Append(str(model.name), model)
618        self.model_cbox_left.Select(0)
619        for id, model in self.constraint_dict.iteritems():
620            ## check if all parameters have been selected for constraint
621            ## then do not allow add constraint on parameters
622            self.model_cbox_right.Append(str(model.name), model)
623        boxsizer.Add(self.model_cbox_left,
624                             flag=wx.RIGHT | wx.EXPAND, border=10)
625        #boxsizer.Add(wx.StaticText(self, wx.ID_ANY, ".parameters"),
626        #                     flag=wx.RIGHT | wx.EXPAND, border=5)
627        boxsizer.Add(egal_txt, flag=wx.RIGHT | wx.EXPAND, border=5)
628        boxsizer.Add(self.model_cbox_right,
629                             flag=wx.RIGHT | wx.EXPAND, border=10)
630        #boxsizer.Add(wx.StaticText(self, wx.ID_ANY, ".parameters"),
631        #                     flag=wx.RIGHT | wx.EXPAND, border=5)
632        boxsizer.Add((20, -1))
633        boxsizer.Add(self.set_button, flag=wx.RIGHT | wx.EXPAND, border=5)
634        sizer_constraint.Add(boxsizer, flag=wx.RIGHT | wx.EXPAND, border=5)
635        self.sizer_all_constraints.Insert(before=0,
636                             item=sizer_constraint,
637                             flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=5)
638        self.FitInside()
639
640    def _on_select_modelcb(self, event):
641        """
642        On select model left or right combobox
643        """
644        event.Skip()
645        flag = True
646        if self.model_cbox_left.GetValue().strip() == '':
647            flag = False
648        if self.model_cbox_right.GetValue().strip() == '':
649            flag = False
650        if (self.model_cbox_left.GetValue() ==
651                self.model_cbox_right.GetValue()):
652            flag = False
653        self.set_button.Enable(flag)
654
655    def _on_set_all_equal(self, event):
656        """
657        On set button
658        """
659        event.Skip()
660        length = len(self.constraints_list)
661        if length < 1:
662            return
663        param_list = []
664        param_listB = []
665        selection = self.model_cbox_left.GetCurrentSelection()
666        model_left = self.model_cbox_left.GetValue()
667        model = self.model_cbox_left.GetClientData(selection)
668        selectionB = self.model_cbox_right.GetCurrentSelection()
669        model_right = self.model_cbox_right.GetValue()
670        modelB = self.model_cbox_right.GetClientData(selectionB)
671        for id, dic_model in self.constraint_dict.iteritems():
672            if model == dic_model:
673                param_list = self.page_finder[id].get_param2fit()
674            if modelB == dic_model:
675                param_listB = self.page_finder[id].get_param2fit()
676            if len(param_list) > 0 and len(param_listB) > 0:
677                break
678        num_cbox = 0
679        has_param = False
680        for param in param_list:
681            num_cbox += 1
682            if param in param_listB:
683                item = self.constraints_list[-1]
684                item.model_cbox.SetStringSelection(model_left)
685                self._on_select_model(None)
686                item.param_cbox.Clear()
687                item.param_cbox.Append(str(param), model)
688                item.param_cbox.SetStringSelection(str(param))
689                item.constraint.SetValue(str(model_right + "." + str(param)))
690                has_param = True
691                if num_cbox == (len(param_list) + 1):
692                    break
693                self._show_constraint()
694
695        self.FitInside()
696        if not has_param:
697            msg = " There is no adjustable parameter (checked to fit)"
698            msg += " either one of the models."
699            wx.PostEvent(self.parent.parent, StatusEvent(info="warning",
700                                                         status=msg))
701        else:
702            msg = " The constraints are added."
703            wx.PostEvent(self.parent.parent, StatusEvent(info="info",
704                                                         status=msg))
705
706    def _show_constraint(self):
707        """
708        Show constraint fields
709        """
710        self.btAdd.Show(True)
711        if len(self.constraints_list) != 0:
712            nb_fit_param = 0
713            for id, model in self.constraint_dict.iteritems():
714                nb_fit_param += len(self.page_finder[id].get_param2fit())
715            ##Don't add anymore
716            if len(self.constraints_list) == nb_fit_param:
717                msg = "Cannot add another constraint. Maximum of number "
718                msg += "Parameters name reached %s" % str(nb_fit_param)
719                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
720                self.sizer_constraints.Layout()
721                self.sizer2.Layout()
722                return
723        if len(self.model_toFit) < 1:
724            msg = "Select at least 1 model to add constraint "
725            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
726            self.sizer_constraints.Layout()
727            self.sizer2.Layout()
728            return
729
730        sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
731
732        # Model list
733        model_cbox = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
734        model_cbox.Clear()
735        for id, model in self.constraint_dict.iteritems():
736            ## check if all parameters have been selected for constraint
737            ## then do not allow add constraint on parameters
738            model_cbox.Append(str(model.name), model)
739        wx.EVT_COMBOBOX(model_cbox, wx.ID_ANY, self._on_select_model)
740
741        # Parameters in model
742        param_cbox = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY,
743                                 size=(100, -1))
744        param_cbox.Hide()
745        wx.EVT_COMBOBOX(param_cbox, wx.ID_ANY, self._on_select_param)
746
747        egal_txt = wx.StaticText(self, wx.ID_ANY, " = ")
748
749        # Parameter constraint
750        constraint = wx.TextCtrl(self, wx.ID_ANY)
751
752        # Remove button
753        #btRemove = wx.Button(self, self.ID_REMOVE, 'Remove')
754        btRemove = wx.Button(self, self._ids.next(), 'Remove')
755        btRemove.Bind(wx.EVT_BUTTON, self.onRemove,
756                      id=btRemove.GetId())
757        btRemove.SetToolTipString("Remove constraint.")
758        btRemove.Hide()
759
760        # Hid the add button, if it exists
761        if hasattr(self, "btAdd"):
762            self.btAdd.Hide()
763
764        sizer_constraint.Add((5, -1))
765        sizer_constraint.Add(model_cbox, flag=wx.RIGHT | wx.EXPAND, border=10)
766        sizer_constraint.Add(param_cbox, flag=wx.RIGHT | wx.EXPAND, border=5)
767        sizer_constraint.Add(egal_txt, flag=wx.RIGHT | wx.EXPAND, border=5)
768        sizer_constraint.Add(constraint, flag=wx.RIGHT | wx.EXPAND, border=10)
769        sizer_constraint.Add(btRemove, flag=wx.RIGHT | wx.EXPAND, border=10)
770
771        self.sizer_constraints.Insert(before=self.nb_constraint,
772                item=sizer_constraint, flag=wx.TOP | wx.BOTTOM | wx.EXPAND,
773                border=5)
774        c = ConstraintLine(model_cbox, param_cbox, egal_txt,
775                           constraint, btRemove, sizer_constraint)
776        self.constraints_list.append(c)
777
778        self.nb_constraint += 1
779        self.sizer_constraints.Layout()
780        self.sizer2.Layout()
781        self.Layout
782
783    def _hide_constraint(self):
784        """
785        hide buttons related constraint
786        """
787        for id in self.page_finder.iterkeys():
788            self.page_finder[id].clear_model_param()
789
790        self.nb_constraint = 0
791        self.constraint_dict = {}
792        if hasattr(self, "btAdd"):
793            self.btAdd.Hide()
794        self._store_model()
795        if self.model_cbox_left is not None:
796            self.model_cbox_left.Clear()
797            self.model_cbox_left = None
798        if self.model_cbox_right is not None:
799            self.model_cbox_right.Clear()
800            self.model_cbox_right = None
801        self.constraints_list = []
802        self.sizer_all_constraints.Clear(True)
803        self.sizer_all_constraints.Layout()
804        self.sizer_constraints.Clear(True)
805        self.sizer_constraints.Layout()
806        self.sizer2.Layout()
807        self.Layout
808        self.FitInside()
809
810    def _on_select_model(self, event):
811        """
812        fill combox box with list of parameters
813        """
814        if not self.constraints_list:
815            return
816
817        ##This way PC/MAC both work, instead of using event.GetClientData().
818        model_cbox = self.constraints_list[-1].model_cbox
819        n = model_cbox.GetCurrentSelection()
820        if n == wx.NOT_FOUND:
821            return
822
823        model = model_cbox.GetClientData(n)
824        param_list = []
825        for id, dic_model in self.constraint_dict.iteritems():
826            if model == dic_model:
827                param_list = self.page_finder[id].get_param2fit()
828                break
829
830        param_cbox = self.constraints_list[-1].param_cbox
831        param_cbox.Clear()
832        ## insert only fittable paramaters
833        for param in param_list:
834            param_cbox.Append(str(param), model)
835        param_cbox.Show(True)
836
837        btRemove = self.constraints_list[-1].btRemove
838        btRemove.Show(True)
839        self.btAdd.Show(True)
840#        self.Layout()
841        self.FitInside()
842
843    def _on_select_param(self, event):
844        """
845        Store the appropriate constraint in the page_finder
846        """
847        ##This way PC/MAC both work, instead of using event.GetClientData().
848        #n = self.param_cbox.GetCurrentSelection()
849        #model = self.param_cbox.GetClientData(n)
850        #param = event.GetString()
851
852        if self.constraints_list:
853            self.constraints_list[-1].egal_txt.Show(True)
854            self.constraints_list[-1].constraint.Show(True)
855
856    def _onAdd_constraint(self, event):
857        """
858        Add another line for constraint
859        """
860        if not self.show_constraint.GetValue():
861            msg = " Select Yes to add Constraint "
862            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
863            return
864        ## check that a constraint is added
865        # before allow to add another constraint
866        for item in self.constraints_list:
867            if item.model_cbox.GetString(0) == "":
868                msg = " Select a model Name! "
869                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
870                return
871            if item.param_cbox.GetString(0) == "":
872                msg = " Select a parameter Name! "
873                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
874                return
875            if item.constraint.GetValue().lstrip().rstrip() == "":
876                model = item.param_cbox.GetClientData(
877                                        item.param_cbox.GetCurrentSelection())
878                if model != None:
879                    msg = " Enter a constraint for %s.%s! " % (model.name,
880                                        item.param_cbox.GetString(0))
881                else:
882                    msg = " Enter a constraint"
883                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
884                return
885        ## some model or parameters can be constrained
886        self._show_constraint()
887        self.FitInside()
888
889    def _set_constraint(self):
890        """
891        get values from the constraint textcrtl ,parses them into model name
892        parameter name and parameters values.
893        store them in a list self.params .when when params is not empty
894        set_model uses it to reset the appropriate model
895        and its appropriates parameters
896        """
897        for item in self.constraints_list:
898            select0 = item.model_cbox.GetSelection()
899            if select0 == wx.NOT_FOUND:
900                continue
901            model = item.model_cbox.GetClientData(select0)
902            select1 = item.param_cbox.GetSelection()
903            if select1 == wx.NOT_FOUND:
904                continue
905            param = item.param_cbox.GetString(select1)
906            constraint = item.constraint.GetValue().lstrip().rstrip()
907            if param.lstrip().rstrip() == "":
908                param = None
909                msg = " Constraint will be ignored!. missing parameters"
910                msg += " in combobox to set constraint! "
911                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
912            for id, value in self.constraint_dict.iteritems():
913                if model == value:
914                    if constraint == "":
915                        msg = " Constraint will be ignored!. missing value"
916                        msg += " in textcrtl to set constraint! "
917                        wx.PostEvent(self.parent.parent,
918                                     StatusEvent(status=msg))
919                        constraint = None
920                    if str(param) in self.page_finder[id].get_param2fit():
921                        msg = " Checking constraint for parameter: %s ", param
922                        wx.PostEvent(self.parent.parent,
923                                     StatusEvent(info="info", status=msg))
924                    else:
925                        model_name = item[0].GetLabel()
926                        fitpage = self.page_finder[id].get_fit_tab_caption()
927                        msg = "All constrainted parameters must be set "
928                        msg += " adjustable: '%s.%s' " % (model_name, param)
929                        msg += "is NOT checked in '%s'. " % fitpage
930                        msg += " Please check it to fit or"
931                        msg += " remove the line of the constraint."
932                        wx.PostEvent(self.parent.parent,
933                                StatusEvent(info="error", status=msg))
934                        return False
935
936                    for fid in self.page_finder[id].iterkeys():
937                        # wrap in param/constraint in str() to remove unicode
938                        self.page_finder[id].set_model_param(str(param),
939                                str(constraint), fid=fid)
940                    break
941        return True
942
943    def on_set_focus(self, event=None):
944        """
945        The  derivative class is on focus if implemented
946        """
947        if self.parent is not None:
948            if self.parent.parent is not None:
949                wx.PostEvent(self.parent.parent, PanelOnFocusEvent(panel=self))
950            self.page_finder = self.parent._manager.get_page_finder()
951
952
953def setComboBoxItems(cbox, items):
954    assert isinstance(cbox, wx.ComboBox)
955    selected = cbox.GetStringSelection()
956    cbox.Clear()
957    for k, (name, value) in enumerate(items):
958        cbox.Append(name, value)
959    cbox.SetStringSelection(selected)
Note: See TracBrowser for help on using the repository browser.