source: sasview/fittingview/src/sans/perspectives/fitting/fitpanel.py @ 71fa9028

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 71fa9028 was 05efe88, checked in by Gervaise Alina <gervyh@…>, 13 years ago

make sure empty page get the batch flag when adding data to them

  • Property mode set to 100644
File size: 20.9 KB
Line 
1
2import numpy
3import string 
4import wx
5import sys
6#from wx.lib.flatnotebook import FlatNotebook as nb
7from wx.aui import AuiNotebook as nb
8
9from sans.guiframe.panel_base import PanelBase
10from sans.guiframe.events import PanelOnFocusEvent
11from sans.guiframe.events import StatusEvent
12from sans.guiframe.dataFitting import check_data_validity
13
14import basepage
15import models
16_BOX_WIDTH = 80
17
18
19class FitPanel(nb, PanelBase):   
20
21    """
22    FitPanel class contains fields allowing to fit  models and  data
23   
24    :note: For Fit to be performed the user should check at least one parameter
25        on fit Panel window.
26       
27    """
28    ## Internal name for the AUI manager
29    window_name = "Fit panel"
30    ## Title to appear on top of the window
31    window_caption = "Fit Panel "
32    CENTER_PANE = True
33   
34    def __init__(self, parent, manager=None, *args, **kwargs):
35        """
36        """
37        nb.__init__(self, parent, -1,
38                    style= wx.aui.AUI_NB_WINDOWLIST_BUTTON|
39                    wx.aui.AUI_NB_DEFAULT_STYLE|
40                    wx.CLIP_CHILDREN)
41        PanelBase.__init__(self, parent)
42        #self.SetWindowStyleFlag(style=nb.FNB_FANCY_TABS)
43        self._manager = manager
44        self.parent = parent
45        self.event_owner = None
46        #dictionary of miodel {model class name, model class}
47        self.menu_mng = models.ModelManager()
48        self.model_list_box = self.menu_mng.get_model_list()
49        #pageClosedEvent = nb.EVT_FLATNOTEBOOK_PAGE_CLOSING
50        self.pageClosedEvent = wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE
51       
52        self.Bind(self.pageClosedEvent, self.on_close_page)
53         ## save the title of the last page tab added
54        self.fit_page_name = {}
55        ## list of existing fit page
56        self.opened_pages = {}
57        #index of fit page
58        self.fit_page_index = 0
59        #index of batch page
60        self.batch_page_index = 0
61        #page of simultaneous fit
62        self.sim_page = None
63        self.fit_engine_type = "scipy"
64        ## get the state of a page
65        self.Bind(basepage.EVT_PAGE_INFO, self._onGetstate)
66        self.Bind(basepage.EVT_PREVIOUS_STATE, self._onUndo)
67        self.Bind(basepage.EVT_NEXT_STATE, self._onRedo)
68        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.on_page_changing)
69        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSED, self.on_closed)
70
71    def on_closed(self, event):
72        """
73        """
74        if self.GetPageCount() == 0:
75            self.add_empty_page()
76            self.enable_close_button()
77       
78    def save_project(self, doc=None):
79        """
80        return an xml node containing state of the panel
81         that guiframe can write to file
82        """
83        for uid, page in self.opened_pages.iteritems():
84            data = page.get_data()
85            # state must be cloned
86            state = page.get_state().clone()
87            if data is not None:
88                new_doc = self._manager.state_reader.write_toXML(data, state)
89                if doc != None and hasattr(doc, "firstChild"):
90                    child = new_doc.firstChild.firstChild
91                    doc.firstChild.appendChild(child) 
92                else:
93                    doc = new_doc
94        return doc   
95   
96    def _on_engine_change(self, name='scipy'):
97        """
98        """
99        for panel in self.opened_pages.values():
100            self.set_engine_helper(panel=panel, name=name)
101           
102    def set_engine_helper(self, panel, name='scipy'):
103        """
104        """
105        self.fit_engine_type = name
106        if panel != self.sim_page:
107            panel._on_engine_change(name=self.fit_engine_type)
108               
109    def update_model_list(self):
110        """
111        """
112        temp = self.menu_mng.update()
113        if len(temp):
114            self.model_list_box = temp
115        return temp
116
117    def get_page_by_id(self, uid): 
118        """
119        """
120        if uid not in self.opened_pages:
121            msg = "Fitpanel cannot find ID: %s in self.opened_pages" % str(uid)
122            raise ValueError, msg
123        else:
124            return self.opened_pages[uid]
125       
126    def on_page_changing(self, event):
127        """
128        calls the function when the current event handler has exited. avoiding
129        to call panel on focus on a panel that is currently deleted
130        """
131        wx.CallAfter(self.helper_on_page_change)
132       
133       
134    def helper_on_page_change(self):
135        """
136        """
137        pos = self.GetSelection()
138        if pos != -1:
139            selected_page = self.GetPage(pos)
140            wx.PostEvent(self.parent, PanelOnFocusEvent(panel=selected_page))
141        self.enable_close_button()
142       
143    def on_set_focus(self, event):
144        """
145        """
146        pos = self.GetSelection()
147        if pos != -1:
148            selected_page = self.GetPage(pos)
149            wx.PostEvent(self.parent, PanelOnFocusEvent(panel=selected_page))
150       
151    def get_data(self):
152        """
153        get the data in the current page
154        """
155        pos = self.GetSelection()
156        if pos != -1:
157            selected_page = self.GetPage(pos)
158            return selected_page.get_data()
159   
160    def set_model_state(state):
161        """
162        receive a state to reset the model in the current page
163        """
164        pos = self.GetSelection()
165        if pos != -1:
166            selected_page = self.GetPage(pos)
167            selected_page.set_model_state(state)
168           
169    def get_state(self):
170        """
171         return the state of the current selected page
172        """
173        pos = self.GetSelection()
174        if pos != -1:
175            selected_page = self.GetPage(pos)
176            return selected_page.get_state()
177   
178 
179 
180    def close_all(self):
181        """
182        remove all pages, used when a svs file is opened
183        """
184       
185        #get number of pages
186        nop = self.GetPageCount()
187        #use while-loop, for-loop will not do the job well.
188        while (nop>0):
189            #delete the first page until no page exists
190            page = self.GetPage(0)
191            if self._manager.parent.panel_on_focus == page:
192                self._manager.parent.panel_on_focus = None
193            self._close_helper(selected_page=page)
194            self.DeletePage(0)
195            nop = nop - 1
196           
197        ## save the title of the last page tab added
198        self.fit_page_name = {}
199        ## list of existing fit page
200        self.opened_pages = {} 
201         
202       
203    def set_state(self, state):
204        """
205        Restore state of the panel
206        """
207        page_is_opened = False
208        if state is not None:
209            for uid, panel in self.opened_pages.iteritems():
210                #Don't return any panel is the exact same page is created
211                if uid == panel.uid and panel.data == state.data:
212                    # the page is still opened
213                    panel.reset_page(state=state)
214                    panel.save_current_state() 
215                    page_is_opened = True
216            if not page_is_opened:
217                panel = self._manager.add_fit_page(data=state.data)
218                # add data associated to the page created
219                if panel is not None: 
220                    self._manager.store_data(uid=panel.uid, 
221                                             data=state.data,
222                                             caption=panel.window_caption)
223                    panel.reset_page(state=state)
224                    panel.save_current_state()
225                   
226    def clear_panel(self):
227        """
228        Clear and close all panels, used by guimanager
229        """
230       
231        #close all panels only when svs file opened
232        self.close_all()
233        self._manager.mypanels = []
234       
235                       
236    def on_close_page(self, event=None):
237        """
238        close page and remove all references to the closed page
239        """
240        nbr_page = self.GetPageCount()
241        selected_page = self.GetPage(self.GetSelection())
242        if nbr_page == 1:
243            if selected_page.get_data() == None:
244                if event is not None:
245                    event.Veto()
246                return 
247        self._close_helper(selected_page=selected_page)
248       
249    def close_page_with_data(self, deleted_data):
250        """
251        close a fit page when its data is completely remove from the graph
252        """
253        if deleted_data is None:
254            return
255        for index in range(self.GetPageCount()):
256            selected_page = self.GetPage(index) 
257            if hasattr(selected_page,"get_data"):
258                data = selected_page.get_data()
259               
260                if data is None:
261                    #the fitpanel exists and only the initial fit page is open
262                    #with no selected data
263                    return
264                if data.id == deleted_data.id:
265                    self._close_helper(selected_page)
266                    self.DeletePage(index)
267                    break
268       
269    def set_manager(self, manager):
270        """
271        set panel manager
272       
273        :param manager: instance of plugin fitting
274       
275        """
276        self._manager = manager
277        for pos in range(self.GetPageCount()):
278            page = self.GetPage(pos)
279            if page is not None:
280                page.set_manager(self._manager)
281
282    def set_model_list(self, dict):
283         """
284         copy a dictionary of model into its own dictionary
285         
286         :param dict: dictionnary made of model name as key and model class
287             as value
288         """
289         self.model_list_box = dict
290       
291    def get_current_page(self):
292        """
293        :return: the current page selected
294       
295        """
296        return self.GetPage(self.GetSelection())
297   
298    def add_sim_page(self):
299        """
300        Add the simultaneous fit page
301        """
302        from simfitpage import SimultaneousFitPage
303        page_finder= self._manager.get_page_finder()
304        self.sim_page = SimultaneousFitPage(self,page_finder=page_finder, id=-1)
305        self.sim_page.uid = wx.NewId()
306        self.AddPage(self.sim_page,"Simultaneous Fit", True)
307        self.sim_page.set_manager(self._manager)
308        self.enable_close_button()
309        return self.sim_page
310       
311 
312    def add_empty_page(self):
313        """
314        add an empty page
315        """
316        """
317        if self.batch_on:
318            from batchfitpage import BatchFitPage
319            panel = BatchFitPage(parent=self)
320            #Increment index of batch page
321            self.batch_page_index += 1
322            index = self.batch_page_index
323        else:
324        """
325        from fitpage import FitPage
326        panel = FitPage(parent=self)
327        if self.batch_on:
328            self.batch_page_index += 1
329            caption = "BatchPage" + str(self.batch_page_index)
330            panel.set_index_model(self.batch_page_index)
331        else:
332            #Increment index of fit page
333            self.fit_page_index += 1
334            caption = "FitPage" + str(self.fit_page_index)
335            panel.set_index_model(self.fit_page_index)
336        panel.batch_on = self.batch_on
337        panel.populate_box(dict=self.model_list_box)
338        panel.set_manager(self._manager)
339        panel.window_caption = caption
340        panel.window_name = caption
341        self.AddPage(panel, caption, select=True)
342        self.opened_pages[panel.uid] = panel
343        self.set_engine_helper(panel=panel)
344        self._manager.create_fit_problem(panel.uid)
345        self._manager.page_finder[panel.uid].add_data(panel.get_data())
346        self.enable_close_button()
347        return panel
348   
349    def enable_close_button(self):
350        """
351        display the close button on tab for more than 1 tabs else remove the
352        close button
353        """
354        if self.GetPageCount() <= 1:
355            style = self.GetWindowStyleFlag() 
356            flag = wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
357            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB == flag:
358                style = style & ~wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
359                self.SetWindowStyle(style)
360        else:
361            style = self.GetWindowStyleFlag()
362            flag = wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
363            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB != flag:
364                style |= wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
365                self.SetWindowStyle(style)
366           
367    def delete_data(self, data):
368        """
369        Delete the given data
370        """
371        if data.__class__.__name__ != "list":
372            raise ValueError, "Fitpanel delete_data expect list of id"
373        else:
374            n = self.GetPageCount()
375            for page in self.opened_pages.values():
376                pos = self.GetPageIndex(page)
377                temp_data = page.get_data()
378                #stop the fitting before deleting the page
379                page.is_fitting()
380                if temp_data is not None and temp_data.id in data:
381                    self.SetSelection(pos)
382                    self.on_close_page(event=None)
383                    temp = self.GetSelection()
384                    self.DeletePage(temp)
385            if self.GetPageCount()== 0:
386                self._manager.on_add_new_page(event=None)
387       
388    def set_data_on_batch_mode(self, data_list):
389        """
390        Add all data to a single tab when the application is on Batch mode.
391        However all data in the set of data must be either 1D or 2D type.
392        This method presents option to select the data type before creating a
393        tab.
394        """
395        data_1d_list = []
396        data_2d_list = []
397        group_id_1d = wx.NewId()
398        # separate data into data1d and data2d list
399        for data in data_list:
400            if data.__class__.__name__ == "Data1D":
401                data.group_id = group_id_1d
402                data_1d_list.append(data)
403            if data.__class__.__name__ == "Data2D":
404                data.group_id = wx.NewId()
405                data_2d_list.append(data)
406        page = None
407        for p in self.opened_pages.values():
408            #check if there is an empty page to fill up
409            if not check_data_validity(p.get_data()):
410                page = p
411                self.batch_page_index += 1
412                break
413        if data_1d_list and data_2d_list:
414            # need to warning the user that this batch is a special case
415            from .fitting_widgets import BatchDataDialog
416            dlg = BatchDataDialog(self)
417            if dlg.ShowModal() == wx.ID_OK:
418                data_type = dlg.get_data()
419                dlg.Destroy()
420                if page  is None:
421                    page = self.add_empty_page()
422                if data_type == 1:
423                    #user has selected only data1D
424                    page.fill_data_combobox(data_1d_list)
425                elif data_type == 2:
426                    page.fill_data_combobox(data_2d_list)
427            else:
428                #the batch analysis is canceled
429                 dlg.Destroy()
430                 return None
431        else:
432            if page is None:
433                page = self.add_empty_page()
434            if data_1d_list and not data_2d_list:
435                #only on type of data
436                page.fill_data_combobox(data_1d_list)
437            elif not data_1d_list and data_2d_list:
438                page.fill_data_combobox(data_2d_list)
439        pos = self.GetPageIndex(page)
440        caption = "BatchPage" + str(self.batch_page_index)
441        self.SetPageText(pos, caption)
442        page.batch_on = self.batch_on
443        page.window_caption = caption
444        page.window_name = caption
445        self.opened_pages[page.uid] = page
446        return page
447   
448    def set_data(self, data_list):
449        """
450        Add a fitting page on the notebook contained by fitpanel
451       
452        :param data: data to fit
453       
454        :return panel : page just added for further used.
455        is used by fitting module
456       
457        """
458        if not data_list:
459            return None
460        if self.batch_on:
461           return self.set_data_on_batch_mode(data_list)
462        else:
463            data = None
464            try:
465                data = data_list[0]
466            except:
467                # for 'fitv' files
468                data_list = [data]
469                data = data_list[0]
470               
471            if data is None:
472                return None
473        for page in self.opened_pages.values():
474            #check if the selected data existing in the fitpanel
475            pos = self.GetPageIndex(page)
476            if not check_data_validity(page.get_data()):
477                #make sure data get placed in 1D empty tab if data is 1D
478                #else data get place on 2D tab empty tab
479                enable2D = page.get_view_mode()
480                if (data.__class__.__name__ == "Data2D" and enable2D)\
481                or (data.__class__.__name__ == "Data1D" and not enable2D):
482                    page.batch_on = self.batch_on
483                    page.fill_data_combobox(data_list)
484                    caption = "FitPage" + str(self.fit_page_index)
485                    self.SetPageText(pos, caption)
486                    self.SetSelection(pos)
487                    return page
488        #create new page and add data
489        page = self.add_empty_page()
490        pos = self.GetPageIndex(page)
491        page.fill_data_combobox(data_list)
492        self.opened_pages[page.uid] = page
493        self.SetSelection(pos)
494        return page
495       
496    def _onGetstate(self, event):
497        """
498        copy the state of a page
499        """
500        page = event.page
501        if page.uid in self.fit_page_name:
502           self.fit_page_name[page.uid].appendItem(page.createMemento()) 
503           
504    def _onUndo(self, event):
505        """
506        return the previous state of a given page is available
507        """
508        page = event.page
509        if page.uid in self.fit_page_name:
510            if self.fit_page_name[page.uid].getCurrentPosition()==0:
511                state = None
512            else:
513                state = self.fit_page_name[page.uid].getPreviousItem()
514                page._redo.Enable(True)
515            page.reset_page(state)
516       
517    def _onRedo(self, event): 
518        """
519        return the next state available
520        """       
521        page = event.page
522        if page.uid in self.fit_page_name:
523            length= len(self.fit_page_name[page.uid])
524            if self.fit_page_name[page.uid].getCurrentPosition()== length -1:
525                state = None
526                page._redo.Enable(False)
527                page._redo.Enable(True)
528            else:
529                state =self.fit_page_name[page.uid].getNextItem()
530            page.reset_page(state) 
531                 
532    def _close_helper(self, selected_page):
533        """
534        Delete the given page from the notebook
535        """
536        #remove hint page
537        #if selected_page == self.hint_page:
538        #    return
539        ## removing sim_page
540        if selected_page == self.sim_page :
541            self._manager.sim_page=None 
542            return
543        """
544        # The below is not working when delete #5 and still have #6.
545        if selected_page.__class__.__name__ == "FitPage":
546            self.fit_page_index -= 1
547        else:
548            self.batch_page_index -= 1
549        """
550        ## closing other pages
551        state = selected_page.createMemento()
552        page_name = selected_page.window_name
553        page_finder = self._manager.get_page_finder() 
554        fitproblem = None
555        ## removing fit page
556        data = selected_page.get_data()
557        #Don' t remove plot for 2D
558        flag = True
559        if data.__class__.__name__ == 'Data2D':
560            flag = False
561        if selected_page in page_finder:
562            #Delete the name of the page into the list of open page
563            for uid, list in self.opened_pages.iteritems():
564                #Don't return any panel is the exact same page is created
565               
566                if flag and selected_page.uid == uid:
567                    self._manager.remove_plot(uid, theory=False)
568                    break 
569            del page_finder[selected_page]
570        ##remove the check box link to the model name of this page (selected_page)
571        try:
572            self.sim_page.draw_page()
573        except:
574            ## that page is already deleted no need to remove check box on
575            ##non existing page
576            pass
577               
578        #Delete the name of the page into the list of open page
579        for uid, list in self.opened_pages.iteritems():
580            #Don't return any panel is the exact same page is created
581            if selected_page.uid == uid:
582                del self.opened_pages[selected_page.uid]
583                break 
584     
Note: See TracBrowser for help on using the repository browser.