source: sasview/sansview/perspectives/fitting/fitpanel.py @ ddf6df3

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 ddf6df3 was 31b0c47, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on save fit page state

  • Property mode set to 100644
File size: 16.3 KB
RevLine 
[e2f1023]1
2import numpy
3import string 
[d89f09b]4import wx
[26bf293]5import wx.aui
[330573d]6
[cfc0913]7import basepage
[00c3aac]8
[330573d]9_BOX_WIDTH = 80
10
11
12class StateIterator(object):
[1b69256]13    """
14        Contains all saved state of a given page.
15        Provide position of the current state of a page, the first save state
16        and the last state for a given page.
[330573d]17        Allow easy undo or redo for a given page 
[1b69256]18    """
[330573d]19    def __init__(self):
20        self._current=0
21       
22   
23    def __iter__(self):
24        return self
25   
26   
27    def first(self):
28        self._current =0
29        return self._current
30   
31    def next(self, max ):
32        if self._current < max:
33            self._current += 1
34        return self._current
35   
36    def previous(self):
37        if self._current > 0:
38            self._current = self._current -1
39        return self._current
40   
41    def currentPosition(self):
42        return self._current
43   
44    def setPosition(self, value):
45        if value >=0:
46            self._current = int(value)
47       
48   
49class ListOfState(list):     
50    def __init__(self, *args, **kw):
51        list.__init__(self, *args, **kw)
52        self.iterator = StateIterator()
53       
54    def appendItem(self, x):
55        self.append(x)
56        self.iterator.setPosition(value= len(self)-1)
57       
58    def removeItem(self, x):
59        self.iterator.previous()
60        self.remove(x)
61       
62    def getPreviousItem(self):
63        position = self.iterator.previous()
64       
65        if position < 0:
66            return None
67        else:
68            return self[position]
69       
70    def getNextItem(self):
[fe496eeb]71        position = self.iterator.next(max= len(self)-1)
[330573d]72        if position >= len(self):
73            return None
74        else:
75            return self[position]
76       
77    def getCurrentItem(self):
78        postion = self.iterator.currentPosition()
79        if postion >= 0 and position < len(self):
80            return self[postion]
81        else:
82            return None
83       
84    def getCurrentPosition(self):
85        return self.iterator.currentPosition()
[2f189dc]86         
[330573d]87
[cfc0913]88class PageInfo(object):
89    """
90        this class contains the minimum numbers of data members
91        a fitpage or model page need to be initialized.
92    """
93    data = None
[ffa69b6]94    model =  None
95    manager = None
[cfc0913]96    event_owner= None
97    model_list_box = None
[ffa69b6]98    name = None
[330573d]99    ## Internal name for the AUI manager
[cfc0913]100    window_name = "Page"
101    ## Title to appear on top of the window
102    window_caption = "Page"
[2f189dc]103    #type of page can be real data , theory 1D or therory2D
104    type = "Data"
105    def __init__(self, model=None, data=None, manager=None,
106                  event_owner=None, model_list_box=None, name=None):
[cfc0913]107        """
108            Initialize data members
109        """
110        self.data = data
111        self.model= model
112        self.manager= manager
113        self.event_owner= event_owner
114        self.model_list_box = model_list_box
115        self.name=None
116        self.window_name = "Page"
117        self.window_caption = "Page"
[2f189dc]118        self.type = "Data"
119       
[90d04eb]120class FitPanel(wx.aui.AuiNotebook):   
[925a30e]121
[d89f09b]122    """
123        FitPanel class contains fields allowing to fit  models and  data
124        @note: For Fit to be performed the user should check at least one parameter
125        on fit Panel window.
126       
127    """
128    ## Internal name for the AUI manager
129    window_name = "Fit panel"
130    ## Title to appear on top of the window
131    window_caption = "Fit Panel "
[2139c3f]132    CENTER_PANE = True
[7437880]133   
[d89f09b]134    def __init__(self, parent, *args, **kwargs):
[90d04eb]135        wx.aui.AuiNotebook.__init__(self, parent, -1,
[3244cbe1]136                    style= wx.aui.AUI_NB_WINDOWLIST_BUTTON|
137                    wx.aui.AUI_NB_DEFAULT_STYLE|
138                    wx.CLIP_CHILDREN)
[848a2ef]139   
[d89f09b]140        self.manager=None
141        self.parent=parent
142        self.event_owner=None
[26bf293]143       
[3244cbe1]144        pageClosedEvent = wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE
[2f189dc]145        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_close_page)
[51d47b5]146       
[d89f09b]147        #dictionary of miodel {model class name, model class}
[2f189dc]148        self.model_list_box = {}
[cfc0913]149        ## save the title of the last page tab added
[2f189dc]150        self.fit_page_name = {}
[cfc0913]151        ## list of existing fit page
[2f189dc]152        self.opened_pages = {}
153        #page of simultaneous fit
[ffa69b6]154        self.sim_page = None
[cfc0913]155        ## get the state of a page
156        self.Bind(basepage.EVT_PAGE_INFO, self._onGetstate)
[330573d]157        self.Bind(basepage.EVT_PREVIOUS_STATE, self._onUndo)
[fe496eeb]158        self.Bind(basepage.EVT_NEXT_STATE, self._onRedo)
[9237df4]159       
160        #add default page
161        from hint_fitpage import HintFitPage
[2377cd4]162        self.hint_page = HintFitPage(self) 
163        self.AddPage(page=self.hint_page, caption="Hint")
[ffa69b6]164        #Add the first fit page
[2f189dc]165        self.add_empty_page()
[ffa69b6]166       
[6bcdad1]167        # increment number for model name
168        self.count=0
[f39511b]169        #updating the panel
[26bf293]170        self.Update()
[d89f09b]171        self.Center()
[31b0c47]172       
173    def set_state(self, state):
174        """
175            Restore state of the panel
176        """
177        page_is_opened = False
178        if state is not None:
179            page_info = self.get_page_info(data=state.data)
180            for name, panel in self.opened_pages.values():
181                #Don't return any panel is the exact same page is created
182                if name == page_info.window_name:
183                    # the page is still opened
184                    panel.reset_page(state=state)
185                    page_is_opened = True
186            if not page_is_opened:
187                panel = self.add_fit_page(data=state.data)
188                # add data associated to the page created
189                if panel is not None: 
190                    self.manager.store_page(page=panel, data=state.data)
191                    panel.reset_page(state=state)
192                   
[2f189dc]193    def on_close_page(self, event):
[51d47b5]194        """
[925a30e]195             close page and remove all references to the closed page
[51d47b5]196        """
[d361b462]197        nbr_page = self.GetPageCount()
198        if nbr_page == 1:
199            event.Veto()
200            return 
[51d47b5]201        selected_page = self.GetPage(self.GetSelection())
[2f189dc]202        self._close_helper(selected_page=selected_page)
[9853ad0]203       
[2f189dc]204    def close_page_with_data(self, deleted_data):
205        """
206            close a fit page when its data is completely remove from the graph
207        """
[784e2fa]208        if deleted_data is None:
209            return
[2f189dc]210        for index in range(self.GetPageCount()):
211            selected_page = self.GetPage(index) 
212            if hasattr(selected_page,"get_data"):
213                data = selected_page.get_data()
[784e2fa]214                if data is None:
215                    #the fitpanel exists and only the initial fit page is open
216                    #with no selected data
217                    return
[2f189dc]218                if data.name == deleted_data.name:
219                    self._close_helper(selected_page)
220                    self.DeletePage(index)
221                    break
[d89f09b]222       
223    def set_manager(self, manager):
224        """
225             set panel manager
226             @param manager: instance of plugin fitting
227        """
228        self.manager = manager
[925a30e]229
[d89f09b]230       
231    def set_owner(self,owner):
232        """
233            set and owner for fitpanel
234            @param owner: the class responsible of plotting
235        """
[c77d859]236        self.event_owner = owner
237   
[ffa69b6]238    def set_model_list(self, dict):
[c77d859]239         """
240             copy a dictionary of model into its own dictionary
241             @param dict: dictionnary made of model name as key and model class
242             as value
243         """
244         self.model_list_box = dict
[51d47b5]245       
[c77d859]246 
247    def get_current_page(self):
248        """
249            @return the current page selected
250        """
251        return self.GetPage(self.GetSelection() )
252   
[51d47b5]253    def add_sim_page(self):
[925a30e]254        """
255            Add the simultaneous fit page
256        """
[51d47b5]257        from simfitpage import SimultaneousFitPage
[b28717b]258        page_finder= self.manager.get_page_finder()
259        self.sim_page = SimultaneousFitPage(self,page_finder=page_finder, id=-1)
260       
[51d47b5]261        self.AddPage(self.sim_page,caption="Simultaneous Fit",select=True)
262        self.sim_page.set_manager(self.manager)
263        return self.sim_page
[d89f09b]264       
[2f189dc]265    def get_page_info(self, data=None):
266        """
267            fill information required to add a page in the fit panel
268        """
269        name = "Fit Page"
270        type = 'empty'
[ffa69b6]271        if data is not None:
272            if data.is_data:
273                name = data.name
[2f189dc]274                type = 'Data'
[882a912]275            else:
[2f189dc]276                if data.__class__.__name__ == "Data2D":
[ffa69b6]277                    name = 'Model 2D Fit'
[2f189dc]278                    type = 'Theory2D'
[ffa69b6]279                else:
280                    name = 'Model 1D Fit'
[2f189dc]281                    type = 'Theory1D'
282        page_info = PageInfo(data=data, name=name)
283        page_info.event_owner = self.event_owner
284        page_info.manager = self.manager
285        page_info.window_name = name
286        page_info.window_caption = name
287        page_info.type = type
288        return page_info
[9853ad0]289   
[2f189dc]290    def add_empty_page(self):
[9853ad0]291        """
[2f189dc]292            add an empty page
[9853ad0]293        """
[2f189dc]294        page_info = self.get_page_info()
295        from fitpage import FitPage
296        panel = FitPage(parent=self, page_info=page_info)
297        self.AddPage(page=panel, caption=page_info.window_name, select=True)
298        self.opened_pages[page_info.type] = [page_info.window_name, panel]
299        return panel
300   
301    def add_page(self, page_info):
[848a2ef]302        """
[2f189dc]303            add a new page
[848a2ef]304        """
[2f189dc]305        from fitpage import FitPage
306        panel = FitPage(parent=self, page_info=page_info)
307        self.AddPage(page=panel, caption=page_info.window_name, select=True)
308        index = self.GetPageIndex(panel)
309        self.change_page_content(data=page_info.data, index=index)
310        return panel
[848a2ef]311   
[2f189dc]312    def change_page_content(self, data, index):
313        """
314            replace the contains of an existing page
315        """
316        page_info = self.get_page_info(data=data)
317        self.SetPageText(index, page_info.window_name)
318        panel = self.GetPage(index)
319        panel.set_data(data)
320        if panel.model_list_box is None or len(panel.model_list_box) == 0: 
321            page_info.model_list_box = self.model_list_box.get_list()
322            panel.populate_box(dict=page_info.model_list_box)
323            panel.initialize_combox()
324        panel.set_page_info(page_info=page_info)
325        self.opened_pages[page_info.type] = [page_info.window_name, panel]
326        return panel
327   
328    def replace_page(self, index, page_info, type):
329        """
330            replace an existing page
331        """
332        self.DeletePage(index)
333        del self.opened_pages[type]
334        return self.add_page(page_info=page_info)
[848a2ef]335       
[2f189dc]336    def add_fit_page(self, data, reset=False):
337        """
338            Add a fitting page on the notebook contained by fitpanel
339            @param data: data to fit
340            @return panel : page just added for further used. is used by fitting module
341        """
342        if data is None:
343            return None
344        page_info = self.get_page_info(data=data)
345        type = page_info.type
346        npages = len(self.opened_pages.keys())
347        #check if only and empty page is opened
348        if len(self.opened_pages.keys()) > 0:
349            first_page_type = self.opened_pages.keys()[0]
350            if npages == 1 and first_page_type in ['empty']:
351                #replace the first empty page
352                name, panel = self.opened_pages[first_page_type]
353                index = self.GetPageIndex(panel)
354                panel = self.change_page_content(data=data, index=index)
355                del self.opened_pages[first_page_type]
356                return panel
357        if type in self.opened_pages.keys():
358            #this type of page is already created but it is a theory
359            # meaning the same page is just to fit different data
360            if not type.lower() in ['data']:
361                #delete the previous theory page and add a new one
362                name, panel = self.opened_pages[type]
[286bb6c]363                #self.manager.reset_plot_panel(panel.get_data())
[2f189dc]364                #delete the existing page and replace it
365                index = self.GetPageIndex(panel)
366                panel = self.replace_page(index=index, page_info=page_info, type=type)
367                return panel
368            else:
369                for name, panel in self.opened_pages.values():
370                    #Don't return any panel is the exact same page is created
371                    if name == page_info.window_name:
372                        return None
373                    else:
374                        panel = self.add_page(page_info=page_info)
375                        return panel       
376        else:
377            #a new type of page is created
378            panel = self.add_page(page_info=page_info)
379            return panel
380   
[cfc0913]381    def  _onGetstate(self, event):
382        """
383            copy the state of a page
384        """
385        page= event.page
[b787e68c]386        if page.window_name in self.fit_page_name:
[330573d]387            self.fit_page_name[page.window_name].appendItem(page.createMemento()) 
[cfc0913]388           
[330573d]389    def _onUndo(self, event ):
390        """
391            return the previous state of a given page is available
392        """
393        page = event.page
394        if page.window_name in self.fit_page_name:
395            if self.fit_page_name[page.window_name].getCurrentPosition()==0:
396                state = None
397            else:
398                state = self.fit_page_name[page.window_name].getPreviousItem()
[fe496eeb]399                page._redo.Enable(True)
[330573d]400            page.reset_page(state)
[fe496eeb]401       
[2f189dc]402    def _onRedo(self, event): 
[fe496eeb]403        """
404            return the next state available
405        """       
406        page = event.page
407        if page.window_name in self.fit_page_name:
408            length= len(self.fit_page_name[page.window_name])
409            if self.fit_page_name[page.window_name].getCurrentPosition()== length -1:
410                state = None
411                page._redo.Enable(False)
[3b9e023]412                page._redo.Enable(True)
[fe496eeb]413            else:
414                state = self.fit_page_name[page.window_name].getNextItem()
415            page.reset_page(state) 
[2f189dc]416                 
417    def _close_helper(self, selected_page):
[3f1af74]418        """
[2f189dc]419            Delete the given page from the notebook
[3f1af74]420        """
[2f189dc]421        #remove hint page
422        if selected_page == self.hint_page:
423            return
424        ## removing sim_page
425        if selected_page == self.sim_page :
426            self.manager.sim_page=None 
427            return
[b787e68c]428       
[2f189dc]429        ## closing other pages
430        state = selected_page.createMemento()
431        page_name = selected_page.window_name
432        page_finder = self.manager.get_page_finder() 
433        fitproblem = None
434        ## removing fit page
[c6036f5]435        data = selected_page.get_data()
436        #Don' t remove plot for 2D
437        flag = True
438        if data.__class__.__name__ == 'Data2D':
439            flag = False
[2f189dc]440        if selected_page in page_finder:
441            #Delete the name of the page into the list of open page
442            for type, list in self.opened_pages.iteritems():
443                #Don't return any panel is the exact same page is created
444                name = str(list[0])
[c6036f5]445                if flag and selected_page.window_name == name:
[2f189dc]446                    if type.lower() in ['theory1d', 'theory2d']:
447                        self.manager.remove_plot(selected_page, theory=True)
448                    else:
449                        self.manager.remove_plot(selected_page, theory=False)
450                    break 
451            del page_finder[selected_page]
452        ##remove the check box link to the model name of this page (selected_page)
453        try:
454            self.sim_page.draw_page()
455        except:
456            ## that page is already deleted no need to remove check box on
457            ##non existing page
458            pass
459               
460        #Delete the name of the page into the list of open page
461        for type, list in self.opened_pages.iteritems():
462            #Don't return any panel is the exact same page is created
463            name = str(list[0])
464            if selected_page.window_name == name:
465                del self.opened_pages[type]
466                break 
[0aeabc6]467     
[b787e68c]468 
Note: See TracBrowser for help on using the repository browser.