Index: sansview/perspectives/fitting/basepage.py
===================================================================
--- sansview/perspectives/fitting/basepage.py	(revision 9466f2d6a8ec770363ff314de3d4768470b1a6f6)
+++ sansview/perspectives/fitting/basepage.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -158,4 +158,7 @@
         #self.onSave(event=None)
         self.Bind(wx.EVT_CONTEXT_MENU, self.onContextMenu)
+        
+        # bind key event
+        self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
 
         ## create the basic structure of the panel with empty sizer
@@ -427,5 +430,9 @@
                                             style=wx.RB_GROUP)
         self.enable_disp = wx.RadioButton(self, -1, 'On', (10, 30))
-       
+
+        self.disp_help_bt = wx.Button(self,wx.NewId(),'?', size=(20,15))
+        self.disp_help_bt.Bind(wx.EVT_BUTTON, 
+                        self.on_pd_help_clicked,id= self.disp_help_bt.GetId())
+        self.disp_help_bt.SetToolTipString("Helps for Polydispersion.")       
         
         self.Bind(wx.EVT_RADIOBUTTON, self._set_dipers_Param,
@@ -442,33 +449,14 @@
         sizer_dispersion.Add((20,20))
         sizer_dispersion.Add(self.disable_disp )
-        sizer_dispersion.Add((10,10))
-        
-        ## fill a sizer with the combobox to select dispersion type
-        sizer_select_dispers = wx.BoxSizer(wx.HORIZONTAL)  
-        self.model_disp = wx.StaticText(self, -1, 'Distribution Function ')
-            
-        import sans.models.dispersion_models 
-        self.polydisp= sans.models.dispersion_models.models
-        self.disp_box = wx.ComboBox(self, -1)
-
-        for key, value in self.polydisp.iteritems():
-            name = str(key)
-            self.disp_box.Append(name,value)
-        self.disp_box.SetStringSelection("gaussian") 
-        wx.EVT_COMBOBOX(self.disp_box,-1, self._on_select_Disp) 
-             
-        sizer_select_dispers.Add((10,10)) 
-        sizer_select_dispers.Add(self.model_disp) 
-        sizer_select_dispers.Add(self.disp_box,0,
-                wx.TOP|wx.BOTTOM|wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE,border=5)
-      
-        self.model_disp.Hide()
-        self.disp_box.Hide()
-        
+        sizer_dispersion.Add((25,20))
+        sizer_dispersion.Add(self.disp_help_bt)
+        
+        ## fill a sizer for dispersion         
         boxsizer1.Add( sizer_dispersion,0,
                 wx.TOP|wx.BOTTOM|wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE,border=5)
         #boxsizer1.Add( (10,10) )
-        boxsizer1.Add( sizer_select_dispers )
-        self.sizer4_4 = wx.GridBagSizer(5,5)
+        #boxsizer1.Add( sizer_select_dispers )
+        self.sizer4_4 = wx.GridBagSizer(6,5)
+
         boxsizer1.Add( self.sizer4_4  )
         #-----------------------------------------------------
@@ -484,106 +472,4 @@
         self.SetupScrolling()
 
-    def select_disp_angle(self, event): 
-        """
-        Event for when a user select a parameter to average over.
-        
-        :param event: radiobutton event
-        
-        """
-        self.values=[]
-        self.weights=[]
-        if event.GetEventObject()==self.noDisper_rbox:
-            if self.noDisper_rbox.GetValue():
-                #No array dispersity apply yet
-                self._reset_dispersity()
-                ## Redraw the model ???
-                self._draw_model()
-        # Go through the list of dispersion check boxes to identify
-        # which one has changed 
-        for p in self.disp_cb_dict:
-            self.state.disp_cb_dict[p]=  self.disp_cb_dict[p].GetValue()
-            # Catch which one of the box was just checked or unchecked.
-            if event.GetEventObject() == self.disp_cb_dict[p]:              
-                if self.disp_cb_dict[p].GetValue() == True:
-                    
-                    ##Temp. FIX for V1.0 regarding changing checkbox 
-                    #to radiobutton.
-                    ##This (self._reset_dispersity) should be removed 
-                    #when the array dispersion is fixed.                
-                    self._reset_dispersity()
-
-                    # The user wants this parameter to be averaged. 
-                    # Pop up the file selection dialog.
-                    path = self._selectDlg()
-                    
-                    # If nothing was selected, just return
-                    if path is None:
-                        self.disp_cb_dict[p].SetValue(False)
-                        self.noDisper_rbox.SetValue(True)
-                        return
-                    try:
-                        self._default_save_location = os.path.dirname(path)
-                    except:
-                        pass 
-                    try:
-                        self.values,self.weights = self.read_file(path)
-                    except:
-                        msg="Could not read input file"
-                        wx.PostEvent(self.parent.parent, 
-                                     StatusEvent(status=msg))
-                        return
-                    
-                    # If any of the two arrays is empty, notify the user that we won't
-                    # proceed 
-                    if self.values is None or self.weights is None or \
-                         self.values ==[] or self.weights ==[]:
-                        msg = "The loaded %s distrubtion is"
-                        msg + " corrupted or empty" % p
-                        wx.PostEvent(self.parent.parent, 
-                                     StatusEvent(status=msg))
-                        return
-                        
-                    # Tell the user that we are about to apply the distribution
-                    msg = "Applying loaded %s distribution: %s" % (p, path)
-                    wx.PostEvent(self.parent.parent, StatusEvent(status=msg))  
-                    
-                    # Create the dispersion objects
-                    from sans.models.dispersion_models import ArrayDispersion
-                    disp_model = ArrayDispersion()
-                    disp_model.set_weights(self.values, self.weights)
-                   
-                    # Store the object to make it persist outside the
-                    # scope of this method
-                    #TODO: refactor model to clean this up?
-                    self._disp_obj_dict[p] = disp_model
-                    self.state._disp_obj_dict [p]= disp_model
-                    self.state.values = []
-                    self.state.weights = []
-                    self.state.values = copy.deepcopy(self.values)
-                    self.state.weights = copy.deepcopy(self.weights)
-                    # Set the new model as the dispersion object for the 
-                    #selected parameter
-                    self.model.set_dispersion(p, disp_model)
-                    # Store a reference to the weights in the model object 
-                    #so that
-                    # it's not lost when we use the model within another thread.
-                    #TODO: total hack - fix this
-                    self.state.model= self.model.clone()
-
-                    self.model._persistency_dict = {}
-                    self.model._persistency_dict[p] = \
-                                                    [self.values, self.weights]
-                    self.state.model._persistency_dict[p] = \
-                                                    [self.values,self.weights]
-                else:
-                    self._reset_dispersity()
-              
-                ## Redraw the model
-                self._draw_model()
-        
-        ## post state to fit panel
-        event = PageInfoEvent(page = self)
-        wx.PostEvent(self.parent, event)
-       
     
     def onResetModel(self, event):
@@ -603,5 +489,16 @@
             previous_state = self.saved_states[name]
             ## reset state of checkbox,textcrtl  and  regular parameters value
-            self.reset_page(previous_state)      
+            self.reset_page(previous_state)   
+               
+    def on_report_state(self, event):
+        """
+        Report the current fit results
+        """   
+        event.Skip()
+        # Get plot image from plotpanel
+        images, canvases = self.get_images()
+        # get the report dialog
+        self.state.report(images, canvases)
+        
          
     def on_save(self, event):   
@@ -785,14 +682,4 @@
         self.state.qmax_x = self.qmax_x
         self.state.qmin_x = self.qmin_x
-        try:
-            n = self.disp_box.GetCurrentSelection()
-            dispersity= self.disp_box.GetClientData(n)
-            name= dispersity.__name__
-            self.disp_name = name
-            if name == "GaussianDispersion" :
-               if hasattr(self,"cb1"):
-                   self.state.cb1= self.cb1.GetValue()
-        except:
-            pass
       
         if hasattr(self,"enable_disp"):
@@ -811,22 +698,7 @@
         self.state.slit_smearer = copy.deepcopy(self.slit_smearer.GetValue())  
                   
-        if hasattr(self,"disp_box"):
-            self.state.disp_box = self.disp_box.GetSelection()
-
-            if len(self.disp_cb_dict)>0:
-                for k , v in self.disp_cb_dict.iteritems():
-         
-                    if v ==None :
-                        self.state.disp_cb_dict[k]= v
-                    else:
-                        try:
-                            self.state.disp_cb_dict[k]=v.GetValue()
-                        except:
-                            self.state.disp_cb_dict[k]= None
-           
-            if len(self._disp_obj_dict)>0:
-                for k , v in self._disp_obj_dict.iteritems():
-      
-                    self.state._disp_obj_dict[k]= v
+        if len(self._disp_obj_dict)>0:
+            for k , v in self._disp_obj_dict.iteritems():
+                self.state._disp_obj_dict[k]= v
                         
             
@@ -836,12 +708,15 @@
         self._save_plotting_range()
         
-        self.state.orientation_params =[]
-        self.state.orientation_params_disp =[]
-        self.state.parameters =[]
-        self.state.fittable_param =[]
-        self.state.fixed_param =[]
+        self.state.orientation_params = []
+        self.state.orientation_params_disp = []
+        self.state.parameters = []
+        self.state.fittable_param = []
+        self.state.fixed_param = []
+        self.state.str_parameters = []
 
         
         ## save checkbutton state and txtcrtl values
+        self._copy_parameters_state(self.str_parameters, 
+                                    self.state.str_parameters)
         self._copy_parameters_state(self.orientation_params,
                                      self.state.orientation_params)
@@ -873,15 +748,4 @@
         ## save data    
         self.state.data= copy.deepcopy(self.data)
-        try:
-            n = self.disp_box.GetCurrentSelection()
-            dispersity= self.disp_box.GetClientData(n)
-            name= dispersity.__name__
-            self.disp_name = name
-            if name == "GaussianDispersion" :
-               if hasattr(self,"cb1"):
-                   self.state.cb1= self.cb1.GetValue()
-
-        except:
-            pass
         
         if hasattr(self,"enable_disp"):
@@ -1065,5 +929,5 @@
             #self._undo.Enable(False)
             return 
-    
+        # set data, etc. from the state
         self.set_data(state.data)
         self.enable2D= state.enable2D
@@ -1108,52 +972,9 @@
         self.enable_disp.SetValue(state.enable_disp)
         self.disable_disp.SetValue(state.disable_disp)
-        
-        if hasattr(self, "disp_box"):
-            
-            self.disp_box.SetSelection(state.disp_box) 
-            n= self.disp_box.GetCurrentSelection()
-            dispersity= self.disp_box.GetClientData(n)
-            name = dispersity.__name__     
-
+        # If the polydispersion is ON
+        if state.enable_disp:
+            # reset dispersion according the state
             self._set_dipers_Param(event=None)
-       
-            if name == "ArrayDispersion":
-                
-                for item in self.disp_cb_dict.keys():
-                    
-                    if hasattr(self.disp_cb_dict[item], "SetValue") :
-                        self.disp_cb_dict[item].SetValue(\
-                                                    state.disp_cb_dict[item])
-                        # Create the dispersion objects
-                        from sans.models.dispersion_models import ArrayDispersion
-                        disp_model = ArrayDispersion()
-                        if hasattr(state,"values")and\
-                                 self.disp_cb_dict[item].GetValue() == True:
-                            if len(state.values)>0:
-                                self.values=state.values
-                                self.weights=state.weights
-                                disp_model.set_weights(self.values,
-                                                        state.weights)
-                            else:
-                                self._reset_dispersity()
-                        
-                        self._disp_obj_dict[item] = disp_model
-                        # Set the new model as the dispersion object 
-                        #for the selected parameter
-                        self.model.set_dispersion(item, disp_model)
-                    
-                        self.model._persistency_dict[item] = \
-                                                [state.values, state.weights]
-                    
-            else:
-                keys = self.model.getParamList()
-                for item in keys:
-                    if item in self.disp_list and \
-                        not self.model.details.has_key(item):
-                        self.model.details[item] = ["", None, None]
-                for k,v in self.state.disp_cb_dict.iteritems():
-                    self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict) 
-                    self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
-
+            self._reset_page_disp_helper(state)
         ##plotting range restore    
         self._reset_plotting_range(state)
@@ -1185,140 +1006,71 @@
         self.state = state.clone() 
     
-        
-    def old_reset_page_helper(self, state):
-        """
-        Use page_state and change the state of existing page
-        
-        :precondition: the page is already drawn or created
-        
-        :postcondition: the state of the underlying data change as well as the
-            state of the graphic interface
-        """
-        if state ==None:
-            #self._undo.Enable(False)
-            return 
-       
-        self.model= state.model
-        self.data = state.data
-        if self.data !=None:
-            from DataLoader.qsmearing import smear_selection
-            self.smearer= smear_selection(self.data, self.model)
-        self.enable2D= state.enable2D
-        self.engine_type = state.engine_type
-
-        self.disp_cb_dict = state.disp_cb_dict
-        self.disp_list = state.disp_list
-
-        ## set the state of the radio box
-        self.shape_rbutton.SetValue(state.shape_rbutton )
-        self.shape_indep_rbutton.SetValue(state.shape_indep_rbutton)
-        self.struct_rbutton.SetValue(state.struct_rbutton )
-        self.plugin_rbutton.SetValue(state.plugin_rbutton)
-        ##draw sizer containing model parameters value for the current model
-        self._set_model_sizer_selection( self.model )
-        self.set_model_param_sizer(self.model)
-
-        ## reset value of combox box
-        self.structurebox.SetSelection(state.structurecombobox )
-        self.formfactorbox.SetSelection(state.formfactorcombobox)
-        
-        
-        ## enable the view 2d button if this is a modelpage type
-        if hasattr(self,"model_view"):
-            if self.enable2D:
-                self.model_view.Disable()
+    def _reset_page_disp_helper(self, state):
+        """
+        Help to rest page for dispersions
+        """
+        keys = self.model.getParamList()
+        for item in keys:
+            if item in self.disp_list and \
+                not self.model.details.has_key(item):
+                self.model.details[item] = ["", None, None]
+        #for k,v in self.state.disp_cb_dict.iteritems():
+        self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict) 
+        self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
+        self.values = copy.deepcopy(state.values)
+        self.weights = copy.deepcopy(state.weights)
+        
+        for key, disp in state._disp_obj_dict.iteritems():
+            # From saved file, disp_model can not be sent in model obj.
+            # it will be sent as a string here, then converted to model object.
+            if disp.__class__.__name__ == 'str':
+                com_str  = "from sans.models.dispersion_models "
+                com_str += "import %s as disp_func"
+                exec com_str % disp
+                disp_model = disp_func()
             else:
-                self.model_view.Enable()
-        ## set the select all check box to the a given state
-        if hasattr(self, "cb1"):   
-            self.cb1.SetValue(state.cb1)
-     
-        ## reset state of checkbox,textcrtl  and  regular parameters value
-            
-        self._reset_parameters_state(self.orientation_params_disp,
-                                     state.orientation_params_disp)
-        self._reset_parameters_state(self.orientation_params,
-                                     state.orientation_params)
-        self._reset_parameters_state(self.parameters,state.parameters)    
-         ## display dispersion info layer        
-        self.enable_disp.SetValue(state.enable_disp)
-        self.disable_disp.SetValue(state.disable_disp)
-        
-        if hasattr(self, "disp_box"):
-            
-            self.disp_box.SetSelection(state.disp_box) 
-            n= self.disp_box.GetCurrentSelection()
-            dispersity= self.disp_box.GetClientData(n)
-            name= dispersity.__name__     
-
-            self._set_dipers_Param(event=None)
-       
-            if name=="ArrayDispersion":
-                
-                for item in self.disp_cb_dict.keys():
-                    
-                    if hasattr(self.disp_cb_dict[item],"SetValue") :
-                        self.disp_cb_dict[item].SetValue(state.disp_cb_dict[item])
-                        # Create the dispersion objects
-                        from sans.models.dispersion_models import ArrayDispersion
-                        disp_model = ArrayDispersion()
-                        if hasattr(state,"values") and\
-                             self.disp_cb_dict[item].GetValue()==True:
-                            if len(state.values) > 0:
-                                self.values = state.values
-                                self.weights = state.weights
-                                disp_model.set_weights(self.values,
-                                                        state.weights)
-                            else:
-                                self._reset_dispersity()
-                        
-                        self._disp_obj_dict[item] = disp_model
-                        # Set the new model as the dispersion
-                        #object for the selected parameter
-                        self.model.set_dispersion(item, disp_model)
-                    
-                        self.model._persistency_dict[item] = [state.values,
-                                                               state.weights]
-                    
-            else:
-                keys = self.model.getParamList()
-                for item in keys:
-                    if item in self.disp_list and \
-                            not self.model.details.has_key(item):
-                        self.model.details[item]=["",None,None]
-                for k,v in self.state.disp_cb_dict.iteritems():
-                    self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict) 
-                    self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
-
-        ##plotting range restore    
-        self._reset_plotting_range(state)
-
-        ## smearing info  restore
-        if hasattr(self,"enable_smearer"):
-            ## set smearing value whether or not the data 
-            #contain the smearing info
-            self.enable_smearer.SetValue(state.enable_smearer)
-            self.disable_smearer.SetValue(state.disable_smearer)
-            self.onSmear(event=None)           
-        self.pinhole_smearer.SetValue(state.pinhole_smearer)
-        self.slit_smearer.SetValue(state.slit_smearer)
-        ## we have two more options for smearing
-        if self.pinhole_smearer.GetValue(): self.onPinholeSmear(event=None)
-        elif self.slit_smearer.GetValue(): self.onSlitSmear(event=None)
-       
-        ## reset state of checkbox,textcrtl  and dispersity parameters value
-        self._reset_parameters_state(self.fittable_param,state.fittable_param)
-        self._reset_parameters_state(self.fixed_param,state.fixed_param)
-        
-        ## draw the model with previous parameters value
-        self._onparamEnter_helper()
-        
-        ## reset context menu items
-        self._reset_context_menu()
-    
-        ## set the value of the current state to the state given as parameter
-        self.state = state.clone() 
-        self._draw_model()
-
+                disp_model = disp
+
+            self._disp_obj_dict[key] = disp_model 
+            param_name = key.split('.')[0]
+            # Try to set dispersion only when available
+            # for eg., pass the orient. angles for 1D Cal 
+            try:
+                self.model.set_dispersion(param_name, disp_model)
+                self.model._persistency_dict[key] = \
+                                 [state.values, state.weights]
+            except:
+                pass
+            selection = self._find_polyfunc_selection(disp_model)
+            for list in self.fittable_param:
+                if list[1] == key and list[7] != None:
+                    list[7].SetSelection(selection)
+                    # For the array disp_model, set the values and weights 
+                    if selection == 1:
+                        disp_model.set_weights(self.values[key], 
+                                              self.weights[key])
+                        try:
+                            # Diables all fittable params for array
+                            list[0].SetValue(False)
+                            list[0].Disable()
+                            list[2].Disable()
+                            list[5].Disable()
+                            list[6].Disable()
+                        except:
+                            pass
+            # For array, disable all fixed params
+            if selection == 1:
+                for item in self.fixed_param:
+                    if item[1].split(".")[0] == key.split(".")[0]:
+                        # try it and pass it for the orientation for 1D
+                        try:
+                            item[2].Disable()
+                        except:
+                            pass
+    
+        # Make sure the check box updated when all checked
+        if self.cb1.GetValue():
+            self.select_all_param(None)        
+      
     def _selectDlg(self):
         """
@@ -1545,4 +1297,8 @@
             if item_page[2]!=None:
                 item_page[2].SetValue(item_page_info[2])
+                if item_page[2].__class__.__name__ == "ComboBox":
+                   if self.model.fun_list.has_key(item_page_info[2]):
+                       fun_val = self.model.fun_list[item_page_info[2]]
+                       self.model.setParam(item_page_info[1],fun_val)
             if item_page[3]!=None:
                 ## show or hide text +/-
@@ -1560,17 +1316,38 @@
             if item_page[5]!=None:
                 ## show of hide the text crtl for fitting error
-                if item_page_info[5][0]:
-                    item_page[5].Show(True)
-                    item_page[5].SetValue(item_page_info[5][1])
-                else:
-                    item_page[5].Hide()
-                    
+                item_page[5].Show(item_page_info[5][0])
+                item_page[5].SetValue(item_page_info[5][1])
+                
             if item_page[6]!=None:
                 ## show of hide the text crtl for fitting error
-                if item_page_info[6][0]:
-                    item_page[6].Show(True)
-                    item_page[6].SetValue(item_page_info[6][1])
-                else:
-                    item_page[6].Hide()
+                item_page[6].Show(item_page_info[6][0])
+                item_page[6].SetValue(item_page_info[6][1])
+
+                    
+    def _reset_strparam_state(self, listtorestore, statelist):
+        """
+        Reset the string parameters at the given state
+        """
+        if len(statelist) == 0:
+            return
+
+        listtorestore = copy.deepcopy(statelist)
+        
+        for j in range(len(listtorestore)):
+            item_page = listtorestore[j]
+            item_page_info = statelist[j]
+            ##change the state of the check box for simple parameters
+            
+            if item_page[0] != None:   
+                item_page[0].SetValue(format_number(item_page_info[0], True))
+
+            if item_page[2] != None:
+                param_name = item_page_info[1]
+                value = item_page_info[2]
+                selection = value
+                if self.model.fun_list.has_key(value):
+                    selection = self.model.fun_list[value]
+                item_page[2].SetValue(selection)
+                self.model.setParam(param_name, selection)
                                       
     def _copy_parameters_state(self, listtocopy, statelist):
@@ -1739,9 +1516,11 @@
                     break
     
-    def _draw_model(self):
+    def _draw_model(self, update_chisqr=True):
         """
         Method to draw or refresh a plotted model.
         The method will use the data member from the model page
         to build a call to the fitting perspective manager.
+        
+        :param chisqr: update chisqr value [bool]
         """
         #if self.check_invalid_panel():
@@ -1762,5 +1541,6 @@
                                     toggle_mode_on=toggle_mode_on, 
                                     state = self.state,
-                                    enable2D=self.enable2D)
+                                    enable2D=self.enable2D,
+                                    update_chisqr=update_chisqr)
         
        
@@ -2171,5 +1951,6 @@
             name = str(item[1])
             
-            if string.find(name,".npts") ==-1 and string.find(name,".nsigmas")==-1:      
+            if string.find(name,".npts") ==-1 and \
+                                        string.find(name,".nsigmas")==-1:      
                 ## check model parameters range             
                 param_min= None
@@ -2191,5 +1972,6 @@
                         except:
                             msg = "Wrong Fit parameter range entered "
-                            wx.PostEvent(self.parent.parent, StatusEvent(status = msg))
+                            wx.PostEvent(self.parent.parent, 
+                                         StatusEvent(status = msg))
                             raise ValueError, msg
                         is_modified = True
@@ -2207,5 +1989,6 @@
                         except:
                             msg = "Wrong Fit parameter range entered "
-                            wx.PostEvent(self.parent.parent, StatusEvent(status = msg))
+                            wx.PostEvent(self.parent.parent, 
+                                         StatusEvent(status = msg))
                             raise ValueError, msg
                         is_modified = True
@@ -2216,21 +1999,25 @@
                         msg= "Wrong Fit range entered for parameter "
                         msg+= "name %s of model %s "%(name, self.model.name)
-                        wx.PostEvent(self.parent.parent, StatusEvent(status = msg))
+                        wx.PostEvent(self.parent.parent, 
+                                     StatusEvent(status = msg))
                 
                 if name in self.model.details.keys():   
-                        self.model.details[name][1:3]= param_min,param_max
+                        self.model.details[name][1:3] = param_min, param_max
                         is_modified = True
               
                 else:
-                        self.model.details [name] = ["",param_min,param_max] 
+                        self.model.details [name] = ["", param_min, param_max] 
                         is_modified = True
-            try:     
-                value= float(item[2].GetValue())
-                item[2].SetBackgroundColour("white")
-                # If the value of the parameter has changed,
-                # +update the model and set the is_modified flag
-                if value != self.model.getParam(name) and numpy.isfinite(value):
-                    self.model.setParam(name,value)
-                    is_modified = True   
+            try:   
+                # Check if the textctr is enabled
+                if item[2].IsEnabled():
+                    value= float(item[2].GetValue())
+                    item[2].SetBackgroundColour("white")
+                    # If the value of the parameter has changed,
+                    # +update the model and set the is_modified flag
+                    if value != self.model.getParam(name) and \
+                                                numpy.isfinite(value):
+                        self.model.setParam(name, value)
+                        
             except:
                 item[2].SetBackgroundColour("pink")
@@ -2264,11 +2051,8 @@
         if self.model ==None:
             self.model_disp.Hide()
-            self.disp_box.Hide()
             self.sizer4_4.Clear(True)
             return
 
         if self.enable_disp.GetValue():
-            self.model_disp.Show(True)
-            self.disp_box.Show(True)
             ## layout for model containing no dispersity parameters
             
@@ -2281,7 +2065,4 @@
                 self._on_select_Disp(event=None)
         else:
-            self.model_disp.Hide()
-            self.disp_box.Hide()
-            self.disp_box.SetSelection(0) 
             self.sizer4_4.Clear(True)
             
@@ -2310,10 +2091,10 @@
         self.orientation_params_disp=[]
         
-        self.model_disp.Hide()
-        self.disp_box.Hide()
         self.sizer4_4.Clear(True)
         text = "No polydispersity available for this model"
+        text = "No polydispersity available for this model"
         model_disp = wx.StaticText(self, -1, text)
-        self.sizer4_4.Add(model_disp,( iy, ix),(1,1),  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        self.sizer4_4.Add(model_disp,( iy, ix),(1,1),  
+                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
         self.sizer4_4.Layout()
         self.sizer4.Layout()
@@ -2335,6 +2116,6 @@
         self.fixed_param=[]
         self.orientation_params_disp=[]
-        self.values=[]
-        self.weights=[]
+        self.values={}
+        self.weights={}
       
         from sans.models.dispersion_models import GaussianDispersion, ArrayDispersion
@@ -2368,15 +2149,6 @@
         self.disp_list should change type later .now only gaussian
         """
-        n = self.disp_box.GetCurrentSelection()
-        name = self.disp_box.GetValue()
-        dispersity= self.disp_box.GetClientData(n)
-        self.disp_name = name
-        
-        if name.lower() == "array":
-            self._set_sizer_arraydispersion()
-        else:
-            self._set_sizer_dispersion(dispersity= dispersity)
-            
-        self.state.disp_box= n
+        self._set_sizer_dispersion()
+
         ## Redraw the model
         self._draw_model() 
@@ -2389,90 +2161,181 @@
         self.SetupScrolling()
     
-    def _set_sizer_arraydispersion(self):
-        """
-        draw sizer with array dispersity  parameters
-        """
-        
+    def _on_disp_func(self, event=None): 
+        """
+        Select a distribution function for the polydispersion
+        
+        :Param event: ComboBox event 
+        """
+        # get ready for new event
+        if event != None:
+            event.Skip()
+        # Get event object
+        disp_box =  event.GetEventObject() 
+
+        # Try to select a Distr. function
+        try:   
+            disp_box.SetBackgroundColour("white")
+            selection = disp_box.GetCurrentSelection()
+            param_name = disp_box.Name.split('.')[0]
+            disp_name = disp_box.GetValue()
+            dispersity= disp_box.GetClientData(selection)
+    
+            #disp_model =  GaussianDispersion()
+            disp_model = dispersity()
+            # Get param names to reset the values of the param
+            name1 = param_name + ".width"
+            name2 = param_name + ".npts"
+            name3 = param_name + ".nsigmas"
+            # Check Disp. function whether or not it is 'array'
+            if disp_name.lower() == "array":
+                value2= ""
+                value3= ""
+                value1 = self._set_array_disp(name=name1, disp=disp_model)
+            else:
+                self._del_array_values(name1)
+                #self._reset_array_disp(param_name)
+                self._disp_obj_dict[name1] = disp_model
+                self.model.set_dispersion(param_name, disp_model)
+                self.state._disp_obj_dict[name1]= disp_model
+ 
+                value1= str(format_number(self.model.getParam(name1), True))
+                value2= str(format_number(self.model.getParam(name2)))
+                value3= str(format_number(self.model.getParam(name3)))
+            # Reset fittable polydispersin parameter value
+            for item in self.fittable_param:
+                 if item[1] == name1:
+                    item[2].SetValue(value1) 
+                    item[5].SetValue("")
+                    item[6].SetValue("")
+                    # Disable for array
+                    if disp_name.lower() == "array":
+                        item[0].SetValue(False)
+                        item[0].Disable()
+                        item[2].Disable()
+                        item[5].Disable()
+                        item[6].Disable()
+                    else:
+                        item[0].Enable()
+                        item[2].Enable()
+                        item[5].Enable()
+                        item[6].Enable()                       
+                    break
+            # Reset fixed polydispersion params
+            for item in self.fixed_param:
+                if item[1] == name2:
+                    item[2].SetValue(value2) 
+                    # Disable Npts for array
+                    if disp_name.lower() == "array":
+                        item[2].Disable()
+                    else:
+                        item[2].Enable()
+                if item[1] == name3:
+                    item[2].SetValue(value3) 
+                    # Disable Nsigs for array
+                    if disp_name.lower() == "array":
+                        item[2].Disable()
+                    else:
+                        item[2].Enable()
+                
+            # Make sure the check box updated when all checked
+            if self.cb1.GetValue():
+                self.select_all_param(None)
+
+            # update params
+            self._update_paramv_on_fit() 
+            # draw
+            self._draw_model()
+            self.Refresh()
+        except:
+            # Error msg
+            msg = "Error occurred:"
+            msg += " Could not select the distribution function..."
+            msg += " Please select another distribution function."
+            disp_box.SetBackgroundColour("pink")
+            # Focus on Fit button so that users can see the pinky box
+            self.btFit.SetFocus()
+            wx.PostEvent(self.parent.parent, 
+                         StatusEvent(status=msg, info="error"))
+        
+        
+    def _set_array_disp(self, name=None, disp=None):
+        """
+        Set array dispersion
+        
+        :param name: name of the parameter for the dispersion to be set
+        :param disp: the polydisperion object
+        """
+        # The user wants this parameter to be averaged. 
+        # Pop up the file selection dialog.
+        path = self._selectDlg()
+        # Array data
+        values = []
+        weights = []
+        # If nothing was selected, just return
+        if path is None:
+            self.disp_cb_dict[name].SetValue(False)
+            #self.noDisper_rbox.SetValue(True)
+            return
+        self._default_save_location = os.path.dirname(path)
+
+        basename  = os.path.basename(path)
+        values,weights = self.read_file(path)
+        
+        # If any of the two arrays is empty, notify the user that we won't
+        # proceed
         if len(self.param_toFit)>0:
-            for item in self.fittable_param:
-                if item in self.param_toFit:
-                    self.param_toFit.remove(item)
-            for item in self.orientation_params_disp:
-                if item in self.param_toFit:
-                    self.param_toFit.remove(item)
-        for item in self.model.details.keys():
-            if item in self.model.fixed:
-                del self.model.details [item]                           
-
-        self.fittable_param=[]
-        self.fixed_param=[]
-        self.orientation_params_disp=[]
-        self.sizer4_4.Clear(True) 
-        self._reset_dispersity()
-        ix=0
-        iy=1     
-        disp1 = wx.StaticText(self, -1, 'Array Dispersion')
-        self.sizer4_4.Add(disp1,( iy, ix),(1,1),  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
-        
-        # Look for model parameters to which we can apply an ArrayDispersion model
-        # Add a check box for each parameter.
-        self.disp_cb_dict = {}
-        ix+=1 
-        self.noDisper_rbox = wx.RadioButton(self, -1,"None", (10, 10),style= wx.RB_GROUP)
-        self.Bind(wx.EVT_RADIOBUTTON,self.select_disp_angle , id=self.noDisper_rbox.GetId())
-        #MAC needs SetValue
-        self.noDisper_rbox.SetValue(True)
-        self.sizer4_4.Add(self.noDisper_rbox, (iy, ix),
-                           (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-        
-        for p in self.model.dispersion.keys():
-            if not p in self.model.orientation_params:
-                ix+=1 
-                self.disp_cb_dict[p] = wx.RadioButton(self, -1, p, (10, 10))
-                self.state.disp_cb_dict[p]=  self.disp_cb_dict[p].GetValue()
-                self.Bind(wx.EVT_RADIOBUTTON, self.select_disp_angle, id=self.disp_cb_dict[p].GetId())
-                self.sizer4_4.Add(self.disp_cb_dict[p], (iy, ix), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-        
-        for p in self.model.dispersion.keys():
-            if p in self.model.orientation_params:
-                ix+=1 
-                self.disp_cb_dict[p] = wx.RadioButton(self, -1, p, (10, 10))
-                self.state.disp_cb_dict[p]=  self.disp_cb_dict[p].GetValue()
-                if not (self.enable2D or self.data.__class__.__name__ =="Data2D"):
-                    self.disp_cb_dict[p].Hide()
-                else:
-                    self.disp_cb_dict[p].Show(True)
-                self.Bind(wx.EVT_RADIOBUTTON, self.select_disp_angle, id=self.disp_cb_dict[p].GetId())
-                self.sizer4_4.Add(self.disp_cb_dict[p], (iy, ix), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-
-
-        ix =0
-        iy +=1 
-        self.sizer4_4.Add((20,20),(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)        
-        self.Layout()
-
-        self.state.orientation_params =[]
-        self.state.orientation_params_disp =[]
-        self.state.parameters =[]
-        self.state.fittable_param =[]
-        self.state.fixed_param =[]
-        
-        ## save checkbutton state and txtcrtl values
-        
-        self._copy_parameters_state(self.orientation_params,
-                                     self.state.orientation_params)
-
-        self._copy_parameters_state(self.orientation_params_disp,
-                                     self.state.orientation_params_disp)
-        
-        self._copy_parameters_state(self.parameters, self.state.parameters)
-        self._copy_parameters_state(self.fittable_param, self.state.fittable_param)
-        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
-        
-        
-        ## post state to fit panel
-        event = PageInfoEvent(page = self)
-        wx.PostEvent(self.parent, event)
-   
+            if name in self.param_toFit:
+                self.param_toFit.remove(name)
+
+        # Tell the user that we are about to apply the distribution
+        msg = "Applying loaded %s distribution: %s" % (name, path)
+        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))  
+
+        disp.set_weights(values, weights)
+        self._disp_obj_dict[name] = disp
+        self.model.set_dispersion(name.split('.')[0], disp)
+        self.state._disp_obj_dict[name]= disp
+        self.values[name] = values
+        self.weights[name] = weights
+        # Store the object to make it persist outside the
+        # scope of this method
+        #TODO: refactor model to clean this up?
+        self.state.values = {}
+        self.state.weights = {}
+        self.state.values = copy.deepcopy(self.values)
+        self.state.weights = copy.deepcopy(self.weights)
+
+        # Set the new model as the dispersion object for the 
+        #selected parameter
+        #self.model.set_dispersion(p, disp_model)
+        # Store a reference to the weights in the model object 
+        #so that
+        # it's not lost when we use the model within another thread.
+        #TODO: total hack - fix this
+        self.state.model= self.model.clone()
+        self.model._persistency_dict[name.split('.')[0]] = \
+                                        [values, weights]
+        self.state.model._persistency_dict[name.split('.')[0]] = \
+                                        [values,weights]
+        return basename
+    
+    def _del_array_values(self, name=None):  
+        """
+        Reset array dispersion
+        
+        :param name: name of the parameter for the dispersion to be set 
+        """
+        # Try to delete values and weight of the names array dic if exists
+        try:
+            del self.values[name]
+            del self.weights[name]
+            # delete all other dic
+            del self.state.values[name]
+            del self.state.weights[name]
+            del self.model._persistency_dict[name.split('.')[0]] 
+            del self.state.model._persistency_dict[name.split('.')[0]]
+        except:
+            pass
+                                            
     def _lay_out(self):
         """
@@ -2494,4 +2357,22 @@
             time.sleep(1)
             
+    def _find_polyfunc_selection(self, disp_func = None):
+        """
+        FInd Comboox selection from disp_func 
+        
+        :param disp_function: dispersion distr. function
+        """
+        # List of the poly_model name in the combobox
+        list = ["RectangleDispersion", "ArrayDispersion", 
+                    "LogNormalDispersion", "GaussianDispersion", 
+                    "SchulzDispersion"]
+
+        # Find the selection
+        try:
+            selection = list.index(disp_func.__class__.__name__)
+            return selection
+        except:
+             return 3
+                            
     def on_reset_clicked(self,event):
         """
@@ -2556,4 +2437,36 @@
         #Re draw plot
         self._draw_model()
+        
+    def get_images(self):
+        """
+        Get the images of the plots corresponding this panel for report
+        
+        : return graphs: list of figures
+        : TODO: Move to guiframe
+        """
+        # set list of graphs
+        graphs = []
+        canvases = []
+        # call gui_manager
+        gui_manager = self.parent.parent
+        # loops through the panels [dic]
+        for item1, item2 in gui_manager.panels.iteritems():
+             data_title = self.data.group_id
+             data_name = self.data.name
+            # try to get all plots belonging to this control panel
+             try:
+                 # check titles (main plot) 
+                 # and data_names (model plot[2D], and residuals)
+                 if item2.group_id == data_title or \
+                                item2.window_name.count(data_name):
+                     #panel = gui_manager._mgr.GetPane(item2.window_name)
+                     # append to the list
+                     graphs.append(item2.figure) 
+                     canvases.append(item2.canvas)     
+             except:
+                 # Not for control panels
+                 pass
+        # return the list of graphs
+        return graphs, canvases
 
     def on_model_help_clicked(self,event):
@@ -2562,5 +2475,9 @@
         """
         from help_panel import  HelpWindow
-        
+        import sans.models as models 
+        
+        # Get models help model_function path
+        path = models.get_data_path(media='media')
+        model_path = os.path.join(path,"model_functions.html")
         if self.model == None:
             name = 'FuncHelp'
@@ -2568,5 +2485,5 @@
             name = self.model.origin_name
 
-        frame = HelpWindow(None, -1,  pageToOpen="media/model_functions.html")    
+        frame = HelpWindow(None, -1,  pageToOpen=model_path)    
         frame.Show(True)
         if frame.rhelp.HasAnchor(name):
@@ -2575,4 +2492,187 @@
            msg= "Model does not contains an available description "
            msg +="Please try searching in the Help window"
-           wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))                    
+           wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))      
+    
+    def on_pd_help_clicked(self, event):
+        """
+        Button event for PD help
+        """
+        from help_panel import  HelpWindow
+        import sans.models as models 
+        
+        # Get models help model_function path
+        path = models.get_data_path(media='media')
+        pd_path = os.path.join(path,"pd_help.html")
+
+        frame = HelpWindow(None, -1,  pageToOpen=pd_path)    
+        frame.Show(True)
+        
+    def on_left_down(self, event):
+        """
+        Get key stroke event
+        """
+        # Figuring out key combo: Cmd for copy, Alt for paste
+        if event.CmdDown() and event.ShiftDown():
+            flag = self.get_paste()
+        elif event.CmdDown():
+            flag = self.get_copy()
+        else:
+            event.Skip()
+            return
+        # make event free
+        event.Skip()
+        # messages depending on the flag
+        if flag == None:
+            msg = " Parameter values are copied to the clipboard..."
+            infor = 'warning'
+        elif flag:
+            msg = " Parameter values are pasted from the clipboad..."
+            infor = "warning"
+        else:
+            msg = "Error was occured during pasting the parameter values "
+            msg += "from the clipboard..."
+            infor = "error"
+        # inform msg to wx
+        wx.PostEvent( self.parent.parent, 
+                      StatusEvent(status= msg, info=infor))
+        
+            
+    def get_copy(self): 
+        """
+        Get the string copies of the param names and values in the tap
+        """  
+        content = 'sansview_parameter_values:'
+        # Do it if params exist        
+        if  self.parameters !=[]:
+            
+            # go through the parameters 
+            string = self._get_copy_helper(self.parameters, 
+                                           self.orientation_params)
+            content += string
+            
+            # go through the fittables
+            string = self._get_copy_helper(self.fittable_param, 
+                                           self.orientation_params_disp)
+            content += string
+
+            # go through the fixed params
+            string = self._get_copy_helper(self.fixed_param, 
+                                           self.orientation_params_disp)
+            content += string
                 
+            # go through the str params
+            string = self._get_copy_helper(self.str_parameters, 
+                                           self.orientation_params)
+            content += string
+
+        if wx.TheClipboard.Open():
+            wx.TheClipboard.SetData(wx.TextDataObject(str(content)))
+            data = wx.TextDataObject()
+            success = wx.TheClipboard.GetData(data)
+            text = data.GetText()
+            wx.TheClipboard.Close()
+            
+        return None
+    
+    def _get_copy_helper(self, param, orient_param):
+        """
+        Helping get value and name of the params
+        
+        : param param:  parameters
+        : param orient_param = oritational params
+        : return content: strings [list] [name,value:....]
+        """
+        content = ''
+        # go through the str params
+        for item in param: 
+            # 2D
+            if self.data.__class__.__name__== "Data2D":
+                name = item[1]
+                value = item[2].GetValue()
+            # 1D
+            else:
+                ## for 1D all parameters except orientation
+                if not item[1] in orient_param:
+                    name = item[1]
+                    value = item[2].GetValue()
+            # add to the content
+            content += name + ',' + value + ':'
+            
+        return content
+    
+    def get_paste(self): 
+        """
+        Get the string copies of the param names and values in the tap
+        """  
+        context = {}
+        text = ""
+        
+        # Get text from the clip board        
+        if wx.TheClipboard.Open():
+            if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
+                data = wx.TextDataObject()
+                # get wx dataobject
+                success = wx.TheClipboard.GetData(data)
+                # get text
+                text = data.GetText()
+            # close clipboard
+            wx.TheClipboard.Close()
+            
+        # put the text into dictionary    
+        lines = text.split(':')
+        if lines[0] != 'sansview_parameter_values':
+            return False
+        for line in lines[1:-1]:
+            if len(line) != 0:
+                item =line.split(',')
+                name = item[0]
+                value = item[1]
+                # Transfer the text to content[dictionary]
+                context[name] = value
+        
+        # Do it if params exist        
+        if  self.parameters != []:
+            # go through the parameters  
+            self._get_paste_helper(self.parameters, 
+                                   self.orientation_params, context)
+
+            # go through the fittables
+            self._get_paste_helper(self.fittable_param, 
+                                   self.orientation_params_disp, context)
+
+            # go through the fixed params
+            self._get_paste_helper(self.fixed_param, 
+                                   self.orientation_params_disp, context)
+            
+            # go through the str params
+            self._get_paste_helper(self.str_parameters, 
+                                   self.orientation_params, context)
+            
+        return True
+    
+    def _get_paste_helper(self, param, orient_param, content):
+        """
+        Helping set values of the params
+        
+        : param param:  parameters
+        : param orient_param: oritational params
+        : param content: dictionary [ name, value: name1.value1,...] 
+        """
+        # go through the str params
+        for item in param: 
+            # 2D
+            if self.data.__class__.__name__== "Data2D":
+                name = item[1]
+                if name in content.keys():
+                    item[2].SetValue(content[name])
+            # 1D
+            else:
+                ## for 1D all parameters except orientation
+                if not item[1] in orient_param:
+                    name = item[1]
+                    if name in content.keys():
+                        # Avoid changing combox content which needs special care
+                        if item[2].__class__.__name__ != "ComboBox":
+                            item[2].SetValue(content[name])
+                            
+                
Index: sansview/perspectives/fitting/console.py
===================================================================
--- sansview/perspectives/fitting/console.py	(revision 66ff25070134c0c0c680c52e02ee279ffccc378f)
+++ sansview/perspectives/fitting/console.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -116,11 +116,9 @@
         """
         """
-        #self.elapsed_time = time.time() - self.elapsed_time
-        #msg = " Updating fit ...\n result:\n %s \n"%self.result.__str__()
-        #wx.PostEvent(self.parent, StatusEvent(status=msg, info="info",
-        #                                  type="progress"))
-        #if self.manager is not None:
-        #    self.manager.update_fit(msg=msg, result=self.result)
-        #time.sleep(0.01)
+        self.elapsed_time = time.time() - self.elapsed_time
+        msg = " Updating fit ...\n result:\n %s \n"%self.result.__str__()
+        wx.PostEvent(self.parent, StatusEvent(status=msg, info="info",
+                                              type="progress"))
+        time.sleep(0.01)
         
     def starting_fit(self):
Index: sansview/perspectives/fitting/fit_thread.py
===================================================================
--- sansview/perspectives/fitting/fit_thread.py	(revision 58e0c83b06bd83e2ec0b20ea6725239ec020d0fc)
+++ sansview/perspectives/fitting/fit_thread.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -15,6 +15,6 @@
                  updatefn   = None,
                  yieldtime  = 0.01,
-                 worktime   = 0.01
-                 ):
+                 worktime   = 0.01,
+                 ftol       = None):
         CalcThread.__init__(self,completefn,
                  updatefn,
@@ -27,4 +27,6 @@
         self.starttime = 0
         self.updatefn = updatefn
+        #Relative error desired in the sum of squares.
+        self.ftol = ftol
    
     def isquit(self):
Index: sansview/perspectives/fitting/fitpage.py
===================================================================
--- sansview/perspectives/fitting/fitpage.py	(revision 9466f2d6a8ec770363ff314de3d4768470b1a6f6)
+++ sansview/perspectives/fitting/fitpage.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -41,4 +41,5 @@
         ## draw sizer
         self._fill_datainfo_sizer()
+        self.is_2D = None
         # get smear info from data
         self._get_smear_info()
@@ -48,4 +49,6 @@
         self._set_smear(self.data)
         self.Bind(EVT_CHI2_UPDATE, self.on_complete_chisqr)
+        # bind key event
+        self.Bind(wx.EVT_RIGHT_DOWN, self.on_right_down)
         self._set_bookmark_flag(False)
         self._set_save_flag(False)
@@ -82,62 +85,4 @@
             self.Layout()
             return
-        for item in self.parameters:
-            if self.engine_type =="scipy" :
-                item[5].SetValue("")
-                item[5].Hide()
-                item[6].SetValue("")
-                item[6].Hide()
-                self.text2_min.Hide()
-                self.text2_max.Hide()
-
-            else:
-                item[5].Show(True)
-                item[6].Show(True)
-                self.text2_min.Show(True)
-                self.text2_max.Show(True)
-        for item in self.fittable_param:
-            if item[5]!=None and item[6]!=None and not \
-                item in self.orientation_params_disp:
-                if self.engine_type =="scipy" and \
-                    not item in self.orientation_params:
-                    item[5].SetValue("")
-                    item[5].Hide()
-                    item[6].SetValue("")
-                    item[6].Hide()
-                    self.text2_min.Hide()
-                    self.text2_max.Hide()
-                    self.text_disp_min.Hide()
-                    self.text_disp_max.Hide()
-                else:
-                    item[5].Show(True)
-                    item[6].Show(True)
-                    self.text2_min.Show(True)
-                    self.text2_max.Show(True)
-                    self.text_disp_min.Show(True)
-                    self.text_disp_max.Show(True)
-            
-        for item in self.orientation_params:
-            if item[5]!=None and item[6]!=None:
-                if self.engine_type =="scipy" or \
-                self.data.__class__.__name__ !="Data2D":
-                    item[5].SetValue("")
-                    item[5].Hide()
-                    item[6].SetValue("")
-                    item[6].Hide()
-                else:
-                    item[5].Show(True)
-                    item[6].Show(True)
-                    
-        for item in self.orientation_params_disp:         
-            if item[5]!=None and item[6]!=None:
-                if self.engine_type =="scipy" or \
-                    self.data.__class__.__name__ !="Data2D":
-                    item[5].SetValue("")
-                    item[5].Hide()
-                    item[6].SetValue("")
-                    item[6].Hide()
-                else:
-                    item[5].Show(True)
-                    item[6].Show(True)
         self.Layout()
         self.Refresh()
@@ -163,6 +108,6 @@
         smear_message_new_ssmear  =  "Please enter only the value of interest to customize smearing..."
         smear_message_new_psmear  =  "Please enter both; the dQ will be generated by interpolation..."
-        smear_message_2d_x_title = "<dQx>[1/A]:"
-        smear_message_2d_y_title = "<dQy>[1/A]:"
+        smear_message_2d_x_title = "<dQp>[1/A]:"
+        smear_message_2d_y_title = "<dQs>[1/A]:"        
         smear_message_pinhole_min_title = "dQ_low[1/A]:"
         smear_message_pinhole_max_title = "dQ_high[1/A]:"
@@ -253,8 +198,13 @@
         self.Npts_total  =  BGTextCtrl(self, -1, "-", size=(75,20), style=0)
         self.Npts_total.SetToolTipString(" Total Npts : total number of data points")
+        # Update and Draw button
+        self.draw_button = wx.Button(self,wx.NewId(),'Compute', size=(88,24))
+        self.draw_button.Bind(wx.EVT_BUTTON, self._onDraw,id= self.draw_button.GetId())
+        self.draw_button.SetToolTipString("Compute and Draw.")
+        
         box_description_1= wx.StaticText(self, -1,'    Chi2/Npts')
         box_description_2= wx.StaticText(self, -1,'Fitted Npts')
         box_description_3= wx.StaticText(self, -1,'Data Npts')
-        box_description_4= wx.StaticText(self, -1,' ')
+        #box_description_4= wx.StaticText(self, -1,' ')
         
         
@@ -262,5 +212,5 @@
         sizer_fit.Add(box_description_2,0,0)
         sizer_fit.Add(box_description_3,0,0)       
-        sizer_fit.Add(box_description_4,0,0)
+        sizer_fit.Add(self.draw_button,0,0)
         sizer_fit.Add(self.tcChi,0,0)
         sizer_fit.Add(self.Npts_fit ,0,0)
@@ -281,5 +231,7 @@
         self.smear_message_new_p = wx.StaticText(self, -1, smear_message_new_psmear  , style=wx.ALIGN_LEFT)
         self.smear_description_2d_x     =  wx.StaticText(self, -1, smear_message_2d_x_title  , style=wx.ALIGN_LEFT)
+        self.smear_description_2d_x.SetToolTipString("  dQp(parallel) in q_r direction.")
         self.smear_description_2d_y     =  wx.StaticText(self, -1, smear_message_2d_y_title  , style=wx.ALIGN_LEFT)
+        self.smear_description_2d_y.SetToolTipString(" dQs(perpendicular) in q_phi direction.")
         self.smear_description_pin_min     =  wx.StaticText(self, -1, smear_message_pinhole_min_title  , style=wx.ALIGN_LEFT)
         self.smear_description_pin_max     =  wx.StaticText(self, -1, smear_message_pinhole_max_title  , style=wx.ALIGN_LEFT)
@@ -570,5 +522,5 @@
         sizer.Layout()
         
-    def _set_sizer_dispersion(self, dispersity):
+    def _set_sizer_dispersion(self):
         """
         draw sizer with gaussian dispersity parameters
@@ -588,20 +540,18 @@
         self._reset_dispersity()
         
-        # Create the dispersion objects
-        for item in self.model.dispersion.keys():
-            #disp_model =  GaussianDispersion()
-            disp_model = dispersity()
-            self._disp_obj_dict[item] = disp_model
-            self.model.set_dispersion(item, disp_model)
-            self.state._disp_obj_dict[item]= disp_model
-
-
-        ix=0
-        iy=1
+        ## fill a sizer with the combobox to select dispersion type
+        #sizer_select_dispers = wx.BoxSizer(wx.HORIZONTAL)  
+        model_disp = wx.StaticText(self, -1, 'Function')
+            
+        import sans.models.dispersion_models 
+        self.polydisp= sans.models.dispersion_models.models
+
+        ix = 0
+        iy = 0
         disp = wx.StaticText(self, -1, ' ')
         self.sizer4_4.Add(disp,( iy, ix),(1,1), 
                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
         ix += 1 
-        values = wx.StaticText(self, -1, 'PD[ratio] ')
+        values = wx.StaticText(self, -1, 'PD[ratio]')
         polytext = "Polydispersity (= STD/mean); "
         polytext +=  "the standard deviation over the mean value."
@@ -614,5 +564,4 @@
         self.sizer4_4.Add( self.text_disp_1,(iy, ix),(1,1),\
                             wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
-        self.text_disp_1.Hide()
         
         
@@ -621,5 +570,5 @@
         self.sizer4_4.Add(self.text_disp_min,(iy, ix),(1,1),\
                             wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
-        self.text_disp_min.Hide()
+
         ix +=1 
         self.text_disp_max = wx.StaticText(self, -1, 'Max')
@@ -635,5 +584,5 @@
         self.sizer4_4.Add(npts,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
         ix += 1 
-        nsigmas = wx.StaticText(self, -1, 'Nsigmas')
+        nsigmas = wx.StaticText(self, -1, 'Nsigs')
         nsigmas.SetToolTipString("   Number of sigmas between which the range\n\
          of the distribution function will be used for weighting. \n\
@@ -642,4 +591,7 @@
         self.sizer4_4.Add(nsigmas,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE,
                            0)
+        ix +=1 
+        self.sizer4_4.Add(model_disp,(iy, ix),(1,1),\
+                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
         
         if self.engine_type=="park":
@@ -664,12 +616,12 @@
                         ix = 0
                         cb = wx.CheckBox(self, -1, name0, (10, 10))
-                        cb.SetToolTipString("Check for fitting")
+                        cb.SetToolTipString("Check mark to fit")
                         wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
                         self.sizer4_4.Add( cb,( iy, ix),(1,1),  
                                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 
-                                           15)
+                                           5)
                         ix = 1
                         value= self.model.getParam(name1)
-                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20)
+                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.3,20)
                                                   ,style=wx.TE_PROCESS_ENTER)
                         ctl1.SetLabel('PD[ratio]')
@@ -678,5 +630,5 @@
                         poly_text += " from the mean value."
                         ctl1.SetToolTipString(poly_text)
-                        ctl1.SetValue(str (format_number(value)))
+                        ctl1.SetValue(str (format_number(value, True)))
                         self.sizer4_4.Add(ctl1, (iy,ix),(1,1),wx.EXPAND)
                         ## text to show error sign
@@ -688,5 +640,5 @@
 
                         ix = 3
-                        ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), 
+                        ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH/1.3,20), 
                                            style=0)
                   
@@ -703,5 +655,5 @@
                         self.sizer4_4.Add(ctl3, (iy,ix),(1,1), 
                                           wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-                        ctl3.Hide()
+                       
                 
                         ix = 5
@@ -713,18 +665,14 @@
                                           wx.EXPAND|wx.ADJUST_MINSIZE, 0)
 
-                        ctl4.Hide()
                         
                         if self.engine_type=="park":
                             ctl3.Show(True)
                             ctl4.Show(True)
-                                          
-                        self.fittable_param.append([cb,name1,ctl1,text2,
-                                                    ctl2, ctl3, ctl4,None])                    
-                    
+                                                              
                     elif p=="npts":
                             ix = 6
                             value= self.model.getParam(name2)
                             Tctl = self.ModelTextCtrl(self, -1, 
-                                                      size=(_BOX_WIDTH/2,20),
+                                                       size=(_BOX_WIDTH/2.2,20),
                                                 style=wx.TE_PROCESS_ENTER)
                             
@@ -738,5 +686,5 @@
                             value= self.model.getParam(name3)
                             Tct2 = self.ModelTextCtrl(self, -1, 
-                                                      size=(_BOX_WIDTH/2,20),
+                                                      size=(_BOX_WIDTH/2.2,20),
                                                 style=wx.TE_PROCESS_ENTER)
                             
@@ -744,12 +692,25 @@
                             self.sizer4_4.Add(Tct2, (iy,ix),(1,1),
                                                wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-                            ix +=1
-                            self.sizer4_4.Add((20,20), (iy,ix),(1,1),
-                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+                            #ix +=1
+                            #self.sizer4_4.Add((20,20), (iy,ix),(1,1),
+                            #                   wx.EXPAND|wx.ADJUST_MINSIZE, 0)
                             
-                            self.fixed_param.append([None,name3, Tct2
-                                                     ,None,None,None, 
-                                                     None,None])
-                            
+                            self.fixed_param.append([None, name3, Tct2,
+                                                     None, None, None, 
+                                                     None, None])
+
+
+                ix = 8      
+                disp_box = wx.ComboBox(self, -1,size=(65,-1),
+                                style=wx.CB_READONLY, name = '%s'% name1)
+                for key, value in self.polydisp.iteritems():
+                    name_disp = str(key)
+                    disp_box.Append(name_disp,value)
+                    disp_box.SetStringSelection("gaussian") 
+                wx.EVT_COMBOBOX(disp_box,-1, self._on_disp_func)      
+                self.sizer4_4.Add(disp_box,(iy,ix),(1,1), wx.EXPAND)
+                self.fittable_param.append([cb,name1,ctl1,text2,
+                                                    ctl2, ctl3, ctl4, disp_box])                     
+                           
         ix =0
         iy +=1 
@@ -776,9 +737,9 @@
                         ix = 0
                         cb = wx.CheckBox(self, -1, name0, (10, 10))
-                        cb.SetToolTipString("Check for fitting")
+                        cb.SetToolTipString("Check mark to fit")
                         wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
                         self.sizer4_4.Add( cb,( iy, ix),(1,1),  
                                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 
-                                           15)
+                                           5)
                         if self.data.__class__.__name__ =="Data2D":
                             cb.Show(True)
@@ -787,9 +748,9 @@
                         ix = 1
                         value= self.model.getParam(name1)
-                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,
+                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.3,
                                         20),style=wx.TE_PROCESS_ENTER)
                         poly_tip = "Absolute Sigma for %s." % item
                         ctl1.SetToolTipString(poly_tip)
-                        ctl1.SetValue(str (format_number(value)))
+                        ctl1.SetValue(str (format_number(value, True)))
                         if self.data.__class__.__name__ =="Data2D":
                             if first_orient:
@@ -817,5 +778,5 @@
 
                         ix = 3
-                        ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), 
+                        ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH/1.3,20), 
                                            style=0)
                     
@@ -842,26 +803,14 @@
                                           wx.EXPAND|wx.ADJUST_MINSIZE, 0)
                         ctl4.Hide()
-                        #if self.data.__class__.__name__ =="Data2D":
-                            #ctl4.Enable(True)
-                        #elif ctl4.Shown():
-                            #ctl4.Hide()
                         
-                        if self.engine_type=="park" and \
-                                    self.data.__class__.__name__ =="Data2D":
+                        if self.data.__class__.__name__ =="Data2D":
                             ctl3.Show(True)
                             ctl4.Show(True) 
-                            
-                            
-                            
-                            
-                        self.fittable_param.append([cb,name1,ctl1,text2,
-                                                    ctl2, ctl3, ctl4,None])
-                        self.orientation_params_disp.append([cb,name1,ctl1,
-                                                  text2, ctl2, ctl3, ctl4,None])
+                             
                     elif p=="npts":
                             ix = 6
                             value= self.model.getParam(name2)
                             Tctl = self.ModelTextCtrl(self, -1, 
-                                                      size=(_BOX_WIDTH/2,20),
+                                                     size=(_BOX_WIDTH/2.2, 20),
                                                 style=wx.TE_PROCESS_ENTER)
                             
@@ -882,5 +831,5 @@
                             value= self.model.getParam(name3)
                             Tct2 = self.ModelTextCtrl(self, -1, 
-                                                      size=(_BOX_WIDTH/2,20),
+                                                      size=(_BOX_WIDTH/2.2,20),
                                                 style=wx.TE_PROCESS_ENTER)
                             
@@ -892,5 +841,5 @@
                             self.sizer4_4.Add(Tct2, (iy,ix),(1,1),
                                                wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-                            ix +=1
+
 
                             self.fixed_param.append([None,name3, Tct2
@@ -900,4 +849,25 @@
                                             Tct2 ,None,None, None, None,None])
         
+
+                ix = 8      
+                disp_box = wx.ComboBox(self, -1,size=(65,-1),
+                                style=wx.CB_READONLY, name = '%s'% name1)
+                for key, value in self.polydisp.iteritems():
+                    name_disp = str(key)
+                    disp_box.Append(name_disp,value)
+                    disp_box.SetStringSelection("gaussian") 
+                wx.EVT_COMBOBOX(disp_box,-1, self._on_disp_func)      
+                self.sizer4_4.Add(disp_box,(iy,ix),(1,1), wx.EXPAND)
+                self.fittable_param.append([cb,name1,ctl1,text2,
+                                            ctl2, ctl3, ctl4, disp_box])
+                self.orientation_params_disp.append([cb,name1,ctl1,
+                                            text2, ctl2, ctl3, ctl4, disp_box])
+                       
+                if self.data.__class__.__name__ =="Data2D":
+                    disp_box.Show(True)
+                else:
+                    disp_box.Hide()
+        
+
         self.state.disp_cb_dict = copy.deepcopy(self.disp_cb_dict)  
           
@@ -920,4 +890,23 @@
         self.Layout()
 
+    
+    def _onDraw(self, event):
+        """
+        Update and Draw the model
+        """ 
+        if self.model ==None:
+            msg="Please select a Model first..."
+            wx.MessageBox(msg, 'Info')
+            wx.PostEvent(self.manager.parent, StatusEvent(status=\
+                            "Draw model: %s"%msg))
+            return
+        flag = self._update_paramv_on_fit()         
+        self._onparamEnter_helper()
+        if not flag:
+            msg= "The parameters are invalid"
+            wx.PostEvent(self.parent.parent, StatusEvent(status= msg ))
+            return 
+        
+
     def _onFit(self, event):     
         """
@@ -934,5 +923,5 @@
             wx.MessageBox(msg, 'Info')
             wx.PostEvent(self._manager.parent, StatusEvent(status=\
-                            "Fit: %s" % msg))
+                            "Fit: %s"%msg, type="stop"))
             return
 
@@ -941,10 +930,12 @@
         if not flag:
             msg= "Fitting range or parameters are invalid"
-            wx.PostEvent(self.parent.parent, StatusEvent(status= msg ))
+            wx.PostEvent(self.parent.parent, StatusEvent(status= msg, 
+                                                         type="stop"))
             return 
         
         if len(self.param_toFit) <= 0:
             msg= "Select at least one parameter to fit"
-            wx.PostEvent(self.parent.parent, StatusEvent(status= msg ))
+            wx.PostEvent(self.parent.parent, StatusEvent(status= msg, 
+                                                         type="stop" ))
             return 
       
@@ -1227,10 +1218,7 @@
                     self.set_npts2fit() 
             else:
-                if self.data is not None:
-                    
-                    index_data = ((self.qmin_x <= self.data.x)& \
-                                  (self.data.x <= self.qmax_x))
-                    self.Npts_fit.SetValue(str(len(self.data.x[index_data])))
-
+                index_data = ((self.qmin_x <= self.data.x)& \
+                              (self.data.x <= self.qmax_x))
+                self.Npts_fit.SetValue(str(len(self.data.x[index_data])))
            
         else:
@@ -1698,5 +1686,5 @@
             raise ValueError,"missing parameter to fit"    
       
-    def onsetValues(self,chisqr,p_name, out,cov):
+    def onsetValues(self, chisqr, p_name, out, cov):
         """
         Build the panel from the fit result
@@ -1718,5 +1706,5 @@
         
         #Check if chi2 is finite
-        if chisqr != None or numpy.isfinite(chisqr):
+        if chisqr != None and numpy.isfinite(chisqr):
         #format chi2  
             if self.engine_type == "park":  
@@ -1724,5 +1712,5 @@
                 if npt_fit > 0:
                     chisqr =chisqr/npt_fit    
-            chi2 = format_number(chisqr)    
+            chi2 = format_number(chisqr, True)    
             self.tcChi.SetValue(chi2)    
             self.tcChi.Refresh()    
@@ -1735,12 +1723,8 @@
       
         try:
-            n = self.disp_box.GetCurrentSelection()
-            dispersity= self.disp_box.GetClientData(n)
-            if dispersity !=None and self.enable_disp.GetValue():
-                name= dispersity.__name__
-                if name == "GaussianDispersion":
-                    if hasattr(self,"text_disp_1" ):
-                        if self.text_disp_1 !=None:
-                            self.text_disp_1.Hide()
+            if self.enable_disp.GetValue():
+                if hasattr(self,"text_disp_1" ):
+                    if self.text_disp_1 != None:
+                        self.text_disp_1.Hide()
         except:
             dispersty = None
@@ -1748,5 +1732,5 @@
         #set the panel when fit result are float not list
         if out.__class__== numpy.float64:
-            self.param_toFit[0][2].SetValue(format_number(out))
+            self.param_toFit[0][2].SetValue(format_number(out, True))
             
             if self.param_toFit[0][4].IsShown:
@@ -1755,11 +1739,8 @@
                 self.text2_3.Show(True)
                 try:
-                    if dispersity !=None:
-                        name= dispersity.__name__
-                        if name == "GaussianDispersion" and \
-                        self.enable_disp.GetValue():
-                            if hasattr(self,"text_disp_1" ):
-                                if self.text_disp_1 !=None:
-                                    self.text_disp_1.Show(True)
+                    if self.enable_disp.GetValue():
+                        if hasattr(self,"text_disp_1" ):
+                            if self.text_disp_1 !=None:
+                                self.text_disp_1.Show(True)
                 except:
                     pass
@@ -1771,5 +1752,5 @@
                     self.param_toFit[0][3].Show(True)               
                     self.param_toFit[0][4].Show(True)
-                    self.param_toFit[0][4].SetValue(format_number(cov[0]))
+                    self.param_toFit[0][4].SetValue(format_number(cov[0], True))
                     has_error = True
         else:
@@ -1788,5 +1769,5 @@
                             break        
                     if len(out)<=len(self.param_toFit) and out[ind] !=None:   
-                        val_out = format_number(out[ind])                  
+                        val_out = format_number(out[ind], True)                  
                         item[2].SetValue(val_out)
 
@@ -1795,7 +1776,5 @@
                         try:
                             if dispersity !=None:
-                                name= dispersity.__name__
-                                if name == "GaussianDispersion" and \
-                                                self.enable_disp.GetValue():
+                                if self.enable_disp.GetValue():
                                     if hasattr(self,"text_disp_1" ):
                                         if self.text_disp_1!=None:
@@ -1807,5 +1786,5 @@
                         if cov[ind]!=None :
                             if numpy.isfinite(float(cov[ind])):
-                                val_err = format_number(cov[ind])
+                                val_err = format_number(cov[ind], True)
                                 item[3].Show(True)
                                 item[4].Show(True)
@@ -1821,7 +1800,8 @@
         ## save current state  
         self.save_current_state()          
-        #plot model
-        self._draw_model()   
-        self._lay_out()      
+        #plot model ( when drawing, do not update chisqr value again)
+        self._draw_model(update_chisqr=False)   
+        self._lay_out()   
+        self.Refresh()    
         #PostStatusEvent     
         msg = "Fit completed! "
@@ -2267,5 +2247,5 @@
             else:
                 output = event.output
-            self.tcChi.SetValue(str(format_number(output)))
+            self.tcChi.SetValue(str(format_number(output, True)))
 
             self.state.tcChi = self.tcChi.GetValue()
@@ -2296,4 +2276,10 @@
                         item[0].SetValue(True)
                         self.param_toFit.append(item )
+                        try:
+                            if len(self.values[item[1]]) > 0:
+                                item[0].SetValue(False)
+                        except:
+                            pass
+
                     else:
                         ## for 1D all parameters except orientation
@@ -2301,4 +2287,10 @@
                             item[0].SetValue(True)
                             self.param_toFit.append(item )
+                            try:
+                                if len(self.values[item[1]]) > 0:
+                                    item[0].SetValue(False)
+                            except:
+                                pass
+
             else:
                 for item in self.parameters:
@@ -2476,10 +2468,10 @@
         sizer.Add(self.text2_min,(iy, ix),(1,1),\
                             wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
-        self.text2_min.Hide()
+        #self.text2_min.Hide()
         ix +=1 
         self.text2_max = wx.StaticText(self, -1, 'Max')
         sizer.Add(self.text2_max,(iy, ix),(1,1),\
                             wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
-        self.text2_max.Hide()
+        #self.text2_max.Hide()
         ix += 1
         self.text2_4 = wx.StaticText(self, -1, '[Units]')
@@ -2487,7 +2479,4 @@
                             wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
         self.text2_4.Hide()
-        if self.engine_type=="park":
-            self.text2_max.Show(True)
-            self.text2_min.Show(True)
         
         for item in keys:
@@ -2524,8 +2513,9 @@
                                 style=wx.TE_PROCESS_ENTER, name ='%s'% item)
                         fun_box.SetToolTipString("Hit 'Enter' after typing.")
-                        fun_box.SetValue(format_number(value))
+                        fun_box.SetValue(format_number(value, True))
                     sizer.Add(fun_box, (iy,ix),(1,1), wx.EXPAND)
                     self.str_parameters.append([None,item, fun_box,
-                                                None,None,None,None,None])
+                                                None, None, None, 
+                                                None, None])
 
                     
@@ -2533,5 +2523,5 @@
                     ## add parameters name with checkbox for selecting to fit
                     cb = wx.CheckBox(self, -1, item )              
-                    cb.SetToolTipString(" Check for fitting.")
+                    cb.SetToolTipString(" Check mark to fit.")
                     #cb.SetValue(True)
                     wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
@@ -2546,5 +2536,5 @@
                                         style=wx.TE_PROCESS_ENTER)
                     ctl1.SetToolTipString("Hit 'Enter' after typing.")
-                    ctl1.SetValue(format_number(value))
+                    ctl1.SetValue(format_number(value, True))
                     sizer.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
                     ## text to show error sign
@@ -2555,5 +2545,5 @@
                     text2.Hide() 
                     ix += 1
-                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=0)
+                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH/1.2,20), style=0)
                     sizer.Add(ctl2, (iy,ix),(1,1), 
                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
@@ -2561,5 +2551,5 @@
                     
                     ix += 1
-                    ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
+                    ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.9,20),
                                                style=wx.TE_PROCESS_ENTER,
                                 text_enter_callback = self._onparamRangeEnter)
@@ -2567,18 +2557,12 @@
                     sizer.Add(ctl3, (iy,ix),(1,1), 
                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-                    ctl3.Hide()
             
                     ix += 1
-                    ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
+                    ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.9,20),
                                                style=wx.TE_PROCESS_ENTER,
                                 text_enter_callback = self._onparamRangeEnter)
                     sizer.Add(ctl4, (iy,ix),(1,1), 
-                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-          
-                    ctl4.Hide()
+                              wx.EXPAND|wx.FIXED_MINSIZE, 0)
     
-                    if self.engine_type=="park":
-                        ctl3.Show(True)
-                        ctl4.Show(True)
                     ix +=1
                     # Units
@@ -2632,5 +2616,5 @@
                     cb = wx.CheckBox(self, -1, item )
                     cb.SetValue(False)
-                    cb.SetToolTipString("Check for fitting")
+                    cb.SetToolTipString("Check mark to fit")
                     wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
                     if self.data.__class__.__name__ =="Data2D":
@@ -2647,5 +2631,5 @@
                                         style=wx.TE_PROCESS_ENTER)
                     ctl1.SetToolTipString("Hit 'Enter' after typing.")
-                    ctl1.SetValue(format_number(value))
+                    ctl1.SetValue(format_number(value, True))
                     if self.data.__class__.__name__ =="Data2D":
                         ctl1.Show(True)
@@ -2660,5 +2644,5 @@
                     text2.Hide() 
                     ix += 1
-                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=0)
+                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH/1.2,20), style=0)
                     sizer.Add(ctl2, (iy,ix),(1,1), 
                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
@@ -2667,5 +2651,5 @@
                     
                     ix += 1
-                    ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), 
+                    ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.8,20), 
                                               style=wx.TE_PROCESS_ENTER,
                                 text_enter_callback = self._onparamRangeEnter)
@@ -2676,5 +2660,5 @@
                  
                     ix += 1
-                    ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
+                    ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.8,20),
                                                style=wx.TE_PROCESS_ENTER,
                             text_enter_callback = self._onparamRangeEnter)
@@ -2684,6 +2668,5 @@
                     ctl4.Hide()
                     
-                    if self.engine_type =="park" and \
-                            self.data.__class__.__name__ =="Data2D":                      
+                    if self.data.__class__.__name__ =="Data2D":                      
                         ctl3.Show(True)
                         ctl4.Show(True)
@@ -2727,5 +2710,37 @@
         self.Layout()
         self.Refresh()
-     
+        
+    def on_right_down(self, event):
+        """
+        Get key stroke event
+        """
+        if self.data == None:
+            return
+        # Figuring out key combo: Cmd for copy, Alt for paste
+        if event.AltDown() and event.ShiftDown():
+            self._show_ftol_dialog()
+            flag = True
+        else:
+            flag = False
+        # make event free
+        event.Skip()
+        # messages depending on the flag
+        if not flag:
+            msg = " Could not open ftol dialog;"
+            msg += " Check if the Scipy fit engine is selected in the menubar."
+            infor = 'warning'
+            # inform msg to wx
+            wx.PostEvent( self.parent.parent, 
+                          StatusEvent(status= msg, info=infor))
+
+
+    def _show_ftol_dialog(self):
+        """
+        Dialog to select ftol for Scipy
+        """
+        from ftol_dialog import ChangeFtol
+        panel = ChangeFtol(self)
+        panel.ShowModal()
+        
     def _onModel2D(self, event):
         """
Index: sansview/perspectives/fitting/fitpanel.py
===================================================================
--- sansview/perspectives/fitting/fitpanel.py	(revision 9466f2d6a8ec770363ff314de3d4768470b1a6f6)
+++ sansview/perspectives/fitting/fitpanel.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -61,4 +61,5 @@
         #add default pages
         self.add_default_pages()
+
     
     def _on_engine_change(self, name='scipy'):
@@ -140,9 +141,10 @@
         Add default pages such as a hint page and an empty fit page
         """
+        pass
         #add default page
-        from hint_fitpage import HintFitPage
-        self.hint_page = HintFitPage(self) 
-        self.AddPage(self.hint_page,"Hint")
-        self.hint_page.set_manager(self._manager)
+        #from hint_fitpage import HintFitPage
+        #self.hint_page = HintFitPage(self) 
+        #self.AddPage(self.hint_page,"Hint")
+        #self.hint_page.set_manager(self._manager)
   
     def close_all(self):
Index: sansview/perspectives/fitting/fitting.py
===================================================================
--- sansview/perspectives/fitting/fitting.py	(revision 9466f2d6a8ec770363ff314de3d4768470b1a6f6)
+++ sansview/perspectives/fitting/fitting.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -69,4 +69,5 @@
         self.calc_1D = None
         self.fit_thread_list = {}
+        self.residuals = None
         self.fit_panel = None
         # Start with a good default
@@ -74,4 +75,5 @@
         # the type of optimizer selected, park or scipy
         self.fitter  = None
+        self.fit_panel = None
         #let fit ready
         self.fitproblem_count = None
@@ -82,4 +84,6 @@
         ## Fit engine
         self._fit_engine = 'scipy'
+        ## Relative error desired in the sum of squares (float); scipy only
+        self.ftol=1.49012e-08
         #List of selected data
         self.selected_data_list = []
@@ -132,5 +136,5 @@
         id1 = wx.NewId()
         simul_help = "Simultaneous Fit"
-        self.menu1.Append(id1, '&Simultaneous Page',simul_help)
+        self.menu1.Append(id1, '&Simultaneous Fit',simul_help)
         wx.EVT_MENU(owner, id1, self.on_add_sim_page)
         
@@ -143,5 +147,5 @@
    
         #create  menubar items
-        return [(self.menu1, "Fitting")]
+        return [(self.menu1, "FitEngine")]
                
     def on_add_sim_page(self, event):
@@ -445,5 +449,18 @@
                 param_name=param_names[1]                    
             return model_name,param_name
-        
+   
+    def set_ftol(self, ftol=None):
+        """
+        Set ftol: Relative error desired in the sum of chi squares.  
+        """
+        # check if it is flaot
+        try:
+            f_tol = float(ftol)
+        except:
+            # default
+            f_tol = 1.49012e-08
+            
+        self.ftol = f_tol
+              
     def stop_fit(self, uid):
         """
@@ -492,5 +509,7 @@
                    state=None,
                    toggle_mode_on=False,
-                   qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, qstep=DEFAULT_NPTS):
+                   qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, 
+                   qstep=DEFAULT_NPTS,
+                   update_chisqr=True):
         """
         Draw model.
@@ -505,4 +524,5 @@
         :param qmax:  Range's maximum value to draw model
         :param qstep: number of step to divide the x and y-axis
+        :param update_chisqr: update chisqr [bool]
              
         """
@@ -519,5 +539,6 @@
                                toggle_mode_on=toggle_mode_on,
                                state=state,
-                               qstep=qstep)
+                               qstep=qstep,
+                               update_chisqr=update_chisqr)
         else:     
             ## draw model 2D with no initial data
@@ -531,5 +552,6 @@
                                 state=state,
                                 toggle_mode_on=toggle_mode_on,
-                                qstep=qstep)
+                                qstep=qstep,
+                                update_chisqr=update_chisqr)
             
     def onFit(self):
@@ -598,7 +620,8 @@
             calc_fit = FitThread(handler = handler,
                                     fn=fitter,
-                                   pars=pars,
-                                   page_id=list_page_id,
-                                   completefn=self._single_fit_completed)
+                                    pars=pars,
+                                    page_id=list_page_id,
+                                    completefn=self._single_fit_completed,
+                                    ftol=self.ftol)
         else:
             current_page_id = self.sim_page.uid
@@ -607,5 +630,6 @@
                                     fn=fitter,
                                     page_id=list_page_id,
-                                   completefn= self._simul_fit_completed)
+                                    updatefn=handler.update_fit,
+                                    ftol=self.ftol)
         self.fit_thread_list[current_page_id] = calc_fit
         calc_fit.queue()
@@ -851,7 +875,9 @@
         try:
             if result == None:
-                msg= "Simple Fitting Stop !!!"
-                wx.PostEvent(self.parent, StatusEvent(status=msg,info="warning",
-                                                      type="stop"))
+                msg= "Single Fitting did not converge!!!"
+                wx.PostEvent(self.parent, 
+                             StatusEvent(status=msg, 
+                                         info="warning",
+                                         type="stop"))
                 return
             if not numpy.isfinite(result.fitness) or \
@@ -860,5 +886,7 @@
                 msg = "Single Fitting did not converge!!!"
                 wx.PostEvent(self.parent, 
-                             StatusEvent(status=msg, type="stop"))
+                             StatusEvent(status=msg, 
+                                         info="warning",
+                                         type="stop"))
                 return
             for uid in page_id:
@@ -875,5 +903,10 @@
                                   param_name, result.pvec,result.stderr)
                 cpage._on_fit_complete()
-           
+
+        except ValueError:
+            msg = "Single Fitting did not converge!!!"
+            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
+                                                  type="stop"))
+            return   
         except:
             raise
@@ -899,5 +932,5 @@
             msg = "" 
             if result == None:
-                msg = "Complex Fitting Stop !!!"
+                msg= "Complex Fitting did not converge!!!"
                 wx.PostEvent(self.parent, StatusEvent(status=msg,
                                                       type="stop"))
@@ -933,4 +966,11 @@
                                   small_out,small_cov)
                 cpage._on_fit_complete()
+                
+        except Exception:
+            msg = "Complex Fitting did not converge!!!"
+            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
+                                                  type="stop"))
+            return
+
         except:
             msg = "Simultaneous Fit completed"
@@ -1144,5 +1184,6 @@
   
     def _complete1D(self, x,y, page_id, elapsed,index,model,
-                    toggle_mode_on=False,state=None, data=None):
+                    toggle_mode_on=False,state=None, 
+                    data=None, update_chisqr=True):
         """
         Complete plotting 1D data
@@ -1202,11 +1243,15 @@
             wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
                                             title= str(title)))
-            
-            wx.PostEvent(current_pg,
-                Chi2UpdateEvent(output=self._cal_chisqr(data=data,
+            if update_chisqr:
+                wx.PostEvent(current_pg,
+                             Chi2UpdateEvent(output=self._cal_chisqr(data=data,
                                                         page_id=page_id,
                                                         index=index)))
+            else:
+                self._plot_residuals(page_id, data, index)
+
             msg = "Plot 1D  complete !"
             wx.PostEvent( self.parent, StatusEvent(status=msg, type="stop" ))
+            #self.current_pg.state.theory_data = deepcopy(self.theory_data)
         except:
             raise
@@ -1224,5 +1269,6 @@
   
     def _complete2D(self, image, data, model, page_id,  elapsed, index, qmin,
-                     qmax, toggle_mode_on=False,state=None,qstep=DEFAULT_NPTS):
+                     qmax, toggle_mode_on=False,state=None,qstep=DEFAULT_NPTS, 
+                     update_chisqr=True):
         """
         Complete get the result of modelthread and create model 2D
@@ -1284,8 +1330,12 @@
                                                title=title))
         # Chisqr in fitpage
-        wx.PostEvent(current_pg,
-            Chi2UpdateEvent(output=self._cal_chisqr(data=data,
+        if update_chisqr:
+            wx.PostEvent(current_pg,
+                         Chi2UpdateEvent(output=\
+                                    self._cal_chisqr(data=data,
                                                      page_id=page_id,
                                                      index=index)))
+        else:
+            self._plot_residuals(page_id, data, index)
         msg = "Plot 2D complete !"
         wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
@@ -1296,5 +1346,6 @@
                       toggle_mode_on=False,
                       qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX,
-                       qstep=DEFAULT_NPTS):
+                      qstep=DEFAULT_NPTS,
+                      update_chisqr=True):
         """
         draw model in 2D
@@ -1346,6 +1397,8 @@
                                     toggle_mode_on=toggle_mode_on,
                                     state=state,
-                                    completefn=self._complete2D)#,
-                                    #updatefn=self._update2D)
+                                    completefn=self._complete2D,
+                                    #updatefn= self._update2D,
+                                    update_chisqr=update_chisqr)
+
             self.calc_2D.queue()
 
@@ -1360,5 +1413,6 @@
                 state=None,
                 toggle_mode_on=False,
-                qstep=DEFAULT_NPTS, enable1D=True):
+                qstep=DEFAULT_NPTS, update_chisqr=True, 
+                enable1D=True):
         """
         Draw model 1D from loaded data1D
@@ -1378,8 +1432,9 @@
                 return
             x = data.x
-            if qmin == DEFAULT_QMIN :
-                qmin = min(data.x)
-            if qmax == DEFAULT_QMAX:
-                qmax = max(data.x) 
+            if qmin == None :
+                qmin == DEFAULT_QMIN
+
+            if qmax == None:
+                qmax == DEFAULT_QMAX 
         if not enable1D:
             return 
@@ -1398,6 +1453,8 @@
                                   state=state,
                                   toggle_mode_on=toggle_mode_on,
-                                  completefn=self._complete1D)#,
-                                  #updatefn=self._update1D)
+                                  completefn=self._complete1D,
+                                  #updatefn = self._update1D,
+                                  update_chisqr=update_chisqr)
+
             self.calc_1D.queue()
 
@@ -1419,9 +1476,10 @@
         
         # Get data: data I, theory I, and data dI in order
-        if data.__class__.__name__ =="Data2D":
+        if data.__class__.__name__ == "Data2D":
             if index == None: 
                 index = numpy.ones(len(data.data),ntype=bool)
             # get rid of zero error points
-            index = index & (data.err_data != 0)  
+            index = index & (data.err_data != 0 )  
+            index = index & (numpy.isfinite(data.data)) 
             fn = data.data[index] 
             theory_data = self.page_finder[page_id].get_theory_data()
@@ -1430,5 +1488,5 @@
         else:
             # 1 d theory from model_thread is only in the range of index
-            if index == None:
+            if index == None: 
                 index = numpy.ones(len(data.y), ntype=bool)
             if data.dy == None or data.dy == []:
@@ -1437,5 +1495,5 @@
                 ## Set consitently w/AbstractFitengine:
                 # But this should be corrected later.
-                dy = data.dy
+                dy = deepcopy(data.dy)
                 dy[dy==0] = 1  
             fn = data.y[index] 
@@ -1444,11 +1502,99 @@
             en = dy[index]
         # residual
-        res = (fn - gn)/en
+        res = (fn - gn) / en
+        residuals = res[numpy.isfinite(res)]
         # get chisqr only w/finite
-        val = res[numpy.isfinite(res)]*res[numpy.isfinite(res)]
-        chisqr = numpy.average(val)
+        chisqr = numpy.average(residuals * residuals)
+        
+        self._plot_residuals(page_id, data, index)
         return chisqr
     
-    
+
+        
+    def _plot_residuals(self, page_id, data=None, index=None): 
+        """
+        Plot the residuals
+        
+        :param data: data
+        :param index: index array (bool) 
+        : Note: this is different from the residuals in cal_chisqr()
+        """
+        if data == None: 
+            return 
+        
+        # Get data: data I, theory I, and data dI in order
+        if data.__class__.__name__ == "Data2D":
+            # build residuals
+            #print data
+            residuals = Data2D()
+            #residuals.copy_from_datainfo(data)
+            # Not for trunk the line below, instead use the line above
+            data.clone_without_data(len(data.data), residuals)
+            residuals.data = None
+            fn = data.data#[index] 
+            theory_data = self.page_finder[page_id].get_theory_data()
+            gn = theory_data.data#[index]
+            en = data.err_data#[index]
+            residuals.data = (fn - gn) / en 
+            residuals.qx_data = data.qx_data#[index]
+            residuals.qy_data = data.qy_data #[index]
+            residuals.q_data = data.q_data#[index]
+            residuals.err_data = numpy.ones(len(residuals.data))#[index]
+            residuals.xmin = min(residuals.qx_data)
+            residuals.xmax = max(residuals.qx_data)
+            residuals.ymin = min(residuals.qy_data)
+            residuals.ymax = max(residuals.qy_data)
+            residuals.q_data = data.q_data#[index]
+            residuals.mask = data.mask
+            residuals.scale = 'linear'
+            #print "print data",residuals
+            # check the lengths
+            if len(residuals.data) != len(residuals.q_data):
+                return
+
+        else:
+            # 1 d theory from model_thread is only in the range of index
+            if data.dy == None or data.dy == []:
+                dy = numpy.ones(len(data.y))
+            else:
+                ## Set consitently w/AbstractFitengine: 
+                ## But this should be corrected later.
+                dy = deepcopy(data.dy)
+                dy[dy==0] = 1  
+            fn = data.y[index] 
+            theory_data = self.page_finder[page_id].get_theory_data()
+            gn = theory_data.y
+            en = dy[index]
+            # build residuals
+            residuals = Data1D()
+            residuals.y = (fn - gn) / en
+            residuals.x = data.x[index]
+            residuals.dy = numpy.ones(len(residuals.y))
+            residuals.dx = None
+            residuals.dxl = None
+            residuals.dxw = None
+            residuals.ytransform = 'y'
+            # For latter scale changes 
+            residuals.xaxis('\\rm{Q} ', 'A^{-1}')
+            residuals.yaxis('\\rm{Residuals} ', 'normalized')
+            
+        new_plot = residuals
+        if data.id == None:
+            data.id = data.name
+        name  = data.id
+        new_plot.name = "Residuals for " + str(data.name)
+        ## allow to highlight data when plotted
+        new_plot.interactive = True
+        ## when 2 data have the same id override the 1 st plotted
+        new_plot.id = new_plot.name#name + " residuals"
+        ##group_id specify on which panel to plot this data
+        new_plot.group_id = new_plot.id
+        #new_plot.is_data = True
+        ##post data to plot
+        title = new_plot.name 
+        
+        # plot data
+        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))   
+   
 #def profile(fn, *args, **kw):
 #    import cProfile, pstats, os
Index: sansview/perspectives/fitting/ftol_dialog.py
===================================================================
--- sansview/perspectives/fitting/ftol_dialog.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
+++ sansview/perspectives/fitting/ftol_dialog.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -0,0 +1,122 @@
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation. 
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+import wx
+import sys
+from sans.guicomm.events import StatusEvent  
+# default ftol
+F_TOL = 1.49012e-08 
+
+if sys.platform.count("win32") > 0:
+    PANEL_WIDTH = 270 
+    PANEL_HEIGHT = 250
+    FONT_VARIANT = 0
+else:
+    PANEL_WIDTH = 285
+    PANEL_HEIGHT = 255
+    FONT_VARIANT = 1
+    
+"""
+Dialog to set ftol for Scipy
+
+    ftol(float): Relative error desired in the sum of squares.
+"""
+class ChangeFtol(wx.Dialog):
+    """
+    Dialog to select ftol
+    """
+    def __init__(self, parent, id=-1, title="FTolerance"):
+        wx.Dialog.__init__(self, parent, id, title, 
+                           size=(PANEL_WIDTH, PANEL_HEIGHT))
+        # parent
+        self.parent = parent
+        # default ftol
+        self.ftol = F_TOL
+                # font size 
+        self.SetWindowVariant(variant=FONT_VARIANT)
+        # build layout
+        panel = wx.Panel(self, -1)
+        vbox = wx.BoxSizer(wx.VERTICAL)
+        wx.StaticBox(panel, -1, 'ftol selection (Scipy)', (5, 5),
+                      (PANEL_WIDTH*0.9, PANEL_HEIGHT*0.65))
+        default_bt = wx.RadioButton(panel, -1, 'Default', (15, 30), 
+                                    style=wx.RB_GROUP)
+        default_bt.Bind(wx.EVT_RADIOBUTTON, self.OnFtolSelection)
+        default_bt.SetValue(True)
+        high_bt = wx.RadioButton(panel, -1, '1e-06', (15, 55))
+        high_bt.SetValue(False)
+        high_bt.Bind(wx.EVT_RADIOBUTTON, self.OnFtolSelection)
+        mid_bt = wx.RadioButton(panel, -1, '1e-05', (15, 80))
+        mid_bt.SetValue(False)
+        mid_bt.Bind(wx.EVT_RADIOBUTTON, self.OnFtolSelection)
+        low_bt = wx.RadioButton(panel, -1, '1e-04', (15, 105))
+        low_bt.SetValue(False)
+        low_bt.Bind(wx.EVT_RADIOBUTTON, self.OnFtolSelection)
+        self.custom_bt = wx.RadioButton(panel, -1, 'Custom', (15, 130))
+        self.custom_bt.SetValue(False)
+        self.custom_bt.Bind(wx.EVT_RADIOBUTTON, self.OnFtolSelection)
+        self.custombox = wx.TextCtrl(panel, -1, '', (95, 130))
+        self.custombox.Disable()
+        hbox = wx.BoxSizer(wx.HORIZONTAL)
+        okButton = wx.Button(self, -1, 'Set', size=(70, 30))
+        hbox.Add(okButton, 1, wx.RIGHT, 5)
+        okButton.Bind(wx.EVT_BUTTON, self.OnClose)
+        vbox.Add(panel)
+        vbox.Add(hbox, 1, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
+        # set sizer
+        self.SetSizer(vbox)
+ 
+    def OnFtolSelection(self, event=None):
+        """
+        Changes the ftol on selection of the radio button
+        """
+        event.Skip()
+        # event object and selection
+        button = event.GetEventObject()
+        selection = button.GetLabel()
+        # get float value 
+        if selection == 'Default':
+            ftol = F_TOL   
+            self.custombox.Disable()     
+        elif selection == 'Custom':
+            ftol = F_TOL 
+            self.custombox.Enable(True)
+        else:
+            ftol =  float(selection)
+            self.custombox.Disable()
+        self.ftol = ftol    
+        
+
+    def OnClose(self, event):
+        """
+        Close event
+        """
+        # clear event
+        event.Skip()
+        flag = True
+        # I case of the custom ftol
+        if self.custom_bt.GetValue():
+            try:
+                ftol = float(self.custombox.GetValue())
+                self.ftol = ftol
+            except:
+                flag = False
+        if flag:
+            # set ftol in fitting
+            self.parent.manager.set_ftol(self.ftol) 
+            msg = "The ftol (Scipy) is set to %s." % self.ftol
+        else:
+           msg = "Error in the selection... No changes in ftol."
+        # post event for info
+        wx.PostEvent( self.parent.manager.parent, 
+                      StatusEvent(status= msg, info='warning')) 
+    
+        self.Destroy()
+
Index: sansview/perspectives/fitting/model_thread.py
===================================================================
--- sansview/perspectives/fitting/model_thread.py	(revision e4957fb9ebb34757ae5ada73fadbe9135c02ee27)
+++ sansview/perspectives/fitting/model_thread.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -20,4 +20,5 @@
                  completefn = None,
                  updatefn   = None,
+                 update_chisqr=True,
                  yieldtime  = 0.01,
                  worktime   = 0.01
@@ -40,4 +41,5 @@
         self.smearer = smearer#(data=self.data,model=self.model)
         self.starttime = 0  
+        self.update_chisqr = update_chisqr
         
     def compute(self):
@@ -130,5 +132,6 @@
                        qmin=self.qmin,
                        qmax=self.qmax,
-                       qstep=self.qstep)
+                       qstep=self.qstep,
+                       update_chisqr = self.update_chisqr )
         
 
@@ -146,4 +149,5 @@
                  state=None,
                  completefn = None,
+                 update_chisqr=True,
                  updatefn   = None,
                  yieldtime  = 0.01,
@@ -166,4 +170,5 @@
         self.smearer = smearer
         self.starttime = 0
+        self.update_chisqr = update_chisqr
         
     def compute(self):
@@ -190,5 +195,6 @@
                       toggle_mode_on=self.toggle_mode_on,
                       elapsed=elapsed,index=index, model=self.model,
-                                        data=self.data)
+                      data=self.data, 
+                      update_chisqr = self.update_chisqr )
         
     def results(self):
Index: sansview/perspectives/fitting/pagestate.py
===================================================================
--- sansview/perspectives/fitting/pagestate.py	(revision dce84c0c2b9c94923bffb588d0a32609d9eefbc6)
+++ sansview/perspectives/fitting/pagestate.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -47,5 +47,4 @@
                       ["formfactorcombobox", "formfactorcombobox", "float"],
                       ["structurecombobox", "structurecombobox", "float"],
-                      ["disp_box", "disp_box", "float"],
                       ["enable_smearer","enable_smearer","bool"],
                       ["disable_smearer","disable_smearer","bool"],
@@ -65,4 +64,6 @@
 list_of_model_attributes = [["values", "values"],
                             ["weights", "weights"]]
+
+list_of_obj_dic =  [["disp_obj_dict", "_disp_obj_dict", "string"]]
 
 list_of_state_parameters = [["parameters", "parameters"] , 
@@ -139,4 +140,10 @@
         #Data used for fitting 
         self.data = data
+        # model data
+        self.theory_data = None
+        #Is 2D
+        self.is_2D = False
+        self.images = None
+        
         #save additional information on data that dataloader.reader does not read
         self.is_data = None
@@ -196,8 +203,9 @@
         if self.model is not None:
             self.disp_list = self.model.getDispParamList()
-        self._disp_obj_dict = {}
+
         self.disp_cb_dict = {}
-        self.values = []
-        self.weights = []
+        self.values = {}
+        self.weights = {}
+
                     
         #contains link between a model and selected parameters to fit 
@@ -289,7 +297,10 @@
             for k , v in self.disp_cb_dict.iteritems():
                 obj.disp_cb_dict[k]= v
-                
-        obj.values = copy.deepcopy(self.values)
-        obj.weights = copy.deepcopy(self.weights)
+        if len(self.values)>0: 
+            for k , v in self.values.iteritems():       
+                obj.values[k] = v
+        if len(self.weights)>0: 
+            for k , v in self.weights.iteritems():       
+                obj.weights[k] = v
         obj.enable_smearer = copy.deepcopy(self.enable_smearer)
         obj.disable_smearer = copy.deepcopy(self.disable_smearer)
@@ -337,5 +348,5 @@
         rep = "\nState name: %s\n"%self.file
         t = time.localtime(self.timestamp)
-        time_str = time.strftime("%b %d %H:%M", t)
+        time_str = time.strftime("%b %d %H;%M of %Y", t)
         rep += "State created on : %s\n"%time_str
         rep += "State form factor combobox selection: %s\n"%self.formfactorcombobox
@@ -368,17 +379,174 @@
         
         rep += "model  : %s\n\n"% str(self.model)
-        rep += "number parameters(self.parameters): %s\n"%len(self.parameters)
-        rep = self._repr_helper( list=self.parameters, rep=rep)
-        rep += "number str_parameters(self.str_parameters): %s\n"%len(self.str_parameters)
-        rep = self._repr_helper( list=self.str_parameters, rep=rep)
-        rep += "number orientation parameters"
-        rep += "(self.orientation_params): %s\n"%len(self.orientation_params)
-        rep = self._repr_helper( list=self.orientation_params, rep=rep)
-        rep += "number dispersity parameters"
-        rep += "(self.orientation_params_disp): %s\n"%len(self.orientation_params_disp)
-        rep = self._repr_helper( list=self.orientation_params_disp, rep=rep)
+        temp_parameters = []
+        temp_fittable_param = []
+        if self.data.__class__.__name__ == "Data2D":
+            self.is_2D = True
+        else:
+            self.is_2D = False
+        if self.data is not None:
+            if not self.is_2D:
+                for item in self.parameters:
+                    if not item in self.orientation_params:
+                        temp_parameters.append(item)
+                for item in self.fittable_param:
+                    if not item in self.orientation_params_disp:
+                        temp_fittable_param.append(item)
+            else:
+                temp_parameters = self.parameters
+                temp_fittable_param = self.fittable_param
+                
+            rep += "number parameters(self.parameters): %s\n"%len(temp_parameters)
+            rep = self._repr_helper( list=temp_parameters, rep=rep)
+            rep += "number str_parameters(self.str_parameters): %s\n"%len(self.str_parameters)
+            rep = self._repr_helper( list=self.str_parameters, rep=rep) 
+            rep += "number fittable_param(self.fittable_param): %s\n"%len(temp_fittable_param)
+            rep = self._repr_helper( list=temp_fittable_param, rep=rep) 
+            """ 
+            if is_2D:
+                rep += "number orientation parameters"
+                rep += "(self.orientation_params): %s\n"%len(self.orientation_params)
+                rep = self._repr_helper( list=self.orientation_params, rep=rep)
+                rep += "number dispersity parameters"
+                rep += "(self.orientation_params_disp): %s\n"%len(self.orientation_params_disp)
+                rep = self._repr_helper( list=self.orientation_params_disp, rep=rep)
+            """
         
         return rep
-   
+
+
+    def set_report_string(self):
+        """
+        Get the values (strings) from __str__ for report 
+        """
+        # Dictionary of teh report strings
+        repo_time = ""
+        model_name = ""
+        title = ""
+        title_name = ""
+        file_name = ""
+        param_string = ""
+        paramval_string = ""
+        chi2_string = ""
+        q_range = ""
+        strings = self.__repr__()
+        lines = strings.split('\n')
+
+        # get all string values from __str__()
+        for line in lines:
+            value = ""
+            content = line.split(":")
+            name = content[0]
+            try:
+                value = content[1]
+            except:
+                pass
+            if name.count("State created on"):
+                repo_time = "Created on " + value
+            if name.count("parameter name"):
+                val_name = value.split(".")
+                if len(val_name) > 1:
+                    if val_name[1].count("width"):
+                        param_string += value + ','
+                    else:
+                        continue
+                else:
+                    param_string += value + ','
+            if name == "value":
+                param_string += value + ','
+            if name == "error value":
+                param_string += value + ','
+            if name == "parameter unit":
+                param_string += value + ':' 
+            if name == "Value of Chisqr ":
+                chi2 = ("Chi2/Npts = " + value)
+                chi2_string = CENTRE % chi2
+            if name == "Title":
+                if len(value.strip()) == 0:
+                    continue
+                title = value + " [" + repo_time + "]"
+                title_name = HEADER % title
+            if name == "data ":
+                try:
+                    file = ("File name:" + content[2])
+                    file_name = CENTRE % file
+                    if len(title) == 0:
+                        title = content[2] + " [" + repo_time + "]"
+                        title_name = HEADER % title
+                except:
+                    pass
+            if name == "Plotting Range":
+                try:
+                    q_range = content[1] + " = " + content[2] \
+                            + " = " + content[3].split(",")[0]
+                    q_name = ("Q Range:    " + q_range)
+                    q_range = CENTRE % q_name
+                except:
+                    pass
+        paramval = ""
+        for lines in param_string.split(":"): 
+            line = lines.split(",")
+            if len(lines) > 0: 
+                param = line[0] 
+                param += " = " + line[1]
+                if len(line[2].split()) > 0 and not line[2].count("None"):
+                    param += " +- " + line[2]
+                if len(line[3].split()) > 0 and not line[3].count("None"):
+                    param += " " + line[3]
+                if not paramval.count(param):
+                    paramval +=  param + "\n"
+                    paramval_string += CENTRE % param + "\n"
+        
+        html_string = title_name + "\n" + file_name + \
+                                   "\n" + q_range + \
+                                   "\n" + chi2_string + \
+                                   "\n" + ELINE + \
+                                   "\n" + paramval_string + \
+                                   "\n" + ELINE + \
+                                   "\n" + FEET_1 % title + \
+                                   "\n" + FEET_2 
+                            
+        text_string = "\n\n\n" + title + "\n\n" + file + \
+                              "\n" + q_name + \
+                              "\n" + chi2 + \
+                              "\n\n" + paramval 
+                                           
+        return html_string, text_string, title
+    
+    def report(self, figs=None, canvases=None):
+        """
+        Invoke report dialog panel
+        
+        : param figs: list of pylab figures [list]
+        """
+        from report_dialog import ReportDialog
+        # get the strings for report
+        html_str, text_str, title = self.set_report_string()
+        # Allow 2 figures to append
+        if len(figs) == 1:
+            add_str = FEET_3 
+        elif len(figs) == 2:
+            add_str = ELINE 
+            add_str += FEET_2 % ("%s") 
+            add_str += ELINE 
+            add_str += FEET_3 
+        elif len(figs) > 2:
+            add_str = ELINE 
+            add_str += FEET_2 % ("%s") 
+            add_str += ELINE 
+            add_str += FEET_2 % ("%s") 
+            add_str += ELINE 
+            add_str += FEET_3 
+        else:
+            add_str = ""
+        # final report html strings
+        report_str = html_str % ("%s") + add_str
+
+        # make plot image
+        images = self.set_plot_state(figs, canvases)
+        report_list = [report_str, text_str, images ]
+        dialog = ReportDialog(report_list, None, -1, "")
+        dialog.ShowModal()
+          
     def _toXML_helper(self, list, element, newdoc):
         """
@@ -463,24 +631,47 @@
         for item in list_of_data_attributes:
             element = newdoc.createElement(item[0])
-            exec "element.setAttribute(item[0], str(self.%s))"%(item[1])
+            exec "element.setAttribute(item[0], str(self.%s))" % (item[1])
             inputs.appendChild(element)   
         
         for item in list_of_state_attributes:
             element = newdoc.createElement(item[0])
-            exec "element.setAttribute(item[0], str(self.%s))"%(item[1])
+            exec "element.setAttribute(item[0], str(self.%s))" % (item[1])
             inputs.appendChild(element)
-            
+
+        # For self.values ={ disp_param_name: [vals,...],...}   
+        # and for self.weights ={ disp_param_name: [weights,...],...}              
         for item in list_of_model_attributes:
             element = newdoc.createElement(item[0])
-            exec "list = self.%s"%item[1]
-            for value in list:
-                exec "element.appendChild(newdoc.createTextNode(str(%s)))"%value
+            exec "list = self.%s" % item[1]
+            for key, value in list.iteritems():
+                sub_element = newdoc.createElement(key)
+                sub_element.setAttribute('name', str(key))
+                for val in value:
+                    com = "sub_element.appendChild"
+                    com += "(newdoc.createTextNode(str(%s)))"
+                    exec com % val
+                   
+                element.appendChild(sub_element) 
             inputs.appendChild(element)
-            
+        
+        # Create doc for the dictionary of self._disp_obj_dic
+        for item in list_of_obj_dic:
+             element = newdoc.createElement(item[0])
+             exec "list = self.%s" % item[1]
+             for key, val in list.iteritems():
+                 value = repr(val)
+                 sub_element = newdoc.createElement(key)
+                 sub_element.setAttribute('name', str(key))
+                 sub_element.setAttribute('value', str(value))
+                 element.appendChild(sub_element) 
+             inputs.appendChild(element)    
+                 
         for item in list_of_state_parameters:
             element = newdoc.createElement(item[0])
-            exec "self._toXML_helper(list=self.%s, element=element, newdoc=newdoc)"%item[1]                       
+            com = "self._toXML_helper(list=self.%s,"
+            com += " element=element, newdoc=newdoc)"
+            exec com % item[1]                       
             inputs.appendChild(element)
-       
+               
         # Save the file
         if doc is None:
@@ -537,6 +728,8 @@
             except:
                 unit = None
-            list.append([selected_to_fit, name, value, "+/-",[error_displayed, error_value],
-                         [minimum_displayed,minimum_value],[maximum_displayed,maximum_value], unit])
+            list.append([selected_to_fit, name, value, "+/-",
+                         [error_displayed, error_value],
+                         [minimum_displayed,minimum_value],
+                         [maximum_displayed,maximum_value], unit])
        
     def fromXML(self, file=None, node=None):
@@ -575,32 +768,107 @@
                 node = get_content('ns:%s'%item[0], entry)
                 try:
-                    exec "self.%s = parse_entry_helper(node, item)"%item[0]
+                    exec "self.%s = parse_entry_helper(node, item)" % item[0]
                     
                 except:
                     raise
-            
+
             if entry is not None:
                 
                 for item in list_of_state_attributes:
-                    node = get_content('ns:%s'%item[0], entry)
+                    node = get_content('ns:%s' % item[0], entry)
                     try:
-                        exec "self.%s = parse_entry_helper(node, item)"%str(item[0])
+                        exec "self.%s = parse_entry_helper(node, item)" % \
+                                                                str(item[0])
                     except:
                         raise
                     
+                for item in list_of_state_parameters:
+                    node = get_content("ns:%s" % item[0], entry)
+                    exec "self._fromXML_helper(node=node, list=self.%s)" % \
+                                                                    item[1]
+                
+                # Recover _disp_obj_dict from xml file   
+                self._disp_obj_dict = {}    
+                for item in list_of_obj_dic:
+                    # Get node
+                    node = get_content("ns:%s" % item[0], entry)
+                    for attr in node:
+                        name = attr.get('name')
+                        val  = attr.get('value')
+                        value = val.split(" instance")[0]
+                        disp_name = value.split("<")[1]
+                        try:
+                            # Try to recover disp_model object from strings
+                            com  = "from sans.models.dispersion_models "
+                            com += "import %s as disp"
+                            com_name = disp_name.split(".")[3]
+                            exec com % com_name
+                            disp_model = disp()
+                            exec "self.%s['%s'] = com_name" % (item[1], name)
+                        except:
+                            pass
+                        
+                # get self.values and self.weights dic. if exists    
                 for item in list_of_model_attributes:
-                    node = get_content("ns:%s"%item[0], entry)
+                    node = get_content("ns:%s" % item[0], entry)
+                    dic = {}
                     list = []
-                    for value in node:
-                        try:
-                            list.append(float(value)) 
-                        except:
-                            list.append(None)
-                    exec "self.%s = list"%item[1]
-                
-                for item in list_of_state_parameters:
-                    node = get_content("ns:%s"%item[0], entry)
-                    exec "self._fromXML_helper(node=node, list=self.%s)"%item[1]
-                   
+                    for par in node:
+                        name = par.get('name')
+                        values = par.text.split('\n')
+                        # Get lines only with numbers
+                        for line in values:
+                            try:
+                                val= float(line)
+                                list.append(val) 
+                            except:
+                                # pass if line is empty (it happens)
+                                pass
+                    dic[name] = numpy.array(list)
+                    exec "self.%s = dic" % item[1]
+                    
+    def set_plot_state(self, figs, canvases):
+        """
+        Build image state that wx.html understand
+        by plotting, putting it into wx.FileSystem image object
+
+        """
+        images = []
+        # some imports
+        import wx
+
+        # Reset memory
+        self.imgRAM = None
+        wx.MemoryFSHandler()
+        
+        # For no figures in the list, prepare empty plot
+        if figs == None or len(figs) == 0:
+            figs = [None]
+            
+        # Loop over the list of figures   
+        # use wx.MemoryFSHandler
+        self.imgRAM = wx.MemoryFSHandler() 
+        for fig in figs:
+            if figs != None:
+                #fig.set_facecolor('w')
+                ind = figs.index(fig)
+                canvas = canvases[ind]
+                
+            #bmp = wx.BitmapDataObject()
+            #bmp.SetBitmap(canvas.bitmap)
+            #store the image in wx.FileSystem Object 
+            wx.FileSystem.AddHandler(wx.MemoryFSHandler())
+            
+            # index of the fig
+            ind = figs.index(fig)
+            
+            #AddFile, image can be retrieved with 'memory:filename'
+            self.imgRAM.AddFile('img_fit%s.png' % ind , 
+                                canvas.bitmap, wx.BITMAP_TYPE_PNG)
+            
+            #append figs
+            images.append(fig)
+            
+        return images                   
 
 class Reader(CansasReader):
@@ -1233,5 +1501,46 @@
             
         return doc 
-  
+
+    
+# Simple html report templet  
+HEADER = "<html>\n"
+HEADER += "<head>\n"
+HEADER += "<meta http-equiv=Content-Type content='text/html; "
+HEADER += "charset=windows-1252'> \n"
+HEADER += "<meta name=Generator >\n"
+HEADER += "</head>\n"
+HEADER += "<body lang=EN-US>\n"
+HEADER += "<div class=WordSection1>\n"
+HEADER += "<p class=MsoNormal><b><span ><center>"
+HEADER += "%s</center></span></center></b></p>"
+HEADER += "<p class=MsoNormal>&nbsp;</p>"
+PARA = "<p class=MsoNormal> %s \n"
+PARA += "</p>"
+CENTRE = "<p class=MsoNormal><center> %s \n"
+CENTRE += "</center></p>"
+FEET_1 = \
+"""
+<p class=MsoNormal>&nbsp;</p>
+<p class=MsoNormal><b><span ><center> Graph</span></center></b></p> 
+<p class=MsoNormal>&nbsp;</p> 
+<center> 
+<br>Model Computation<br> 
+<br>Data: "%s"<br> 
+"""
+FEET_2 = \
+"""
+<img src="%s" > 
+</img>
+"""
+FEET_3 = \
+"""
+</center> 
+</div>
+</body>
+</html>
+"""
+ELINE = "<p class=MsoNormal>&nbsp;</p>"
+
+ 
 if __name__ == "__main__":
     state = PageState(parent=None)
Index: sansview/perspectives/fitting/report_dialog.py
===================================================================
--- sansview/perspectives/fitting/report_dialog.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
+++ sansview/perspectives/fitting/report_dialog.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -0,0 +1,243 @@
+
+################################################################################
+#This software was developed by the University of Tennessee as part of the
+#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+#project funded by the US National Science Foundation. 
+#
+#See the license text in license.txt
+#
+#copyright 2009, University of Tennessee
+################################################################################
+
+"""
+Dialog report panel to show and summarize the results of 
+the invariant calculation.
+"""
+import wx
+import sys
+import os
+import wx.html as html
+
+if sys.platform.count("win32") > 0:
+    _STATICBOX_WIDTH = 450
+    PANEL_WIDTH = 500 
+    PANEL_HEIGHT = 700
+    FONT_VARIANT = 0
+else:
+    _STATICBOX_WIDTH = 480
+    PANEL_WIDTH = 530
+    PANEL_HEIGHT = 700
+    FONT_VARIANT = 1
+    
+
+        
+class ReportDialog(wx.Dialog):
+    """
+    The report dialog box. 
+    """
+    
+    def __init__(self,  list, *args, **kwds):
+        """
+        Initialization. The parameters added to Dialog are:
+        
+        :param list: report_list (list of html_str, text_str, image)
+        from invariant_state
+        """
+        kwds["style"] = wx.RESIZE_BORDER|wx.DEFAULT_DIALOG_STYLE
+        wx.Dialog.__init__(self, *args, **kwds)
+        kwds["image"] = 'Dynamic Image'
+        # title
+        self.SetTitle("Report: Fitting")
+        # size
+        self.SetSize((720, 650))
+        # font size 
+        self.SetWindowVariant(variant=FONT_VARIANT)
+        # report string
+        self.report_list = list
+        # number of images of plot
+        self.nimages = len(list[2])
+        
+        if list[2] != None:
+            # put image path in the report string
+            if len(list[2]) == 1:
+                self.report_html = self.report_list[0] % \
+                                    "memory:img_fit0.png"
+            elif len(list[2]) == 2:
+                #print "self.report_list[0]",self.report_list[0]
+                self.report_html = self.report_list[0] % \
+                                    ("memory:img_fit0.png", 
+                                     "memory:img_fit1.png")
+            # allows up to three images
+            else:
+                self.report_html = self.report_list[0] % \
+                                    ("memory:img_fit0.png", 
+                                     "memory:img_fit1.png",
+                                     "memory:img_fit2.png")
+        else:
+            self.report_html = self.report_list[0]
+        # layout
+        self._setup_layout()
+        
+    def _setup_layout(self):
+        """
+        Set up layout
+        """
+        hbox = wx.BoxSizer(wx.HORIZONTAL)
+        
+        # buttons
+        id = wx.ID_OK
+        button_close = wx.Button(self, id, "Close")
+        button_close.SetToolTipString("Close this report window.") 
+        #hbox.Add((5,10), 1 , wx.EXPAND|wx.ADJUST_MINSIZE,0)
+        hbox.Add(button_close)
+        button_close.SetFocus()
+
+        id = wx.NewId()
+        button_preview = wx.Button(self, id, "Preview")
+        button_preview.SetToolTipString("Print preview this report.")
+        button_preview.Bind(wx.EVT_BUTTON, self.onPreview,
+                            id=button_preview.GetId()) 
+        hbox.Add(button_preview)
+
+        id = wx.NewId()
+        button_print = wx.Button(self, id, "Print")
+        button_print.SetToolTipString("Print this report.")
+        button_print.Bind(wx.EVT_BUTTON, self.onPrint,
+                          id=button_print.GetId()) 
+        hbox.Add(button_print)
+        
+        id = wx.NewId()
+        button_save = wx.Button(self, id, "Save" )
+        button_save.SetToolTipString("Save this report.")
+        button_save.Bind(wx.EVT_BUTTON, self.onSave, id = button_save.GetId()) 
+        hbox.Add(button_save)     
+        
+        # panel for report page
+        #panel = wx.Panel(self, -1)
+        vbox = wx.BoxSizer(wx.VERTICAL)
+        # html window
+        self.hwindow = html.HtmlWindow(self,style=wx.BORDER)
+        # set the html page with the report string
+        self.hwindow.SetPage(self.report_html)
+        
+        # add panels to boxsizers
+        vbox.Add(hbox)
+        vbox.Add(self.hwindow, 1, wx.EXPAND|wx.ALL,0)
+
+        self.SetSizer(vbox)
+        self.Centre()
+        self.Show(True)
+
+    def onSave(self, event=None):
+        """
+        Save
+        """
+        #todo: complete saving fig file and as a txt file
+        dlg = wx.FileDialog(self, "Choose a file",
+                            wildcard='HTML files (*.html)|*.html|'+
+                            'Text files (*.txt)|*.txt',
+                            style=wx.SAVE|wx.OVERWRITE_PROMPT|wx.CHANGE_DIR)
+        dlg.SetFilterIndex(0) #Set .html files to be default
+
+        if dlg.ShowModal() != wx.ID_OK:
+            dlg.Destroy()
+            return
+        
+        fName = dlg.GetPath()
+        ext_num = dlg.GetFilterIndex()     
+
+        #set file extensions 
+        img_ext = []
+        if ext_num == 0:
+            ext = '.html'
+            for num in range(self.nimages):
+                img_ext.append('_img4html%s.png' % num)
+            report_frame = self.report_list[0]
+        elif ext_num == 1:
+            ext = '.txt'   
+            # changing the image extension actually changes the image
+            # format on saving
+            for num in range(self.nimages):
+                img_ext.append('_img4txt%s.pdf' % num)
+            report = self.report_list[1]
+        else:
+            return
+        
+        #file name     
+        fName = os.path.splitext(fName)[0] + ext
+        dlg.Destroy()
+        pic_fname = []
+        #pic (png) file path/name
+        for num in range(self.nimages):
+            pic_name = os.path.splitext(fName)[0] + img_ext[num]
+            pic_fname.append(pic_name)
+        #put the image path in html string
+        if ext_num == 0:
+            if self.nimages == 1:
+                report = report_frame % pic_fname[0]
+            elif self.nimages == 2:
+                report = report_frame % (pic_fname[0], pic_fname[1])
+            elif self.nimages == 3:
+                report = report_frame % (pic_fname[0], pic_fname[1],
+                                          pic_fname[2])
+        f = open(fName, 'w')
+        f.write(report)
+        f.close()
+        #save png file using pic_fname
+        for num in range(self.nimages):
+            self.report_list[2][num].savefig(pic_fname[num])
+        
+            
+    def onPreview(self, event=None):
+        """
+        Preview
+        
+        : event: Preview button event
+        """
+        previewh = html.HtmlEasyPrinting(name="Printing", parentWindow=self)
+        previewh.PreviewText(self.report_html)
+        if event is not None:
+            event.Skip()
+    
+    def onPrint(self, event=None):
+        """
+        Print
+        
+        : event: Print button event
+        """
+        printh = html.HtmlEasyPrinting(name="Printing", parentWindow=self)
+        printh.PrintText(self.report_html)
+        if event is not None:
+            event.Skip()
+
+    def OnClose(self,event=None):
+        """
+        Close the Dialog
+        
+        : event: Close button event
+        """
+        self.Close()
+        # Reset memory
+        #wx.MemoryFSHandler()
+        if event is not None:
+            event.Skip()
+    
+    def HTML2PDF(self, data, filename):
+        """
+        Create a PDF file from html source string. 
+        
+        : data: html string
+        : filename: name of file to be saved
+        """
+        import ho.pisa as pisa
+        f = file(filename, "wb")
+        # pisa requires some extra packages, see their web-site
+        pdf = pisa.CreatePDF(data, f)
+        # close the file here otherwise it will be open until quitting
+        #the application.
+        f.close()
+
+        return not pdf.err
+
+        
+        
Index: sansview/perspectives/fitting/simfitpage.py
===================================================================
--- sansview/perspectives/fitting/simfitpage.py	(revision 66ff25070134c0c0c680c52e02ee279ffccc378f)
+++ sansview/perspectives/fitting/simfitpage.py	(revision 22963162e77a658f5b9affbe8d77c9cda810b0a3)
@@ -234,5 +234,7 @@
         #------------------------------------------------------
         if len(self.page_finder)==0:
-            sizer_title.Add(wx.StaticText(self,-1," No fit combinations are found!"))
+            msg = " No fit combinations are found! \n\n"
+            msg += " Please load data and set up at least two fit panels first..."
+            sizer_title.Add(wx.StaticText(self, -1, msg))
         else:
             ## store model  
