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

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 c83a5af was 3cd5806, checked in by Gervaise Alina <gervyh@…>, 14 years ago

bindind save button with guiframe toolbar

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