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

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 a0da535 was 340c2b3, checked in by Gervaise Alina <gervyh@…>, 14 years ago

make panel inheriting from panelBase

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