Index: sansview/perspectives/fitting/__init__.py
===================================================================
--- sansview/perspectives/fitting/__init__.py	(revision d89f09b35713186021727a80260c3d5a38746821)
+++ sansview/perspectives/fitting/__init__.py	(revision d89f09b35713186021727a80260c3d5a38746821)
@@ -0,0 +1,2 @@
+PLUGIN_ID = "Fitting plug-in 1.0"
+from fitting import *
Index: sansview/perspectives/fitting/fitpage.py
===================================================================
--- sansview/perspectives/fitting/fitpage.py	(revision d89f09b35713186021727a80260c3d5a38746821)
+++ sansview/perspectives/fitting/fitpage.py	(revision d89f09b35713186021727a80260c3d5a38746821)
@@ -0,0 +1,612 @@
+import sys
+import wx
+import wx.lib
+import numpy
+import copy
+
+from sans.guicomm.events import StatusEvent   
+(ModelEventbox, EVT_MODEL_BOX) = wx.lib.newevent.NewEvent()
+_BOX_WIDTH = 80
+
+def format_number(value, high=False):
+    """
+        Return a float in a standardized, human-readable formatted string 
+    """
+    try: 
+        value = float(value)
+    except:
+        print "returning 0"
+        return "0"
+    
+    if high:
+        return "%-6.4g" % value
+    else:
+        return "%-5.3g" % value
+
+    
+class FitPage(wx.Panel):
+    """
+        FitPanel class contains fields allowing to display results when
+        fitting  a model and one data
+        @note: For Fit to be performed the user should check at least one parameter
+        on fit Panel window.
+  
+    """
+    ## Internal name for the AUI manager
+    window_name = "Fit page"
+    ## Title to appear on top of the window
+    window_caption = "Fit Page"
+    
+    
+    def __init__(self, parent, *args, **kwargs):
+        wx.Panel.__init__(self, parent, *args, **kwargs)
+        """ 
+            Initialization of the Panel
+        """
+        self.manager = None
+        self.parent  = parent
+        self.event_owner=None
+        #panel interface
+        self.vbox  = wx.BoxSizer(wx.VERTICAL)
+        self.sizer4 = wx.GridBagSizer(5,5)
+        self.sizer3 = wx.GridBagSizer(5,5)
+        self.sizer2 = wx.GridBagSizer(5,5)
+        self.sizer1 = wx.GridBagSizer(5,5)
+        self.DataSource      = wx.TextCtrl(self, -1,size=(_BOX_WIDTH,20))
+        self.DataSource.SetToolTipString("name of data to fit")
+        self.modelbox = wx.ComboBox(self, -1)
+        id = wx.NewId()
+        self.btFit =wx.Button(self,id,'Fit')
+        self.btFit.Bind(wx.EVT_BUTTON, self.onFit,id=id)
+        self.btFit.SetToolTipString("Perform fit.")
+        self.vbox.Add(self.sizer3)
+        self.vbox.Add(self.sizer2)
+        self.vbox.Add(self.sizer4)
+        self.vbox.Add(self.sizer1)
+        
+        ix = 0
+        iy = 1
+        self.sizer3.Add(wx.StaticText(self, -1, 'Data Source'),(iy,ix),\
+                 (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        ix += 1
+        self.sizer3.Add(self.DataSource,(iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        ix += 1
+        self.sizer3.Add((20,20),(iy,ix),(1,1),wx.RIGHT|wx.EXPAND|wx.ADJUST_MINSIZE,0)
+        ix = 0
+        iy += 1
+        self.sizer3.Add(wx.StaticText(self,-1,'Model'),(iy,ix),(1,1)\
+                  , wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        ix += 1
+        self.sizer3.Add(self.modelbox,(iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        ix = 1
+        iy = 1
+        self.text4_1 = wx.StaticText(self, -1, 'Min')
+        self.sizer4.Add(self.text4_1,(iy, ix),(1,1),\
+                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        self.text4_1.Hide()
+        ix += 2
+        self.text4_2 = wx.StaticText(self, -1, 'Max')
+        self.sizer4.Add(self.text4_2,(iy, ix),(1,1),\
+                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        self.text4_2.Hide()
+        ix = 0
+        iy += 1
+        #set maximum range for x in linear scale
+        self.text4_3 = wx.StaticText(self, -1, 'Maximum Data\n Range (Linear)', style=wx.ALIGN_LEFT)
+        self.sizer4.Add(self.text4_3,(iy,ix),(1,1),\
+                   wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        self.text4_3.Hide()
+        ix += 1
+        self.xmin    = wx.TextCtrl(self, -1,size=(_BOX_WIDTH,20))
+        self.xmin.SetToolTipString("Minimun value of x in linear scale.")
+        self.sizer4.Add(self.xmin,(iy, ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        self.xmin.Bind(wx.EVT_KILL_FOCUS, self._onTextEnter)
+        self.xmin.Hide()
+        ix += 2
+        self.xmax    = wx.TextCtrl(self, -1,size=(_BOX_WIDTH,20))
+        self.xmax.SetToolTipString("Maximum value of x in linear scale.")
+        self.sizer4.Add(self.xmax,(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        self.xmax.Bind(wx.EVT_KILL_FOCUS, self._onTextEnter)
+        self.xmax.Hide()
+        #Set chisqr  result into TextCtrl
+        ix = 0
+        iy = 1
+        self.text1_1 = wx.StaticText(self, -1, 'Chi2/dof', style=wx.ALIGN_LEFT)
+        self.sizer1.Add(self.text1_1,(iy,ix),(1,1),\
+                   wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        ix += 1
+        self.tcChi    = wx.TextCtrl(self, -1,size=(_BOX_WIDTH,20))
+        self.tcChi.SetToolTipString("Chi^2 over degrees of freedom.")
+        self.sizer1.Add(self.tcChi,(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        ix +=2
+        self.sizer1.Add(self.btFit,(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        
+        # contains link between  model ,all its parameters, and panel organization
+        self.parameters=[]
+        #contains link between a model and selected parameters to fit 
+        self.param_toFit=[]
+        # model on which the fit would be performed
+        self.model=None
+        # preview selected model name
+        self.prevmodel_name=None
+        # flag to check if the user has selected a new model in the combox box
+        self.model_hasChanged=False
+        #flag to check if the user has selected a new data
+        self.data_hasChanged=False
+        #dictionary of model name and model class
+        self.model_list_box={}
+        # Data1D to make a deep comparison between 2 Data1D for checking data
+        #change
+        from sans.guitools.plottables import Data1D
+        self.prevData = Data1D(x=[], y=[],dx=None, dy=None)
+        self.prevData.name= None
+        
+        self.data=None
+        self.vbox.Layout()
+        self.vbox.Fit(self) 
+        self.SetSizer(self.vbox)
+        self.Centre()
+        
+        
+    def set_owner(self,owner):
+        """ 
+            set owner of fitpage
+            @param owner: the class responsible of plotting
+        """
+        self.event_owner=owner    
+   
+  
+    def set_manager(self, manager):
+        """
+             set panel manager
+             @param manager: instance of plugin fitting
+        """
+        self.manager = manager
+ 
+         
+    def _DataNameEnter(self):
+        """
+            reset the panel when a new data is selected
+        """
+        if len(self.parameters )>0:
+            for item in self.parameters:
+                item[0].SetValue(False)
+                wx.EVT_CHECKBOX(self, item[0].GetId(), self.select_param)
+                item[2].Hide()
+                item[3].Clear()
+                item[3].Hide()
+                self.xmax.Disable()
+                self.xmin.Disable()
+                self.text1_1.Hide()
+                self.tcChi.Clear()
+                self.vbox.Layout() 
+                self.GrandParent.GetSizer().Layout()
+                
+                
+    def copy_data(self,dataset):
+        """
+             copy a select data in the panel to compared with the previous selected data
+             @param dataset: the data selected
+             @note : everything a data is selected, the panel check is it is different 
+             from the previous selected data
+        """
+       
+        try:
+            if dataset !=None:
+                self.prevData.x= copy.deepcopy(dataset.x)
+                self.prevData.y= copy.deepcopy(dataset.y)
+                self.prevData.name=dataset.name
+                if dataset.dy==None:
+                    self.prevData.dy= copy.deepcopy(dataset.dy)
+        except:
+            raise ValueError, " copy_data: cannot copy data" 
+        
+        
+    def onFit(self,event):
+        """ signal for fitting"""
+         
+        flag=self.checkFitRange()
+        self.set_manager(self.manager)
+     
+        qmin=float(self.xmin.GetValue())
+        qmax =float( self.xmax.GetValue())
+        if len(self.param_toFit) >0 and flag==True:
+            #self.manager._on_single_fit(model=self.model,qmin=qmin,qmax=qmax)
+            self.manager._on_single_fit(qmin=qmin,qmax=qmax)
+        else:
+              wx.PostEvent(self.parent.GrandParent, StatusEvent(status=\
+                            "Select at least on parameter to fit "))
+    def populate_box(self, dict):
+        """
+            Populate each combox box of each page
+            @param page: the page to populate
+        """
+        id=0
+        self.model_list_box=dict
+        for item in self.model_list_box.itervalues():
+            if hasattr(item, "name"):
+                name = item.name
+            else:
+                name = item.__name__
+            
+            self.modelbox.Insert(name,int(id))
+            id+=1
+            
+            wx.EVT_COMBOBOX(self.modelbox,-1, self._on_select_model) 
+        return 0
+    
+    
+    def _on_select_model(self,event):
+        """
+            react when a model is selected from page's combo box
+            post an event to its owner to draw an appropriate theory
+        """
+        for item in self.model_list_box.itervalues():
+            model=item()
+            if hasattr(model, "name"):
+                name = model.name
+            else:
+                name = model.__class__.__name__
+            try:
+                if name ==event.GetString():
+                    evt = ModelEventbox(model=model,name=name)
+                    wx.PostEvent(self.event_owner, evt)
+            except:
+                raise #ValueError,"model.name is not equal to model class name"
+
+
+    
+    def _onTextEnter(self,event):
+        """
+            set a flag to determine if the fitting range entered by the user is valid
+        """
+        try:
+            flag=self.checkFitRange()
+            if flag==True and self.model!=None:
+                 self.manager.redraw_model(float(self.xmin.GetValue())\
+                                               ,float(self.xmax.GetValue()))
+        except:
+            wx.PostEvent(self.parent.GrandParent, StatusEvent(status=\
+                            "Drawing  Error:wrong value entered %s"% sys.exc_value))
+        
+    def checkFitRange(self):
+        """
+            Check the validity of fitting range
+            @note: xmin should always be less than xmax or else each control box
+            background is colored in pink.
+        """
+       
+        flag = True
+        valueMin = self.xmin.GetValue()
+        valueMax = self.xmax.GetValue()
+        # Check for possible values entered
+        
+        try:
+            if (float(valueMax)> float(valueMin)):
+                self.xmax.SetBackgroundColour(wx.WHITE)
+                self.xmin.SetBackgroundColour(wx.WHITE)
+            else:
+                flag = False
+                self.xmin.SetBackgroundColour("pink")
+                self.xmax.SetBackgroundColour("pink")      
+        except:
+            flag = False
+            self.xmin.SetBackgroundColour("pink")
+            self.xmax.SetBackgroundColour("pink")
+            
+        self.xmin.Refresh()
+        self.xmax.Refresh()
+        return flag
+    
+    def check_data_change(self,dataset):
+        """
+             check if data selected has changed and set flag self.data_hasChanged
+             has true is changed or false is unchanged
+             @param dataset: data selected
+        """
+        self.data_hasChanged=False
+        if self.prevData.__class__ !=dataset.__class__:
+            self.data_hasChanged=True
+            
+        elif self.prevData.name != dataset.name:
+            self.data_hasChanged=True
+            
+        elif len(self.prevData.x) != len(self.prevData.y):
+            self.data_hasChanged=True
+            
+        else:
+            for i in range(len(dataset.x)):
+                if self.prevData.x[i] !=dataset.x[i]:
+                    self.data_hasChanged=True
+                    break
+                
+                if self.prevData.y[i] !=dataset.y[i]:
+                    self.data_hasChanged=True
+                    break
+                
+                if dataset.dy !=None:
+                    if self.prevData.dy[i] !=dataset.dy[i]:
+                        self.data_hasChanged=True
+                        break
+                    
+                    
+    def set_data_name(self,dataset):
+        """ 
+            set data's name.if data has changed reset the panel and xmin and xmax
+            @param name: data 's name
+            @attention:  still  haven't find a better way to display Q name and unit
+            for xmin and xmax range sizer
+        """
+        self.check_data_change(dataset)
+        if self.data_hasChanged==True:
+            self._DataNameEnter()
+        self.data=dataset
+        self.copy_data(dataset)
+        #Displaying Data information
+        self.DataSource.SetValue(str(dataset.name))
+        self._xaxis,self._xunit=dataset.get_xaxis()
+        self.text4_3.SetLabel(self._xaxis+"["+self._xunit+"]")
+        self.text4_1.Show()
+        self.text4_2.Show()
+        self.text4_3.Show()
+        
+        self.xmin.SetValue(format_number(min(dataset.x)))
+        self.xmin.Show()
+
+        self.xmax.SetValue(format_number(max(dataset.x)))
+        self.xmax.Show()
+        
+        if ((len(self.param_toFit ) >0) and self.DataSource.GetValue()and \
+            self.modelbox.GetValue() and (self.model_hasChanged ==False)):
+            self.xmin.Enable()
+            self.xmax.Enable()
+        else:
+            self.xmin.Disable()
+            self.xmax.Disable()
+            
+        self.vbox.Layout()
+        self.GrandParent.GetSizer().Layout()
+        
+        
+    def set_model_name(self,name):
+        """ 
+            set model name. set also self.model_hasChanged to true is the model 
+            type has changed or false if it didn't
+            @param name: model 's name
+        """
+        self.model_hasChanged=False
+        if (name != self.prevmodel_name):
+            self.model_hasChanged=True
+        self.tcChi.Clear()
+        #self.modelbox.SetValue(str(name))
+        self.prevmodel_name=self.modelbox.GetValue()
+       
+            
+    def get_model_box(self): 
+        """ return reference to combox box self.model"""
+        return self.modelbox
+
+    
+    def get_param_list(self):
+        """
+            @return self.param_toFit: list containing  references to TextCtrl
+            checked.Theses TextCtrl will allow reference to parameters to fit.
+            @raise: if return an empty list of parameter fit will nnote work 
+            properly so raise ValueError,"missing parameter to fit"
+        """
+        if self.param_toFit !=[]:
+            return self.param_toFit
+        else:
+            raise ValueError,"missing parameter to fit"
+        
+        
+    def set_panel(self,model):
+        """
+            Build the panel from the model content
+            @param model: the model selected in combo box for fitting purpose
+        """
+    
+        self.sizer2.Clear(True)
+        self.parameters = []
+        self.param_toFit=[]
+        self.model = model
+        keys = self.model.getParamList()
+        keys.sort()
+        iy = 1
+        ix = 0
+        self.cb1 = wx.CheckBox(self, -1,'Parameters', (10, 10))
+        wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_param)
+        self.sizer2.Add(self.cb1,(iy, ix),(1,1),\
+                          wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        ix +=1
+        self.text2_2 = wx.StaticText(self, -1, 'Values')
+        self.sizer2.Add(self.text2_2,(iy, ix),(1,1),\
+                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
+        ix +=2
+        self.text2_3 = wx.StaticText(self, -1, 'Errors')
+        self.sizer2.Add(self.text2_3,(iy, ix),(1,1),\
+                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        self.text2_3.Hide() 
+        ix +=1
+        self.text2_4 = wx.StaticText(self, -1, 'Units')
+        self.sizer2.Add(self.text2_4,(iy, ix),(1,1),\
+                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
+        self.text2_4.Hide()
+        for item in keys:
+            iy += 1
+            ix = 0
+
+            cb = wx.CheckBox(self, -1, item, (10, 10))
+            cb.SetValue(False)
+            self.sizer2.Add( cb,( iy, ix),(1,1),  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+            wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
+            
+            ix += 1
+            value= self.model.getParam(item)
+            ctl1 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=wx.TE_PROCESS_ENTER)
+            ctl1.SetValue(str (format_number(value)))
+            ctl1.Bind(wx.EVT_KILL_FOCUS, self._onparamEnter)
+            self.sizer2.Add(ctl1, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+            ix += 1
+            text2=wx.StaticText(self, -1, '+/-')
+            self.sizer2.Add(text2,(iy, ix),(1,1),\
+                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
+            text2.Hide()  
+            ix += 1
+            ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=wx.TE_PROCESS_ENTER)
+            self.sizer2.Add(ctl2, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+            ctl2.Hide()
+            ix +=1
+            # Units
+            try:
+                units = wx.StaticText(self, -1, self.model.details[item][0], style=wx.ALIGN_LEFT)
+            except:
+                units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
+             
+            self.sizer2.Add(units, (iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+            #save data
+            self.parameters.append([cb,ctl1,text2,ctl2])
+        #Display units text on panel
+        for item in keys:   
+            if self.model.details[item][0]!='':
+                self.text2_4.Show()
+                break
+            else:
+                self.text2_4.Hide()
+        #Disable or enable fit button
+        if (self.modelbox.GetValue() and self.DataSource.GetValue()):
+            if not (len(self.param_toFit ) >0):
+                self.xmin.Disable()
+                self.xmax.Disable()
+            else:
+                self.xmin.Enable()
+                self.xmax.Enable()
+        else:
+            self.xmin.Disable()
+            self.xmax.Disable()
+      
+        self.vbox.Layout()
+        self.GrandParent.GetSizer().Layout()
+        
+    
+        
+    def _onparamEnter(self,event):
+        """ 
+            when enter value on panel redraw model according to changed
+        """
+        if len(self.parameters) !=0 and self.model !=None:
+            for item in self.parameters:
+                try:
+                     name=str(item[0].GetLabelText())
+                     value= float(item[1].GetValue())
+                     
+                     self.model.setParam(name,value)
+                     self.manager.redraw_model(float(self.xmin.GetValue())\
+                                               ,float(self.xmax.GetValue()))
+                except:
+                     wx.PostEvent(self.parent.GrandParent, StatusEvent(status=\
+                            "Drawing  Error:wrong value entered : %s"% sys.exc_value))
+        
+       
+    def select_all_param(self,event): 
+        """
+             set to true or false all checkBox given the main checkbox value cb1
+        """
+        self.param_toFit=[]
+        if  self.parameters !=[]:
+            if  self.cb1.GetValue()==True:
+                for item in self.parameters:
+                   
+                    item[0].SetValue(True)
+                    list= [item[0],item[1],item[2],item[3]]
+                    self.param_toFit.append(list )
+                if (self.modelbox.GetValue() and self.DataSource.GetValue()):
+                    if not (len(self.param_toFit ) >0):
+                        self.xmin.Disable()
+                        self.xmax.Disable()
+                    else:
+                        self.xmin.Enable()
+                        self.xmax.Enable()
+            else:
+                for item in self.parameters:
+                    item[0].SetValue(False)
+                self.param_toFit=[]
+              
+                self.xmin.Disable()
+                self.xmax.Disable()
+                
+                
+    def select_param(self,event):
+        """ 
+            Select TextCtrl  checked for fitting purpose and stores them
+            in  self.param_toFit=[] list
+        """
+        self.param_toFit=[]
+        for item in self.parameters:
+            if item[0].GetValue()==True:
+                list= [item[0],item[1],item[2],item[3]]
+                self.param_toFit.append(list )  
+            else:
+                if item in self.param_toFit:
+                    self.param_toFit.remove(item)
+        if len(self.parameters)==len(self.param_toFit):
+            self.cb1.SetValue(True)
+        else:
+            self.cb1.SetValue(False)
+        if (self.modelbox.GetValue() and self.DataSource.GetValue()):
+            if not (len(self.param_toFit ) >0):
+                self.xmin.Disable()
+                self.xmax.Disable()
+            else:
+                self.xmin.Enable()
+                self.xmax.Enable()
+        else:
+            self.xmin.Disable()
+            self.xmax.Disable()
+   
+       
+  
+    def onsetValues(self,chisqr, out,cov):
+        """
+            Build the panel from the fit result
+            @param chisqr:Value of the goodness of fit metric
+            @param out:list of parameter with the best value found during fitting
+            @param cov:Covariance matrix
+       
+        """
+        #print "fitting : onsetvalues out",out
+        self.tcChi.Clear()
+        self.tcChi.SetValue(format_number(chisqr))
+        params = {}
+        is_modified = False
+        has_error = False
+        if out.__class__==numpy.float64:
+            self.param_toFit[0][1].SetValue(format_number(out))
+            self.param_toFit[0][1].Refresh()
+            if cov !=None :
+                self.text2_3.Show()
+                self.param_toFit[0][2].Show()
+                self.param_toFit[0][3].Clear()
+                self.param_toFit[0][3].SetValue(format_number(cov[0]))
+                self.param_toFit[0][3].Show()
+        #out is a list : set parameters and errors in TextCtrl
+        else:
+            i=0
+            #print "fitpage: list param  model",list
+            #for item in self.param_toFit:
+            #    print "fitpage: list display",item[0].GetLabelText()
+            for item in self.param_toFit:
+                if( out != None ) and len(out)<=len(self.param_toFit)and i < len(out):
+                    item[1].SetValue(format_number(out[i]))
+                    item[1].Refresh() 
+                if (cov !=None)and len(cov)<=len(self.param_toFit)and i < len(cov):
+                    self.text2_3.Show() 
+                    item[2].Show()
+                    item[3].Clear()
+                    item[3].SetValue(format_number(cov[i]))
+                    item[3].Show()   
+                i+=1
+        
+        self.vbox.Layout()
+        self.GrandParent.GetSizer().Layout()
+    
Index: sansview/perspectives/fitting/fitpanel.py
===================================================================
--- sansview/perspectives/fitting/fitpanel.py	(revision d89f09b35713186021727a80260c3d5a38746821)
+++ sansview/perspectives/fitting/fitpanel.py	(revision d89f09b35713186021727a80260c3d5a38746821)
@@ -0,0 +1,151 @@
+import wx
+import wx.lib
+import numpy
+import string ,re
+#import models
+_BOX_WIDTH = 80
+
+
+    
+class FitPanel(wx.Panel):
+    """
+        FitPanel class contains fields allowing to fit  models and  data
+        @note: For Fit to be performed the user should check at least one parameter
+        on fit Panel window.
+       
+    """
+    ## Internal name for the AUI manager
+    window_name = "Fit panel"
+    ## Title to appear on top of the window
+    window_caption = "Fit Panel "
+   
+    
+    def __init__(self, parent, *args, **kwargs):
+        wx.Panel.__init__(self, parent, *args, **kwargs)
+        self.manager=None
+        self.parent=parent
+        self.event_owner=None
+        #self.menu_mng = models.ModelManager()
+        self.nb = wx.Notebook(self)
+        self.sizer = wx.BoxSizer(wx.VERTICAL)
+        self.sizer.Add(self.nb, 0, wx.EXPAND)
+        #Creating an initial page for simultaneous fitting
+        from simfitpage import SimultaneousFitPage
+        self.sim_page = SimultaneousFitPage(self.nb, -1)
+        
+        #self.fit_panel.add_page(self.sim_page,"Simultaneous Fit")
+        self.nb.AddPage(self.sim_page,"Simultaneous Fit")
+        
+        id = wx.NewId()
+        self.btClose =wx.Button(self,id,'Close')
+        self.btClose.Bind(wx.EVT_BUTTON, self.onClose,id=id)
+        self.btClose.SetToolTipString("Close page.")
+    
+        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
+        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        sizer_button.Add(self.btClose, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
+        self.sizer.Add(sizer_button,1, wx.EXPAND)
+        #dictionary of miodel {model class name, model class}
+        self.model_list_box={}
+        # save the title of the last page tab added
+        self.name=None
+        self.nb.Update()
+        self.SetSizer(self.sizer)
+        self.sizer.Fit(self)
+        self.Center()
+        
+        
+    def set_manager(self, manager):
+        """
+             set panel manager
+             @param manager: instance of plugin fitting
+        """
+        self.manager = manager
+        self.sim_page.set_manager(manager)
+        
+    def set_owner(self,owner):
+        """ 
+            set and owner for fitpanel
+            @param owner: the class responsible of plotting
+        """
+        self.event_owner=owner
+      
+        
+    def add_page( self,page_title ):
+        """ 
+            Add a fitting page on the notebook contained by fitpanel
+            @param panel: contains in the page to add
+            @param name: title of the page tab
+            @return panel : page just added for futher used. is used by fitting module
+        """     
+        if self.name != page_title:
+            from fitpage import FitPage
+            panel = FitPage(self.nb, -1)
+            panel.set_manager(self.manager)
+            panel.set_owner(self.event_owner)
+            self.nb.AddPage(page=panel,text=page_title,select=True)
+            panel.populate_box( self.model_list_box)
+            self.name = page_title
+            return panel
+  
+    def get_notebook(self):
+        """
+            @return self.nb: return its own notebook mostly used by fitting module 
+        """
+        return self.nb
+    
+    def get_page(self, n):
+        """
+            @return page at position n
+            @param n: page number
+        """
+        return self.nb.GetPage(n)
+    
+    
+    def get_page_count(self):
+        """ @return  number total of pages contained in notebook"""
+        return self.nb.GetPageCount()
+        
+        
+    def get_current_page(self):
+        """
+            @return the current page selected
+        """
+        return self.nb.GetCurrentPage()
+    
+    
+    def get_selected_page(self):
+        """ @return the page just selected by the user """
+        return self.nb.GetPage(self.nb.GetSelection())
+    
+    def onClose(self,event):
+        """
+             close the current page except the simpage. remove each check box link to the model
+             selected on that page. remove its reference into page_finder (fitting module)
+        """
+        sim_page = self.nb.GetPage(0)
+        selected_page = self.nb.GetPage(self.nb.GetSelection())
+        
+        if sim_page != selected_page:
+            # remove the check box link to the model name of this page (selected_page)
+            sim_page.remove_model(selected_page)
+            #remove that page from page_finder of fitting module
+            page_finder=self.manager.get_page_finder() 
+            for page, value in page_finder.iteritems():
+                if page==selected_page:
+                    del page_finder[page]
+                    break
+            #delete the page from notebook
+            selected_page.Destroy()
+            self.nb.RemovePage(self.nb.GetSelection())
+            self.name=None
+            
+            
+    def set_model_list(self,dict):
+         """ 
+             copy a dictionary of model into its own dictionary
+             @param dict: dictionnary made of model name as key and model class
+             as value
+         """
+         self.model_list_box = dict
+  
Index: sansview/perspectives/fitting/fitproblem.py
===================================================================
--- sansview/perspectives/fitting/fitproblem.py	(revision d89f09b35713186021727a80260c3d5a38746821)
+++ sansview/perspectives/fitting/fitproblem.py	(revision d89f09b35713186021727a80260c3d5a38746821)
@@ -0,0 +1,79 @@
+from sans.fit.AbstractFitEngine import Model
+
+class FitProblem:
+    """  
+        FitProblem class allows to link a model with the new name created in _on_model,
+        a name theory created with that model  and the data fitted with the model.
+        FitProblem is mostly used  as value of the dictionary by fitting module.
+    """
+    
+    def __init__(self):
+        
+        """
+            @ self.data :is the data selected to perform the fit
+            @ self.theory_name: the name of the theory created with self.model
+            @ self.model_list:  is a list containing a model as first element 
+            and its name assign example [lineModel, M0]
+        """
+        self.data=None
+        self.theory_name=None
+        self.model_list=[]
+        
+    def set_model(self,model,name):
+        """ 
+             associates each model with its new created name
+             @param model: model selected
+             @param name: name created for model
+        """
+        self.model_list=[model,name]
+
+  
+    def add_data(self,data):
+        """ 
+            save a copy of the data select to fit
+            @param data: data selected
+        """
+        self.data = data
+            
+    def get_model(self):
+        """ @return: saved model """
+        return self.model_list
+     
+    def get_data(self):
+        """ @return:  list of data dList"""
+        return self.data
+      
+      
+    def get_theory(self):
+        """ @return the name of theory for plotting purpose"""
+        return self.theory_name
+    
+    
+    def set_theory(self,name):
+        """
+            Set theory name
+            @param name: name of the theory
+        """
+        self.theory_name = name
+
+        
+    def set_model_param(self,name,value):
+        """ 
+            set the value of a given parameter of this model
+            @param name: name of the given parameter
+            @param value: value of that parameter
+        """
+        
+        self.model_list[0].model.setParam(name,value)
+        new_model=Model(self.model_list[0].model)
+        self.model_list[0]=new_model
+        
+    def reset_model(self,model):
+        """ 
+            reset a model when parameter has changed
+            @param value: new model
+        """
+        print "fitproblem : reset model"
+        self.model_list[0]=model
+        
+        
Index: sansview/perspectives/fitting/fitting.py
===================================================================
--- sansview/perspectives/fitting/fitting.py	(revision d89f09b35713186021727a80260c3d5a38746821)
+++ sansview/perspectives/fitting/fitting.py	(revision d89f09b35713186021727a80260c3d5a38746821)
@@ -0,0 +1,570 @@
+import os,os.path, re
+import sys, wx, logging
+import string, numpy, pylab, math
+
+from sans.guitools.plottables import Data1D, Theory1D
+from sans.guitools.PlotPanel import PlotPanel
+from sans.guicomm.events import NewPlotEvent, StatusEvent  
+from copy import deepcopy 
+from sans.fit.AbstractFitEngine import Model
+from sans.fit.AbstractFitEngine import Data
+from fitproblem import FitProblem
+from fitpanel import FitPanel
+
+import models
+import fitpage
+class PlottableData(Data,Data1D):
+    """ class plottable data"""
+    def __init__(self,data,data1d):
+        self.x = data1d.x
+        self.y = data1d.y
+        self.dx= data1d.dx
+        self.dy= data1d.dy
+       
+        self.group_id= data1d.group_id
+        x_name, x_units = data1d.get_xaxis() 
+        y_name, y_units = data1d.get_yaxis() 
+        self.xaxis( x_name, x_units)
+        self.yaxis( y_name, y_units )
+        self.qmin=data.qmin
+        self.qmax=data.qmax
+class Plugin:
+    """
+    """
+    
+    def __init__(self):
+        ## Plug-in name
+        self.sub_menu = "Fitting"
+        
+        ## Reference to the parent window
+        self.parent = None
+        self.menu_mng = models.ModelManager()
+        ## List of panels for the simulation perspective (names)
+        self.perspective = []
+        # Start with a good default
+        self.elapsed = 0.022
+        self.fitter  = None
+       
+        #Flag to let the plug-in know that it is running standalone
+        self.standalone=True
+        ## Fit engine
+        self._fit_engine = 'park'
+        # Log startup
+        logging.info("Fitting plug-in started")   
+
+    def populate_menu(self, id, owner):
+        """
+            Create a menu for the Fitting plug-in
+            @param id: id to create a menu
+            @param owner: owner of menu
+            @ return : list of information to populate the main menu
+        """
+        #Menu for fitting
+        self.menu1 = wx.Menu()
+        id1 = wx.NewId()
+        self.menu1.Append(id1, '&Show fit panel')
+        wx.EVT_MENU(owner, id1, self.on_perspective)
+        
+        #menu for model
+        menu2 = wx.Menu()
+        self.menu_mng.populate_menu(menu2, owner)
+        id2 = wx.NewId()
+        owner.Bind(models.EVT_MODEL,self._on_model_menu)
+        self.fit_panel.set_owner(owner)
+        self.fit_panel.set_model_list(self.menu_mng.get_model_list())
+        owner.Bind(fitpage.EVT_MODEL_BOX,self._on_model_panel)
+      
+        return [(id, self.menu1, "Fitting"),(id2, menu2, "Model")]
+    
+    
+    def help(self, evt):
+        """
+            Show a general help dialog. 
+            TODO: replace the text with a nice image
+        """
+        pass
+    
+    def get_context_menu(self, graph=None):
+        """
+            Get the context menu items available for P(r)
+            @param graph: the Graph object to which we attach the context menu
+            @return: a list of menu items with call-back function
+        """
+        
+        self.graph=graph
+        for item in graph.plottables:
+            if item.name==graph.selected_plottable and item.__class__.__name__ is not "Theory1D":
+                return [["Select Data", "Dialog with fitting parameters ", self._onSelect]] 
+        return []   
+
+
+    def get_panels(self, parent):
+        """
+            Create and return a list of panel objects
+        """
+        self.parent = parent
+        # Creation of the fit panel
+        self.fit_panel = FitPanel(self.parent, -1)
+        #Set the manager forthe main panel
+        self.fit_panel.set_manager(self)
+        # List of windows used for the perspective
+        self.perspective = []
+        self.perspective.append(self.fit_panel.window_name)
+        # take care of saving  data, model and page associated with each other
+        self.page_finder={}
+        self.index_model=0
+        return [self.fit_panel]
+   
+      
+    def get_perspective(self):
+        """
+            Get the list of panel names for this perspective
+        """
+        return self.perspective
+    
+    
+    def on_perspective(self, event):
+        """
+            Call back function for the perspective menu item.
+            We notify the parent window that the perspective
+            has changed.
+        """
+        self.parent.set_perspective(self.perspective)
+    
+    
+    def post_init(self):
+        """
+            Post initialization call back to close the loose ends
+            [Somehow openGL needs this call]
+        """
+        self.parent.set_perspective(self.perspective)
+        
+        
+    def _onSelect(self,event):
+        """ 
+            when Select data to fit a new page is created .Its reference is 
+            added to self.page_finder
+        """
+        self.panel = event.GetEventObject()
+        for item in self.panel.graph.plottables:
+            if item.name == self.panel.graph.selected_plottable:
+                try:
+                    name = item.group_id # item in Data1D
+                except:
+                    name = 'Fit'
+                try:
+                    page = self.fit_panel.add_page(name)
+                    page.set_data_name(item)
+                    self.page_finder[page]= FitProblem()
+                    #creating Data type
+                    data1= Data(sans_data=item)
+                    datas=PlottableData(data=data1,data1d=item)
+                    self.page_finder[page].add_data(datas)
+                except:
+                    raise 
+                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: \
+                    data already Selected "))
+                    
+                    
+    def get_page_finder(self):
+        """ @return self.page_finder used also by simfitpage.py"""  
+        return self.page_finder 
+    
+    
+    def set_page_finder(self,modelname,param,values):
+        """
+             Used by simfitpage.py to reset a parameter given the string constrainst.
+             @param modelname: the name ot the model for with the parameter has to reset
+             @param value: can be a string in this case.
+             @note: expecting park used for fit.
+        """  
+        sim_page=self.fit_panel.get_page(0)
+        for page, value in self.page_finder.iteritems():
+            if page != sim_page:
+                list=value.get_model()
+                model=list[0]
+                if model.name== modelname:
+                    value.set_model_param(param,values)
+                    break
+
+   
+                            
+    def split_string(self,item): 
+        """
+            recieve a word containing ""
+        """
+        #print "fitting: split :went here" 
+        
+        if string.find(item,".")!=-1:
+            param_names= re.split("\.",item)
+            model_name=param_names[0]
+            param_name=param_names[1]  
+            return model_name,param_name
+        
+        
+    def _single_fit_completed(self,result,pars,current_pg,qmin,qmax):
+        """
+          
+        """
+       
+        try:
+            for page, value in self.page_finder.iteritems():
+                if page== current_pg:
+                    data = value.get_data()
+                    list = value.get_model()
+                    model= list[0]
+                    break
+            #print "fitting : result",result,result.pvec,result.cov,result.fitness
+            i = 0
+            for name in pars:
+                if result.pvec.__class__==numpy.float64:
+                    model.model.setParam(name,result.pvec)
+                else:
+                    model.model.setParam(name,result.pvec[i])
+                    #print "fitting: i name out[i]", i,name,float(result.pvec[i])
+                    i += 1
+            new_cov=[]
+            if result.cov !=None:
+                 for j in range(len(result.cov)):
+                     new_cov.append(result.cov[j][j])  
+            else:
+                new_cov=None
+            current_pg.onsetValues(result.fitness, result.pvec,new_cov)
+            self.plot_helper(currpage=current_pg,qmin=qmin,qmax=qmax)
+        except:
+             wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
+            
+       
+    def _simul_fit_completed(self,result,qmin,qmax):
+        """
+            Parameter estimation completed, 
+            display the results to the user
+            @param alpha: estimated best alpha
+            @param elapsed: computation time
+        """
+        try:
+            for page, value in self.page_finder.iteritems():
+                data = value.get_data()
+                list = value.get_model()
+                model= list[0]
+               
+                small_out = []
+                small_cov = []
+                i = 0
+                for p in result.parameters:
+                    print "fitting: fit in park fitting", p.name, p.value,p.stderr
+                    model_name,param_name = self.split_string(p.name)  
+                    print "fitting: simultfit",model.model.name,model_name,param_name ,p.name,param_name,p.value
+                    if model.model.name == model_name:
+                        print "fitting: hello",p.name,param_name,p.value
+                        small_out.append(p.value )
+                        small_cov.append(p.stderr)
+                        model.model.setParam(param_name,p.value)   
+                #print "fitting: out of each page",page,small_out,small_cov,data.group_id
+                page.onsetValues(result.fitness, small_out,small_cov)
+                self.plot_helper(currpage= page,qmin= qmin,qmax= qmax) 
+        except:
+             wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
+            
+     
+    def _completed(self,result,pars,current_pg, elapsed):
+        """
+            Method called with the results when the inversion
+            is done
+            
+            @param out: output coefficient for the base functions
+            @param cov: covariance matrix
+            @param pr: Invertor instance
+            @param elapsed: time spent computing
+        """
+       
+        # Save useful info
+        self.elapsed = elapsed
+        # Keep a copy of the last result
+        self._last_out = result.pvec
+        self._last_cov = result.cov
+        self._last_chisqr=result.fitness
+        #print "fitting: initial parameter ",pars
+        #result=self.fitter.fit(qmin,qmax)
+        
+        #print "fitting : result",result,result.pvec,result.cov,result.fitness
+        i = 0
+        for name in pars:
+            if result.pvec.__class__==numpy.float64:
+                model.model.setParam(name,result.pvec)
+            else:
+                model.model.setParam(name,result.pvec[i])
+                #print "fitting: i name out[i]", i,name,float(result.pvec[i])
+                i += 1
+        new_cov=[]
+        if result.cov !=None:
+             for j in range(len(result.cov)):
+                 new_cov.append(result.cov[j][j])  
+        else:
+            new_cov=None
+        current_pg.onsetValues(result.fitness, result.pvec,new_cov)
+        self.plot_helper(currpage=current_pg,qmin=qmin,qmax=qmax)
+ 
+        
+    def _on_single_fit(self,id=None,qmin=None,qmax=None):
+        """ 
+            perform fit for the  current page  and return chisqr,out and cov
+            @param engineName: type of fit to be performed
+            @param id: unique id corresponding to a fit problem(model, set of data)
+            @param model: model to fit
+            
+        """
+        #set an engine to perform fit
+        from sans.fit.Fitting import Fit
+        self.fitter= Fit(self._fit_engine)
+        #Setting an id to store model and data
+        if id==None:
+            id=0
+        self.id=id
+        current_pg=self.fit_panel.get_current_page() 
+        for page, value in self.page_finder.iteritems():
+            if page ==current_pg :
+                #print "fitting: self.page_finder",self.page_finder
+                data = value.get_data()
+                list=value.get_model()
+                model=list[0]
+                
+                #Create dictionary of parameters for fitting used
+                pars=[]
+                templist=[]
+                try:
+                    templist=current_pg.get_param_list()
+                except:
+                    raise
+                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
+                    return
+                #for element in templist:
+                #    print "fitting: templist",str(element[0].GetLabelText())
+                #print "fitting: model list",model.getParamList()
+                for element in templist:
+                    try:
+                       pars.append(str(element[0].GetLabelText()))
+                    except:
+                        raise
+                        wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
+                        return
+                #print "fitting: pars",pars
+                pars.sort()
+                
+                self.fitter.set_model(model,model.name, self.id, pars) 
+                self.fitter.set_data(data,self.id,qmin,qmax)
+                #Do the fit SCIPY
+                try:
+                    result=self.fitter.fit()
+                    self._single_fit_completed(result,pars,current_pg,qmin,qmax)
+                   
+                except:
+                    wx.PostEvent(self.parent, StatusEvent(status="Single Fit error: %s" % sys.exc_value))
+                    return
+         
+    def _on_simul_fit(self, id=None,qmin=None,qmax=None):
+        """ 
+            perform fit for all the pages selected on simpage and return chisqr,out and cov
+            @param engineName: type of fit to be performed
+            @param id: unique id corresponding to a fit problem(model, set of data)
+             in park_integration
+            @param model: model to fit
+            
+        """
+        #print "fitting: probabily breaking on fit call"
+        #set an engine to perform fit
+        from sans.fit.Fitting import Fit
+        self.fitter= Fit(self._fit_engine)
+        #Setting an id to store model and data
+        if id==None:
+             id = 0
+        self.id = id
+        for page, value in self.page_finder.iteritems():
+            try:
+                #print "fitting: self.page_finder",value
+                data = value.get_data()
+                #print "fitting: data",data
+                list = value.get_model()
+                model= list[0]
+                if data != None :
+                    #Create dictionary of parameters for fitting used
+                    pars = []
+                    templist = []
+                    try:
+                        templist = page.get_param_list()
+                    except:
+                        wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
+                        return
+                    
+                    for element in templist:
+                        try:
+                            name = str(element[0].GetLabelText())
+                            pars.append(name)
+                        except:
+                            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
+                            return
+                
+                    print "fitting: pars",pars,model.name
+                    #print "fitter",self.fitter
+                    #print "fitting: model name",model.name
+                    self.fitter.set_model(model,model.model.name, self.id, pars) 
+                    self.fitter.set_data(data,self.id,qmin,qmax)
+                else:
+                    raise ValueError," Fitting: cannot set model with empty parameter"
+                self.id += 1 
+            except:
+                    raise
+                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
+                    return 
+        #Do the fit SCIPY
+        try:
+            result=self.fitter.fit()
+            self._simul_fit_completed(result,qmin,qmax)
+        except:
+            raise
+            wx.PostEvent(self.parent, StatusEvent(status="Simultaneous Fitting error: %s" % sys.exc_value))
+            return
+   
+    def _on_change_engine(self, engine='park'):
+        """
+            Allow to select the type of engine to perform fit 
+            @param engine: the key work of the engine
+        """
+        self._fit_engine = engine
+   
+   
+    def _on_model_panel(self, evt):
+        """
+            react to model selection on any combo box or model menu.plot the model  
+        """
+        model = evt.model
+        name = evt.name
+        sim_page=self.fit_panel.get_page(0)
+        current_pg = self.fit_panel.get_current_page() 
+        if current_pg != sim_page:
+            current_pg.set_model_name(name)
+            current_pg.set_panel(model)
+            try:
+                data=self.page_finder[current_pg].get_data()
+                M_name="M"+str(self.index_model)+"= "+name+"("+data.group_id+")"
+            except:
+                raise 
+                M_name="M"+str(self.index_model)+"= "+name
+            model.name="M"+str(self.index_model)
+            self.index_model += 1  
+            self.page_finder[current_pg].set_theory("Fitness")
+            #print "on model",model.name
+            self.page_finder[current_pg].set_model(Model(model),M_name)
+            self.plot_helper(currpage= current_pg,qmin= None,qmax= None)
+            sim_page.add_model(self.page_finder)
+        
+            
+    def redraw_model(self,qmin= None,qmax= None):
+        """
+            Draw a theory according to model changes or data range.
+            @param qmin: the minimum value plotted for theory
+            @param qmax: the maximum value plotted for theory
+        """
+        current_pg=self.fit_panel.get_current_page()
+        for page, value in self.page_finder.iteritems():
+            if page ==current_pg :
+                break 
+        self.plot_helper(currpage=page,qmin= qmin,qmax= qmax)
+        
+    def plot_helper(self,currpage,qmin=None,qmax=None):
+        """
+            Plot a theory given a model and data
+            @param model: the model from where the theory is derived
+            @param currpage: page in a dictionary referring to some data
+        """
+        #print "fitting: plot helper"
+        if self.fit_panel.get_page_count() >1:
+            for page in self.page_finder.iterkeys():
+                if  page==currpage :  
+                    break 
+           
+            data=self.page_finder[page].get_data()
+            list=self.page_finder[page].get_model()
+            model=list[0]
+            if data!=None:
+                theory = Theory1D(x=[], y=[])
+                theory.name = self.page_finder[page].get_theory()
+                theory.group_id = data.group_id
+              
+                x_name, x_units = data.get_xaxis() 
+                y_name, y_units = data.get_yaxis() 
+                theory.xaxis(x_name, x_units)
+                theory.yaxis(y_name, y_units)
+              
+                if qmin == None :
+                   qmin = min(data.x)
+                if qmax == None :
+                    qmax = max(data.x)
+                try:
+                    tempx = qmin
+                    tempy = model.eval(qmin)
+                    theory.x.append(tempx)
+                    theory.y.append(tempy)
+                except :
+                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
+                        skipping point x %g %s" %(qmin, sys.exc_value)))
+                           
+                for i in range(len(data.x)):
+                    try:
+                        if data.x[i]> qmin and data.x[i]< qmax:
+                            tempx = data.x[i]
+                            tempy = model.eval(tempx)
+                            
+                            theory.x.append(tempx) 
+                            theory.y.append(tempy)
+                    except:
+                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
+                        skipping point x %g %s" %(data.x[i], sys.exc_value)))   
+                try:
+                    tempx = qmax
+                    tempy = model.eval(qmax)
+                    theory.x.append(tempx)
+                    theory.y.append(tempy)
+                except:
+                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
+                        skipping point x %g %s" %(qmax, sys.exc_value)))
+                try:
+                    from sans.guicomm.events import NewPlotEvent
+                    #print"fitting: theory",theory
+                    wx.PostEvent(self.parent, NewPlotEvent(plot=theory, title="Analytical model"))
+                except:
+                    raise
+                    print "SimView.complete1D: could not import sans.guicomm.events"
+            
+            
+    def _on_model_menu(self, evt):
+        """
+            Plot a theory from a model selected from the menu
+        """
+        x = pylab.arange(0.001, 0.1, 0.001)
+        xlen = len(x)
+        dy = numpy.zeros(xlen)
+        y = numpy.zeros(xlen)
+        
+        for i in range(xlen):
+            y[i] = evt.model.run(x[i])
+            dy[i] = math.sqrt(math.fabs(y[i]))
+        try:
+           
+            new_plot = Theory1D(x, y)
+            #new_plot.name = evt.model.__class__.__name__
+            new_plot.name ="Fitness"
+            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
+            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
+         
+            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Analytical model"))
+        except:
+            print "SimView.complete1D: could not import sans.guicomm.events"
+
+
+if __name__ == "__main__":
+    i = Plugin()
+    
+    
+    
+    
Index: sansview/perspectives/fitting/models.py
===================================================================
--- sansview/perspectives/fitting/models.py	(revision d89f09b35713186021727a80260c3d5a38746821)
+++ sansview/perspectives/fitting/models.py	(revision d89f09b35713186021727a80260c3d5a38746821)
@@ -0,0 +1,87 @@
+import wx
+import os
+import os.path
+
+(ModelEvent, EVT_MODEL) = wx.lib.newevent.NewEvent()
+
+
+class ModelManager:
+    
+    ## Dictionary of models
+    model_list = {}
+    model_list_box = {}
+    ## Event owner
+    event_owner = None
+    
+    def _getModelList(self):
+        """
+            List of models we want to make available by default
+            for this application
+            
+            @param id: first event ID to register the menu events with
+            @return: the next free event ID following the new menu events
+        """
+        self.model_list = {}
+        self.model_list_box = {}
+        from sans.models.CylinderModel import CylinderModel
+        self.model_list[str(wx.NewId())] = CylinderModel 
+      
+        from sans.models.SphereModel import SphereModel
+        self.model_list[str(wx.NewId())] = SphereModel
+   
+        from sans.guitools.LineModel import LineModel
+        self.model_list[str(wx.NewId())]  = LineModel
+      
+        return 0
+
+    
+    def populate_menu(self, modelmenu, event_owner):
+        """
+            Populate a menu with our models
+            
+            @param id: first menu event ID to use when binding the menu events
+            @param modelmenu: wx.Menu object to populate
+            @param event_owner: wx object to bind the menu events to
+            @return: the next free event ID following the new menu events
+        """
+        
+        self._getModelList()
+        self.event_owner = event_owner
+
+        for id_str,value in self.model_list.iteritems():
+            item = self.model_list[id_str]
+            
+            name = item.__name__
+            if hasattr(item, "name"):
+                name = item.name
+                
+            self.model_list_box[name] =value
+            
+            modelmenu.Append(int(id_str), name, name)
+            wx.EVT_MENU(event_owner, int(id_str), self._on_model)       
+    
+        return 0
+    
+    def _on_model(self, evt):
+        """
+            React to a model menu event
+            @param event: wx menu event
+        """
+        if str(evt.GetId()) in self.model_list.keys():
+            # Notify the application manager that a new model has been set
+            #self.app_manager.set_model(self.model_list[str(evt.GetId())]())
+            
+            #TODO: post a model event to update all panels that need
+            #evt = ModelEvent(model=self.model_list[str(evt.GetId())]())
+           
+            model = self.model_list[str(evt.GetId())]()
+            evt = ModelEvent(model=model)
+            wx.PostEvent(self.event_owner, evt)
+        
+    def get_model_list(self):    
+        """ @ return dictionary of models for fitpanel use """
+        return self.model_list_box
+    
+    
+    
+ 
Index: sansview/perspectives/fitting/simfitpage.py
===================================================================
--- sansview/perspectives/fitting/simfitpage.py	(revision d89f09b35713186021727a80260c3d5a38746821)
+++ sansview/perspectives/fitting/simfitpage.py	(revision d89f09b35713186021727a80260c3d5a38746821)
@@ -0,0 +1,253 @@
+
+
+import sys,re,string, wx   
+from sans.guicomm.events import StatusEvent    
+
+class SimultaneousFitPage(wx.Panel):
+    """
+        Simultaneous fitting panel
+        All that needs to be defined are the
+        two data members window_name and window_caption
+    """
+      ## Internal name for the AUI manager
+    window_name = "simultaneous Fit page"
+    ## Title to appear on top of the window
+    window_caption = "Simultaneous Fit Page"
+    
+    
+    def __init__(self, parent, *args, **kwargs):
+        wx.Panel.__init__(self, parent, *args, **kwargs)
+        """
+             Simultaneous page display
+        """
+        self.parent = parent
+        self.sizer3 = wx.GridBagSizer(5,5)
+        self.sizer1 = wx.GridBagSizer(5,5)
+        self.sizer2 = wx.GridBagSizer(5,5)
+        self.vbox  = wx.BoxSizer(wx.VERTICAL)
+        self.vbox.Add(self.sizer3)
+        self.vbox.Add(self.sizer1)
+        self.vbox.Add(self.sizer2)
+        id = wx.NewId()
+        self.btFit =wx.Button(self,id,'Constraint Fit')
+        self.btFit.Bind(wx.EVT_BUTTON, self.onFit,id=id)
+        self.btFit.SetToolTipString("Perform fit.")
+        ix = 0
+        iy = 1 
+        self.cb1 = wx.CheckBox(self, -1,'Models', (10, 10))
+        self.sizer3.Add(self.cb1,(iy, ix),(1,1),\
+                        wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_model_name)
+        wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_model_name)
+        ix  = 0
+        iy  = 1
+        text=wx.StaticText(self, -1, 'Constraint')
+        self.sizer2.Add(text,(iy, ix),(1,1),\
+                        wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        ix  = 0
+        iy  += 1
+        self.ctl2 = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
+        self.ctl2.Bind(wx.EVT_KILL_FOCUS, self._onTextEnter)
+        self.sizer2.Add(self.ctl2, (iy, ix),(1,1),wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        ix +=2
+        self.sizer2.Add(self.btFit,(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        self.params=[]
+        self.model_list=[]
+        self.model_toFit=[]
+        iy +=1
+        self.sizer2.Add((20,20),(iy, ix))
+        self.vbox.Layout()
+        self.vbox.Fit(self) 
+        self.SetSizer(self.vbox)
+        self.Centre()
+        
+        
+    def onFit(self,event):
+         """ signal for fitting"""
+         if len(self.model_toFit) >0 :
+             self.set_model()
+             self.manager._on_simul_fit()
+         else:
+             wx.PostEvent(self.parent.GrandParent, StatusEvent(status=\
+                            "Select at least on model to fit "))
+    def set_manager(self, manager):
+        """
+            set panel manager
+            @param manager: instance of plugin fitting
+        """
+        self.manager = manager
+        
+        
+    def select_all_model_name(self,event):
+        """
+            check all models names
+        """
+        self.model_toFit=[] 
+        if self.cb1.GetValue()==True:
+            for item in self.model_list:
+                item[0].SetValue(True)
+                self.model_toFit.append(item)
+        else:
+            for item in self.model_list:
+                item[0].SetValue(False) 
+            self.model_toFit=[]
+       
+            
+    def add_model(self,page_finder):
+        """
+            Receive a dictionary containing information to display model name
+            @param page_finder: the dictionary containing models information
+        """
+        self.model_list=[]
+        self.model_toFit=[]
+        self.sizer1.Clear(True)
+        ix = 0
+        iy = 1 
+        list=[]
+        for page, value in page_finder.iteritems():
+            try:
+                list=value.get_model()
+                model=list[0]
+                modelname=list[1]
+                cb = wx.CheckBox(self, -1, modelname, (10, 10))
+                cb.SetValue(False)
+                self.sizer1.Add( cb,( iy,ix),(1,1),  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+                ix = 0
+                iy += 1 
+                wx.EVT_CHECKBOX(self, cb.GetId(), self.select_model_name)
+                self.model_list.append([cb,value,page,modelname])
+            except:
+                #wx.PostEvent(self.parent.GrandParent, StatusEvent(status="Simultaneous fit: %s doesn't have a model selected yet %s" % \
+                #(value.get_data().group_id,sys.exc_value)))
+                pass
+        self.sizer1.Layout()        
+        self.vbox.Layout()
+        
+    def remove_model(self,delpage):
+        """
+             Remove  a checkbox and the name realted to a model selected on page delpage
+             @param delpage: the page removed
+        """
+        self.sizer1.Clear(True)
+        ix = 0
+        iy = 1 
+        for item in self.model_list:
+            try:
+                if not delpage in item:
+                    #print "simfitpage:  redraw modelname",item[3]
+                    cb = wx.CheckBox(self, -1, item[3], (10, 10))
+                    cb.SetValue(False)
+                    self.sizer1.Add( cb,( iy,ix),(1,1),  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+                    ix = 0
+                    iy += 1 
+                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_model_name)
+                else:
+                    self.model_list.remove(item)
+            except:
+                raise
+        self.sizer1.Layout()        
+        self.vbox.Layout()
+            
+        
+    def select_model_name(self,event):
+        """
+            Save interformation related to checkbox and their states
+        """
+        self.model_toFit=[]
+        for item in self.model_list:
+            if item[0].GetValue()==True:
+                self.model_toFit.append(item)
+            else:
+                if item in self.model_toFit:
+                    self.model_toFit.remove(item)
+                    self.cb1.SetValue(False)
+        if len(self.model_list)==len(self.model_toFit):
+            self.cb1.SetValue(True)
+        else:
+            self.cb1.SetValue(False)
+  
+   
+    def set_model(self):
+        """
+            set_model take values in self.params which are the values enters by the user
+            and try to assign them into the model concerned in self.manager. page.finder
+        """
+        if len(self.params) >0:
+            for item in self.model_toFit:
+                #print"simfitpage: self.model_toFit",item[1]
+                list=item[1].get_model()
+                #print "simfitpage: list fitpanel2",list,list[0]
+                model=list[0]
+                param_list=model.model.getParamList()
+                #print "simfitpage: on set_model ",self.params
+                if self.params !=[]:
+                    for element in self.params:
+                        if model.model.name == str(element[0]):
+                            for item in param_list:
+                                if item==str(element[1]):
+                                    #print "simfitpage: on set_model page 1",param_list
+                                    #print "simfitpage: model name",element[0], model.name
+                                    #print "simfitpage: param name ,param value",element[1],element[2]
+                                    self.manager.set_page_finder(model.model.name,element[1],\
+                                                                 str(element[2]))
+                            #print "simfitpage:on set_model page 2",model.params['A'],self.params[2]
+                
+                
+    def _onTextEnter(self,event):
+        """
+            get values from the constrainst textcrtl ,parses them into model name
+            parameter name and parameters values.
+            store them in a list self.params .when when params is not empty set_model uses it
+            to reset the appropriate model and its appropriates parameters
+        """
+        value= self.ctl2.GetValue()
+        self.params=[]
+        #print "simfitpage: value",value
+        try:
+            expression='[\s,;]'
+            if re.search(expression,value) !=None:
+                word=re.split(expression,value)
+                #print "simfitpage: when herre",word
+                for item in word:
+                    try:
+                        self.params.append(self.parser_helper(item))
+                    except:
+                        wx.PostEvent(self.parent.GrandParent, StatusEvent(status="Loading Error: %s" % sys.exc_value))
+            else:
+                try:
+                    self.params.append(self.parser_helper(value))
+                except:
+                     wx.PostEvent(self.parent.GrandParent, StatusEvent(status="Loading Error: %s" % sys.exc_value))
+        except:
+            raise
+        #print "simfitpage: self.params",self.params
+        
+        
+        
+    def parser_helper(self,value):
+        """
+             @return  param:a list containing the name of a model ,its parameters 
+             value and name extracted from the constrainst controlbox
+        """
+        #print "simfitpage: value",value
+        if string.find(value, "=") !=-1:
+            model_param= re.split("=",value)
+            param_name=model_param[0]
+            param_value=model_param[1]
+            #print"simfitpage: ", param_name
+            #print "simfitpage: ",param_value
+            if string.find(param_name,".")!=-1:
+                param_names= re.split("\.",param_name)
+                model_name=param_names[0]
+                param_name=param_names[1]
+                param=[str(model_name),str(param_name),str(param_value)]
+                #print "simfitpage: param",param
+                return param
+            else:
+                raise ValueError,"cannot evaluate this expression"
+                return
+        else:
+            raise ValueError,"Missing '=' in expression"
+        
+   
+    
