source: sasview/sansview/perspectives/fitting/fitpanel.py @ 509af3d

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 509af3d was 2f189dc, checked in by Gervaise Alina <gervyh@…>, 15 years ago

refactore fitpanel and removing the bug introduce while changing add fitpage use case

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