source: sasview/sansview/perspectives/fitting/fitpanel.py @ 11a7e11

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 11a7e11 was 784e2fa, checked in by Gervaise Alina <gervyh@…>, 14 years ago

make sur the fitpage is close when removing data1D from the graph

  • Property mode set to 100644
File size: 15.4 KB
Line 
1
2import numpy
3import string 
4import wx
5import wx.aui
6
7import basepage
8
9_BOX_WIDTH = 80
10
11
12class StateIterator(object):
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.
17        Allow easy undo or redo for a given page 
18    """
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):
71        position = self.iterator.next(max= len(self)-1)
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()
86         
87
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
94    model =  None
95    manager = None
96    event_owner= None
97    model_list_box = None
98    name = None
99    ## Internal name for the AUI manager
100    window_name = "Page"
101    ## Title to appear on top of the window
102    window_caption = "Page"
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):
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"
118        self.type = "Data"
119       
120class FitPanel(wx.aui.AuiNotebook):   
121
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 "
132    CENTER_PANE = True
133   
134    def __init__(self, parent, *args, **kwargs):
135        wx.aui.AuiNotebook.__init__(self, parent, -1,
136                    style= wx.aui.AUI_NB_WINDOWLIST_BUTTON|
137                    wx.aui.AUI_NB_DEFAULT_STYLE|
138                    wx.CLIP_CHILDREN)
139   
140        self.manager=None
141        self.parent=parent
142        self.event_owner=None
143       
144        pageClosedEvent = wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE
145        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_close_page)
146       
147        #dictionary of miodel {model class name, model class}
148        self.model_list_box = {}
149        ## save the title of the last page tab added
150        self.fit_page_name = {}
151        ## list of existing fit page
152        self.opened_pages = {}
153        #page of simultaneous fit
154        self.sim_page = None
155        ## get the state of a page
156        self.Bind(basepage.EVT_PAGE_INFO, self._onGetstate)
157        self.Bind(basepage.EVT_PREVIOUS_STATE, self._onUndo)
158        self.Bind(basepage.EVT_NEXT_STATE, self._onRedo)
159       
160        #add default page
161        from hint_fitpage import HintFitPage
162        self.hint_page = HintFitPage(self) 
163        self.AddPage(page=self.hint_page, caption="Hint")
164        #Add the first fit page
165        self.add_empty_page()
166       
167        # increment number for model name
168        self.count=0
169        #updating the panel
170        self.Update()
171        self.Center()
172 
173    def on_close_page(self, event):
174        """
175             close page and remove all references to the closed page
176        """
177        nbr_page = self.GetPageCount()
178        if nbr_page == 1:
179            event.Veto()
180            return 
181        selected_page = self.GetPage(self.GetSelection())
182        self._close_helper(selected_page=selected_page)
183       
184    def close_page_with_data(self, deleted_data):
185        """
186            close a fit page when its data is completely remove from the graph
187        """
188        if deleted_data is None:
189            return
190        for index in range(self.GetPageCount()):
191            selected_page = self.GetPage(index) 
192            if hasattr(selected_page,"get_data"):
193                data = selected_page.get_data()
194                if data is None:
195                    #the fitpanel exists and only the initial fit page is open
196                    #with no selected data
197                    return
198                if data.name == deleted_data.name:
199                    self._close_helper(selected_page)
200                    self.DeletePage(index)
201                    break
202       
203    def set_manager(self, manager):
204        """
205             set panel manager
206             @param manager: instance of plugin fitting
207        """
208        self.manager = manager
209
210       
211    def set_owner(self,owner):
212        """
213            set and owner for fitpanel
214            @param owner: the class responsible of plotting
215        """
216        self.event_owner = owner
217   
218    def set_model_list(self, dict):
219         """
220             copy a dictionary of model into its own dictionary
221             @param dict: dictionnary made of model name as key and model class
222             as value
223         """
224         self.model_list_box = dict
225       
226 
227    def get_current_page(self):
228        """
229            @return the current page selected
230        """
231        return self.GetPage(self.GetSelection() )
232   
233    def add_sim_page(self):
234        """
235            Add the simultaneous fit page
236        """
237        from simfitpage import SimultaneousFitPage
238        page_finder= self.manager.get_page_finder()
239        self.sim_page = SimultaneousFitPage(self,page_finder=page_finder, id=-1)
240       
241        self.AddPage(self.sim_page,caption="Simultaneous Fit",select=True)
242        self.sim_page.set_manager(self.manager)
243        return self.sim_page
244       
245    def get_page_info(self, data=None):
246        """
247            fill information required to add a page in the fit panel
248        """
249        name = "Fit Page"
250        type = 'empty'
251        if data is not None:
252            if data.is_data:
253                name = data.name
254                type = 'Data'
255            else:
256                if data.__class__.__name__ == "Data2D":
257                    name = 'Model 2D Fit'
258                    type = 'Theory2D'
259                else:
260                    name = 'Model 1D Fit'
261                    type = 'Theory1D'
262        page_info = PageInfo(data=data, name=name)
263        page_info.event_owner = self.event_owner
264        page_info.manager = self.manager
265        page_info.window_name = name
266        page_info.window_caption = name
267        page_info.type = type
268        return page_info
269   
270    def add_empty_page(self):
271        """
272            add an empty page
273        """
274        page_info = self.get_page_info()
275        from fitpage import FitPage
276        panel = FitPage(parent=self, page_info=page_info)
277        self.AddPage(page=panel, caption=page_info.window_name, select=True)
278        self.opened_pages[page_info.type] = [page_info.window_name, panel]
279        return panel
280   
281    def add_page(self, page_info):
282        """
283            add a new page
284        """
285        from fitpage import FitPage
286        panel = FitPage(parent=self, page_info=page_info)
287        self.AddPage(page=panel, caption=page_info.window_name, select=True)
288        index = self.GetPageIndex(panel)
289        self.change_page_content(data=page_info.data, index=index)
290        return panel
291   
292    def change_page_content(self, data, index):
293        """
294            replace the contains of an existing page
295        """
296        page_info = self.get_page_info(data=data)
297        self.SetPageText(index, page_info.window_name)
298        panel = self.GetPage(index)
299        panel.set_data(data)
300        if panel.model_list_box is None or len(panel.model_list_box) == 0: 
301            page_info.model_list_box = self.model_list_box.get_list()
302            panel.populate_box(dict=page_info.model_list_box)
303            panel.initialize_combox()
304        panel.set_page_info(page_info=page_info)
305        self.opened_pages[page_info.type] = [page_info.window_name, panel]
306        return panel
307   
308    def replace_page(self, index, page_info, type):
309        """
310            replace an existing page
311        """
312        self.DeletePage(index)
313        del self.opened_pages[type]
314        return self.add_page(page_info=page_info)
315       
316    def add_fit_page(self, data, reset=False):
317        """
318            Add a fitting page on the notebook contained by fitpanel
319            @param data: data to fit
320            @return panel : page just added for further used. is used by fitting module
321        """
322        if data is None:
323            return None
324        page_info = self.get_page_info(data=data)
325        type = page_info.type
326        npages = len(self.opened_pages.keys())
327        #check if only and empty page is opened
328        if len(self.opened_pages.keys()) > 0:
329            first_page_type = self.opened_pages.keys()[0]
330            if npages == 1 and first_page_type in ['empty']:
331                #replace the first empty page
332                name, panel = self.opened_pages[first_page_type]
333                index = self.GetPageIndex(panel)
334                panel = self.change_page_content(data=data, index=index)
335                del self.opened_pages[first_page_type]
336                return panel
337        if type in self.opened_pages.keys():
338            #this type of page is already created but it is a theory
339            # meaning the same page is just to fit different data
340            if not type.lower() in ['data']:
341                #delete the previous theory page and add a new one
342                name, panel = self.opened_pages[type]
343                #self.manager.reset_plot_panel(panel.get_data())
344                #delete the existing page and replace it
345                index = self.GetPageIndex(panel)
346                panel = self.replace_page(index=index, page_info=page_info, type=type)
347                return panel
348            else:
349                for name, panel in self.opened_pages.values():
350                    #Don't return any panel is the exact same page is created
351                    if name == page_info.window_name:
352                        return None
353                    else:
354                        panel = self.add_page(page_info=page_info)
355                        return panel       
356        else:
357            #a new type of page is created
358            panel = self.add_page(page_info=page_info)
359            return panel
360   
361    def  _onGetstate(self, event):
362        """
363            copy the state of a page
364        """
365        page= event.page
366        if page.window_name in self.fit_page_name:
367            self.fit_page_name[page.window_name].appendItem(page.createMemento()) 
368           
369    def _onUndo(self, event ):
370        """
371            return the previous state of a given page is available
372        """
373        page = event.page
374        if page.window_name in self.fit_page_name:
375            if self.fit_page_name[page.window_name].getCurrentPosition()==0:
376                state = None
377            else:
378                state = self.fit_page_name[page.window_name].getPreviousItem()
379                page._redo.Enable(True)
380            page.reset_page(state)
381       
382    def _onRedo(self, event): 
383        """
384            return the next state available
385        """       
386        page = event.page
387        if page.window_name in self.fit_page_name:
388            length= len(self.fit_page_name[page.window_name])
389            if self.fit_page_name[page.window_name].getCurrentPosition()== length -1:
390                state = None
391                page._redo.Enable(False)
392                page._redo.Enable(True)
393            else:
394                state = self.fit_page_name[page.window_name].getNextItem()
395            page.reset_page(state) 
396                 
397    def _close_helper(self, selected_page):
398        """
399            Delete the given page from the notebook
400        """
401        #remove hint page
402        if selected_page == self.hint_page:
403            return
404        ## removing sim_page
405        if selected_page == self.sim_page :
406            self.manager.sim_page=None 
407            return
408       
409        ## closing other pages
410        state = selected_page.createMemento()
411        page_name = selected_page.window_name
412        page_finder = self.manager.get_page_finder() 
413        fitproblem = None
414        ## removing fit page
415        data = selected_page.get_data()
416        #Don' t remove plot for 2D
417        flag = True
418        if data.__class__.__name__ == 'Data2D':
419            flag = False
420        if selected_page in page_finder:
421            #Delete the name of the page into the list of open page
422            for type, list in self.opened_pages.iteritems():
423                #Don't return any panel is the exact same page is created
424                name = str(list[0])
425                if flag and selected_page.window_name == name:
426                    if type.lower() in ['theory1d', 'theory2d']:
427                        self.manager.remove_plot(selected_page, theory=True)
428                    else:
429                        self.manager.remove_plot(selected_page, theory=False)
430                    break 
431            del page_finder[selected_page]
432        ##remove the check box link to the model name of this page (selected_page)
433        try:
434            self.sim_page.draw_page()
435        except:
436            ## that page is already deleted no need to remove check box on
437            ##non existing page
438            pass
439               
440        #Delete the name of the page into the list of open page
441        for type, list in self.opened_pages.iteritems():
442            #Don't return any panel is the exact same page is created
443            name = str(list[0])
444            if selected_page.window_name == name:
445                del self.opened_pages[type]
446                break 
447     
448 
Note: See TracBrowser for help on using the repository browser.