Index: sansview/perspectives/fitting/calcthread.py
===================================================================
--- sansview/perspectives/fitting/calcthread.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
+++ sansview/perspectives/fitting/calcthread.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
@@ -0,0 +1,294 @@
+# This program is public domain
+
+## \file
+#  \brief Abstract class for defining calculation threads.
+#
+
+import thread, traceback
+
+import sys
+if sys.platform.count("darwin")>0:
+    import mactime as time
+else:
+    import time
+
+class CalcThread:
+    """Threaded calculation class.  Inherit from here and specialize
+    the compute() method to perform the appropriate operations for the
+    class.
+
+    If you specialize the __init__ method be sure to call
+    CalcThread.__init__, passing it the keyword arguments for
+    yieldtime, worktime, update and complete.
+    
+    When defining the compute() method you need to include code which
+    allows the GUI to run.  They are as follows:
+        self.isquit()          call frequently to check for interrupts
+        self.update(kw=...)    call when the GUI could be updated
+        self.complete(kw=...)  call before exiting compute()
+    The update() and complete() calls accept field=value keyword
+    arguments which are passed to the called function.  complete()
+    should be called before exiting the GUI function.  A KeyboardInterrupt
+    event is triggered if the GUI signals that the computation should
+    be halted.
+
+    The following documentation should be included in the description
+    of the derived class.
+
+    The user of this class will call the following:
+
+        thread = Work(...,kw=...)  prepare the work thread.
+        thread.queue(...,kw=...)   queue a work unit
+        thread.requeue(...,kw=...) replace work unit on the end of queue
+        thread.reset(...,kw=...)   reset the queue to the given work unit
+        thread.stop()              clear the queue and halt
+        thread.interrupt()         halt the current work unit but continue
+        thread.ready(delay=0.)     request an update signal after delay
+        thread.isrunning()         returns true if compute() is running
+
+    Use queue() when all work must be done.  Use requeue() when intermediate
+    work items don't need to be done (e.g., in response to a mouse move
+    event).  Use reset() when the current item doesn't need to be completed
+    before the new event (e.g., in response to a mouse release event).  Use
+    stop() to halt the current and pending computations (e.g., in response to
+    a stop button).
+    
+    The methods queue(), requeue() and reset() are proxies for the compute()
+    method in the subclass.  Look there for a description of the arguments.
+    The compute() method can be called directly to run the computation in
+    the main thread, but it should not be called if isrunning() returns true.
+
+    The constructor accepts additional keywords yieldtime=0.01 and
+    worktime=0.01 which determine the cooperative multitasking
+    behaviour.  Yield time is the duration of the sleep period
+    required to give other processes a chance to run.  Work time
+    is the duration between sleep periods.
+
+    Notifying the GUI thread of work in progress and work complete
+    is done with updatefn=updatefn and completefn=completefn arguments
+    to the constructor.  Details of the parameters to the functions
+    depend on the particular calculation class, but they will all
+    be passed as keyword arguments.  Details of how the functions
+    should be implemented vary from framework to framework.
+
+    For wx, something like the following is needed:
+
+        import wx, wx.lib.newevent
+        (CalcCompleteEvent, EVT_CALC_COMPLETE) = wx.lib.newevent.NewEvent()
+
+        # methods in the main window class of your application
+        def __init__():
+            ...
+            # Prepare the calculation in the GUI thread.
+            self.work = Work(completefn=self.CalcComplete)
+            self.Bind(EVT_CALC_COMPLETE, self.OnCalcComplete)
+            ...
+            # Bind work queue to a menu event.
+            self.Bind(wx.EVT_MENU, self.OnCalcStart, id=idCALCSTART)
+            ...
+
+        def OnCalcStart(self,event):
+            # Start the work thread from the GUI thread.
+            self.work.queue(...work unit parameters...)
+
+        def CalcComplete(self,**kwargs):
+            # Generate CalcComplete event in the calculation thread.
+            # kwargs contains field1, field2, etc. as defined by
+            # the Work thread class.
+            event = CalcCompleteEvent(**kwargs)
+            wx.PostEvent(self, event)
+
+        def OnCalcComplete(self,event):
+            # Process CalcComplete event in GUI thread.
+            # Use values from event.field1, event.field2 etc. as
+            # defined by the Work thread class to show the results.
+            ...
+    """
+
+    def __init__(self,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        """Prepare the calculator"""
+        self.yieldtime     = yieldtime
+        self.worktime      = worktime
+        self.completefn    = completefn
+        self.updatefn      = updatefn
+        self._interrupting = False
+        self._running      = False
+        self._queue        = []
+        self._lock         = thread.allocate_lock()
+        self._delay        = 1e6
+
+    def queue(self,*args,**kwargs):
+        """Add a work unit to the end of the queue.  See the compute()
+        method for details of the arguments to the work unit."""
+        self._lock.acquire()
+        self._queue.append((args,kwargs))
+        # Cannot do start_new_thread call within the lock
+        self._lock.release()
+        if not self._running:
+            self._time_for_update = time.clock()+1e6
+            thread.start_new_thread(self._run,())
+
+    def requeue(self,*args,**kwargs):
+        """Replace the work unit on the end of the queue.  See the compute()
+        method for details of the arguments to the work unit."""
+        self._lock.acquire()
+        self._queue = self._queue[:-1]
+        self._lock.release()
+        self.queue(*args,**kwargs)
+
+    def reset(self,*args,**kwargs):
+        """Clear the queue and start a new work unit.  See the compute()
+        method for details of the arguments to the work unit."""
+        self.stop()
+        self.queue(*args,**kwargs)
+
+    def stop(self):
+        """Clear the queue and stop the thread.  New items may be
+        queued after stop.  To stop just the current work item, and
+        continue the rest of the queue call the interrupt method"""
+        self._lock.acquire()
+        self._interrupting = True
+        self._queue = []
+        self._lock.release()
+
+    def interrupt(self):
+        """Stop the current work item.  To clear the work queue as
+        well call the stop() method."""
+        self._lock.acquire()
+        self._interrupting = True
+        self._lock.release()
+
+    def isrunning(self): return self._running
+
+    def ready(self, delay=0.):
+        """Ready for another update after delay=t seconds.  Call
+        this for threads which can show intermediate results from
+        long calculations."""
+        self._delay = delay
+        self._lock.acquire()
+        self._time_for_update = time.clock() + delay
+        # print "setting _time_for_update to ",self._time_for_update
+        self._lock.release()
+
+    def isquit(self):
+        """Check for interrupts.  Should be called frequently to
+        provide user responsiveness.  Also yields to other running
+        threads, which is required for good performance on OS X."""
+
+        # Only called from within the running thread so no need to lock
+        if self._running and self.yieldtime>0 and time.clock()>self._time_for_nap:
+            # print "sharing"
+            time.sleep(self.yieldtime)
+            self._time_for_nap = time.clock() + self.worktime
+        if self._interrupting: raise KeyboardInterrupt
+
+    def update(self,**kwargs):
+       
+        """Update GUI with the lastest results from the current work unit."""
+        if self.updatefn != None and time.clock() > self._time_for_update:
+            self._lock.acquire()
+            self._time_for_update = time.clock() + self._delay
+            self._lock.release()
+            self._time_for_update += 1e6  # No more updates
+            
+            self.updatefn(**kwargs)
+            time.sleep(self.yieldtime)
+            if self._interrupting: raise KeyboardInterrupt
+        else:
+            self.isquit()
+        return
+
+    def complete(self,**kwargs):
+        """Update the GUI with the completed results from a work unit."""
+        if self.completefn != None:
+            self.completefn(**kwargs)
+            time.sleep(self.yieldtime)
+        return
+
+    def compute(self,*args,**kwargs):
+        """Perform a work unit.  The subclass will provide details of
+        the arguments."""
+        raise NotImplemented, "Calculation thread needs compute method"
+
+    def _run(self):
+        """Internal function to manage the thread."""
+        # The code for condition wait in the threading package is
+        # implemented using polling.  I'll accept for now that the
+        # authors of this code are clever enough that polling is
+        # difficult to avoid.  Rather than polling, I will exit the
+        # thread when the queue is empty and start a new thread when
+        # there is more work to be done.
+        while 1:
+            self._lock.acquire()
+            # print "lock aquired"
+            self._time_for_nap = time.clock()+self.worktime
+            self._running = True
+            if self._queue == []: break
+            self._interrupting = False
+            args,kwargs = self._queue[0]
+            self._queue = self._queue[1:]
+            self._lock.release()
+            # print "lock released"
+            try:
+                self.compute(*args,**kwargs)
+            except KeyboardInterrupt:
+                pass
+            except:
+                traceback.print_exc()
+                #print 'CalcThread exception',
+        self._running = False
+
+# ======================================================================
+# Demonstration of calcthread in action
+class CalcDemo(CalcThread):
+    """Example of a calculation thread."""
+    def compute(self,n):
+        total = 0.
+        for i in range(n):
+            self.update(i=i)
+            for j in range(n):
+                self.isquit()
+                total += j
+        self.complete(total=total)
+
+class CalcCommandline:
+    def __init__(self, n=20000):
+        print thread.get_ident()
+        self.starttime = time.clock()
+        self.done = False
+        self.work = CalcDemo(completefn=self.complete,
+                             updatefn=self.update, yieldtime=0.001)
+        self.work2 = CalcDemo(completefn=self.complete,
+                             updatefn=self.update)
+        self.work3 = CalcDemo(completefn=self.complete,
+                             updatefn=self.update)
+        self.work.queue(n)
+        self.work2.queue(n)
+        self.work3.queue(n)
+        print "Expect updates from Main every second and from thread every 2.5 seconds"
+        print ""
+        self.work.ready(.5)
+        while not self.done:
+            time.sleep(1)
+            print "Main thread %d at %.2f"%(thread.get_ident(),time.clock()-self.starttime)
+
+    def update(self,i=0):
+        print "Update i=%d from thread %d at %.2f"%(i,thread.get_ident(),time.clock()-self.starttime)
+        self.work.ready(2.5)
+
+    def complete(self,total=0.0):
+        print "Complete total=%g from thread %d at %.2f"%(total,thread.get_ident(),time.clock()-self.starttime)
+        self.done = True
+
+if __name__ == "__main__":
+    CalcCommandline()
+
+# version
+__id__ = "$Id: calcthread.py 249 2007-06-15 17:03:01Z ziwen $"
+
+# End of file
Index: sansview/perspectives/fitting/fit_thread.py
===================================================================
--- sansview/perspectives/fitting/fit_thread.py	(revision 925a30e1970e2e81bed1969735af0a4824905734)
+++ sansview/perspectives/fitting/fit_thread.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
@@ -175,6 +175,5 @@
             raise
         except:
-            raise
-            #wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
-            #return 
+            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
+            return 
     
Index: sansview/perspectives/fitting/fitpage1D.py
===================================================================
--- sansview/perspectives/fitting/fitpage1D.py	(revision 51502505e9a26b85c2224996fa550cceb4102dd8)
+++ sansview/perspectives/fitting/fitpage1D.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
@@ -140,5 +140,9 @@
         # This sizer contains model list and chisqr value 
         #filling sizer4
+        ## structure combox box
+        self.structbox = wx.ComboBox(self, -1)
+        # define combox box
         self.modelbox = wx.ComboBox(self, -1)
+        
         self.tcChi    =  wx.StaticText(self, -1, str(0), style=wx.ALIGN_LEFT)
         self.tcChi.Hide()
@@ -149,6 +153,15 @@
         self.sizer4.Add(wx.StaticText(self,-1,'Model'),(iy,ix),(1,1)\
                   , wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+        
         ix += 1
         self.sizer4.Add(self.modelbox,(iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        ix +=1
+        self.text_mult= wx.StaticText(self,-1,' x ')
+        self.sizer4.Add(self.text_mult,(iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        ix += 1
+        self.sizer4.Add(self.structbox,(iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        
+        
+        
         ix += 1
         self.sizer4.Add(self.text1_1,(iy,ix),(1,1),\
@@ -262,5 +275,5 @@
         # model on which the fit would be performed
         self.model=None
-        
+       
         self.back_up_model= None
         #dictionary of model name and model class
@@ -282,5 +295,6 @@
         self.Centre()
         self.Layout()
-        self.GrandParent.GetSizer().Layout()
+        
+        self.parent.GetSizer().Layout()
    
     def compute_chisqr2D(self):
@@ -289,5 +303,7 @@
             to the tcChi txtcrl
         """
-        flag=self.checkFitRange()
+        from sans.guiframe.utils import check_value
+        flag = check_value( self.qmin, self.qmax)
+        #flag=self.checkFitRange()
         res=[]
         if flag== True:
@@ -322,5 +338,7 @@
             to the tcChi txtcrl
         """
-        flag=self.checkFitRange()
+        from sans.guiframe.utils import check_value
+        flag = check_value( self.qmin, self.qmax)
+        #flag=self.checkFitRange()
         if flag== True:
             try:
@@ -367,9 +385,18 @@
         self.parent.GetSizer().Layout()
 
-        for item in self.model_list_box.itervalues():
-            name = item.__name__
-            if hasattr(item, "name"):
-                name = item.name
-            
+       
+        name= self.modelbox.GetString(self.modelbox.GetCurrentSelection())
+        form_factor =self.modelbox.GetClientData(self.modelbox.GetCurrentSelection())
+        struct_factor =self.structbox.GetClientData(self.structbox.GetCurrentSelection())
+       
+      
+        if form_factor!="separator":
+            if struct_factor != None and struct_factor.__name__ != "NoStructure":
+                from sans.models.MultiplicationModel import MultiplicationModel
+                self.model= MultiplicationModel(form_factor(),struct_factor())
+            else:
+                 self.model= form_factor() 
+            self.back_up_model= self.model.clone()
+            name= self.model.name
             if name == None:
                 self.qmin.Disable()
@@ -378,37 +405,48 @@
                 self.qmin.Enable()
                 self.qmax.Enable() 
-            
-            if name ==event.GetString():
-                try:
-                    self.model=item()
-                    self.back_up_model= self.model.clone()
-                    evt = ModelEventbox(model=self.model,name=name)
-                    wx.PostEvent(self.event_owner, evt)
-                    self.text1_1.Show()
-                    self.compute_chisqr()
-                    self.tcChi.Show()
-                except:
-                    raise #ValueError,"model.name is not equal to model class name"
-                break  
+            evt = ModelEventbox(model=self.model,name=name)
+            wx.PostEvent(self.event_owner, evt)   
+            self.text1_1.Show()
+            self.tcChi.Show()
+            self.compute_chisqr()
+        
+            
+        else:
+            self.model=None 
+            msg= " Select non - model value:%s ! Previous Model reloaded "%name 
+            wx.PostEvent(self.parent.parent, StatusEvent(status= msg))
+            
+        self.set_panel(self.model)
             
                  
     def onFit(self,event):
-        """ signal for fitting"""
-         
-        flag=self.checkFitRange()
-        self.set_manager(self.manager)
-     
+        """ 
+            signal for fitting .Perform single fit only
+        """
+        from sans.guiframe.utils import check_value
+        flag = check_value( self.qmin, self.qmax) 
+        
+        if not flag:
+            msg= "Fitting range invalid"
+            wx.PostEvent(self.parent.parent, StatusEvent(status= msg ))
+            return 
+        
+        if len(self.param_toFit) <= 0:
+            msg= "Select at least one parameter to fit"
+            wx.PostEvent(self.parent.parent, StatusEvent(status= msg ))
+            return 
+        
         self.qmin_x=float(self.qmin.GetValue())
         self.qmax_x =float( self.qmax.GetValue())
-        if len(self.param_toFit) >0 and flag==True:
-            self.manager.schedule_for_fit( value=1,fitproblem =None) 
-            if hasattr(self.data, "data"):
-                #single fit for Data2D
-                self.manager._on_single_fit(qmin=self.qmin_x,qmax=self.qmax_x,
-                                            ymin=self.data.ymin, ymax=self.data.ymax,
-                                            xmin=self.data.xmin,xmax=self.data.xmax)
-            else:
-                #single fit for Data1D
-                self.manager._on_single_fit(qmin=self.qmin_x,qmax=self.qmax_x)
+        
+        self.manager.schedule_for_fit( value=1,fitproblem =None) 
+        if hasattr(self.data, "data"):
+            #single fit for Data2D
+            self.manager._on_single_fit(qmin=self.qmin_x,qmax=self.qmax_x,
+                                        ymin=self.data.ymin, ymax=self.data.ymax,
+                                        xmin=self.data.xmin,xmax=self.data.xmax)
+        else:
+            #single fit for Data1D
+            self.manager._on_single_fit(qmin=self.qmin_x,qmax=self.qmax_x)
                 
             self.vbox.Layout()
@@ -416,24 +454,7 @@
             self.Layout()
             self.parent.GetSizer().Layout()
-        else:
-            wx.PostEvent(self.parent.parent, StatusEvent(status=\
-                            "Select at least one parameter to fit "))
+        
+            
   
-   
-    def _onTextEnter(self,event):
-        """
-            set a flag to determine if the fitting range entered by the user is valid
-        """
-      
-        try:
-            flag=self.checkFitRange()
-            if flag==True and self.model!=None:
-                self.manager.redraw_model(float(self.xmin.GetValue())\
-                                               ,float(self.xmax.GetValue()))
-        except:
-
-            wx.PostEvent(self.parent.GrandParent, StatusEvent(status=\
-                            "Drawing  Error:wrong value entered %s"% sys.exc_value))
-        
    
     
@@ -576,10 +597,8 @@
             from DataLoader.qsmearing import smear_selection
             smear =smear_selection( self.data )
-            if hasattr(self.data,"dx"):
+            if hasattr(self.data,"dxl"):
                 msg= ": Resolution smearing parameters"
-            if hasattr(self.data,"dxl"):
-                msg= ": Slit_l smearing parameters"
             if hasattr(self.data,"dxw"):
-                msg= ": Slit_w smearing parameters"
+                msg= ": Slit smearing parameters"
             if smear ==None:
                 wx.PostEvent(self.manager.parent, StatusEvent(status=\
Index: sansview/perspectives/fitting/fitpanel.py
===================================================================
--- sansview/perspectives/fitting/fitpanel.py	(revision ae9c692ba14fcc54f9fd475d00808583c3038427)
+++ sansview/perspectives/fitting/fitpanel.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
@@ -33,5 +33,5 @@
         #Creating the default page --welcomed page
         self.about_page=None
-        from welcome_panel import PanelAbout
+        from sans.guiframe.welcome_panel import PanelAbout
         self.about_page = PanelAbout(self, -1)
         self.AddPage(self.about_page,"welcome!")
@@ -40,4 +40,6 @@
         #dictionary of miodel {model class name, model class}
         self.model_list_box={}
+        ## list of structure factor
+        self.struct_list_box=[]
         # save the title of the last page tab added
         self.fit_page_name=[]
@@ -101,5 +103,5 @@
             @param owner: the class responsible of plotting
         """
-        self.event_owner = owner
+        self.event_owner=owner
         
     def add_sim_page(self):
@@ -126,5 +128,5 @@
         if not name in self.fit_page_name :
             from fitpage1D import FitPage1D
-            panel = FitPage1D(parent=self,data=data, id=-1)
+            panel = FitPage1D(self,data, -1)
             panel.name=name
             
@@ -149,5 +151,5 @@
         """
         from modelpage import ModelPage
-        
+        #print "fitpanel model", model
         panel = ModelPage(self,model,page_title, -1)
         panel.set_manager(self.manager)
@@ -169,4 +171,39 @@
         self.manager.draw_model(model, page_title)
         
+    def new_help_add_model_page(self,model,description,page_title, qmin=0, qmax=0.1, npts=50):
+        """
+            #TODO: fill in description
+            
+            @param qmin: mimimum Q
+            @param qmax: maximum Q
+            @param npts: number of Q points
+        """
+        ## storing page info
+        from pageInfo import  PageInfo
+        myinfo = PageInfo( self, model )
+        myinfo.model_list_box = self.model_list_box
+        from modelpage import ModelPage
+        
+        panel = ModelPage(self,myinfo,page_title)
+        panel.set_manager(self.manager)
+        panel.set_owner(self.event_owner)
+        
+        
+        self.AddPage(page=panel,caption="Model",select=True)
+        panel.populate_box( self.model_list_box)
+        panel.name = page_title
+        self.draw_model_name=page_title
+        self.model_page_number=self.GetSelection()
+        self.model_page=self.GetPage(self.GetSelection())
+        
+        
+        # Set the range used to plot models
+        self.model_page.set_range(qmin, qmax, npts)
+        
+        # We just created a model page, we are ready to plot the model
+        #self.manager.draw_model(model, model.name)
+        #FOR PLUGIN  for some reason model.name is = BASEcomponent
+        self.manager.draw_model(model, page_title)
+     
         
     def add_model_page(self,model,description,page_title, qmin=0, qmax=0.1, npts=50, topmenu=False):
@@ -193,7 +230,9 @@
             @return the current page selected
         """
+        #return self.nb.GetCurrentPage()
         return self.GetPage(self.GetSelection() )
   
-   
+    
+     
     def set_model_list(self,dict):
          """ 
Index: sansview/perspectives/fitting/fitproblem.py
===================================================================
--- sansview/perspectives/fitting/fitproblem.py	(revision 925a30e1970e2e81bed1969735af0a4824905734)
+++ sansview/perspectives/fitting/fitproblem.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
@@ -45,4 +45,10 @@
         return self.smearer
     
+    def save_model_name(self, name):  
+        self.name_per_page= name
+        
+        
+    def get_name(self):
+        return self.name_per_page
     
     def set_model(self,model,name):
@@ -52,5 +58,9 @@
              @param name: name created for model
         """
-        self.model_list=[model,name]
+        
+        if len(self.model_list)>0 and name==None:
+            self.model_list=[model,self.model_list[1]]
+        else:
+            self.model_list=[model,name]
 
   
Index: sansview/perspectives/fitting/fitting.py
===================================================================
--- sansview/perspectives/fitting/fitting.py	(revision 0f7b597f9b5e3ccab19b7b40e808cb63f0939d5c)
+++ sansview/perspectives/fitting/fitting.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
@@ -81,13 +81,20 @@
         #Set park engine
         id3 = wx.NewId()
-        self.menu1.AppendCheckItem(id3, "park") 
-        wx.EVT_MENU(owner, id3, self._onset_engine)
+        scipy_help= "Scipy Engine: Perform Simple fit. More in Help window...."
+        self.menu1.Append(id3, "Scipy",scipy_help) 
+        wx.EVT_MENU(owner, id3,  self._onset_engine_scipy)
+        
+        id3 = wx.NewId()
+        park_help = "Park Engine: Perform Complex fit. More in Help window...."
+        self.menu1.Append(id3, "park",park_help) 
+        wx.EVT_MENU(owner, id3,  self._onset_engine_park)
         
         #menu for model
         menu2 = wx.Menu()
+    
         self.menu_mng.populate_menu(menu2, owner)
         id2 = wx.NewId()
         owner.Bind(models.EVT_MODEL,self._on_model_menu)
-        ## Allow fitpanel to access list of models
+      
         self.fit_panel.set_owner(owner)
         self.fit_panel.set_model_list(self.menu_mng.get_model_list())
@@ -96,5 +103,4 @@
         #create  menubar items
         return [(id, self.menu1, "Fitting"),(id2, menu2, "Model")]
-    
     
     def on_add_sim_page(self, event):
@@ -130,4 +136,6 @@
                
                 if item.name==graph.selected_plottable :
+                    if not hasattr(item, "group_id"):
+                        return []
                     return [["Select data  for Fitting", \
                              "Dialog with fitting parameters ", self._onSelect]] 
@@ -240,5 +248,4 @@
         for item in self.panel.graph.plottables:
             if item.name == self.panel.graph.selected_plottable:
-                ## reset the error back to data
                 if len(self.err_dy)>0:
                     if item.name in  self.err_dy.iterkeys():
@@ -354,5 +361,4 @@
                     model= list[0]
                     break
-            ## reset the current model with new fitted parameters    
             i = 0
             for name in pars:
@@ -383,6 +389,4 @@
         """
         if cpage!=None:
-            ## the fit perform was a single fit but selected  from the 
-            ## simultaneous fit page
             self._single_fit_completed(result=result,pars=pars,cpage=cpage,
                                        qmin=qmin,qmax=qmax,
@@ -540,12 +544,21 @@
             
         """
-        #set an engine to perform fit
-        from sans.fit.Fitting import Fit
-        self.fitter= Fit(self._fit_engine)
+        ##Setting an id to store model and data
         self.fit_id= 0
         #Setting an id to store model and data
         if id!=None:
              self.fit_id= id
-       
+        ##  count the number of fitproblem schedule to fit 
+        fitproblem_count= 0
+        for value in self.page_finder.itervalues():
+            if value.get_scheduled()==1:
+                fitproblem_count += 1
+        ## if simultaneous fit change automatically the engine to park
+        if fitproblem_count >1:
+            self._on_change_engine(engine='park')
+        from sans.fit.Fitting import Fit
+        self.fitter= Fit(self._fit_engine)
+        
+        
         for page, value in self.page_finder.iteritems():
             try:
@@ -576,4 +589,5 @@
                             param_value = item[1]
                             param_name = item[0]
+    
                             new_model.parameterset[ param_name].set( param_value )
                         
@@ -613,6 +627,6 @@
             if self.calc_thread != None and self.calc_thread.isrunning():
                 self.calc_thread.stop()
-            ## Perform a single fit , then need to page 
-            if  self.fit_id==1:
+			## perform single fit
+            if  fitproblem_count==1:
                 self.calc_thread =FitThread(parent =self.parent,
                                         fn= self.fitter,
@@ -644,18 +658,17 @@
             return
         
-        
-    def _onset_engine(self,event):
+    def _onset_engine_park(self,event):
         """ 
-            Toggle engine name from "park" to "scipy" or reverse if event received
-            @param event: wx.menu item checked
-        """
-        if self._fit_engine== 'park':
-            self._on_change_engine('scipy')
-        else:
-            self._on_change_engine('park')
-            
-        msg= "Engine set to: %s" % self._fit_engine
-        wx.PostEvent(self.parent, StatusEvent(status= msg ))
-  
+            set engine to park
+        """
+        self._on_change_engine('park')
+       
+       
+    def _onset_engine_scipy(self,event):
+        """ 
+            set engine to scipy
+        """
+        self._on_change_engine('scipy')
+       
     
     def _on_change_engine(self, engine='park'):
@@ -665,4 +678,5 @@
         """
         self._fit_engine = engine
+        wx.PostEvent(self.parent, StatusEvent(status="Engine set to: %s" % self._fit_engine))
    
    
@@ -681,19 +695,23 @@
         ## example trying to call set_panel on self.sim_page
         if current_pg != sim_page:
-            current_pg.set_panel(model)
            
-            model.name="M"+str(self.index_model)
+            if len(self.page_finder[current_pg].get_model())==0:
+                
+                model.name="M"+str(self.index_model)
+                self.index_model += 1  
+            else:
+                model.name= self.page_finder[current_pg].get_model()[0].name
+                
             try:
-                metadata=self.page_finder[current_pg].get_data()
-                M_name=model.name+"= "+name+"("+metadata.group_id+")"
+                metadata=self.page_finder[current_pg].get_plotted_data()
+                M_name = model.name+"= "+name+"("+metadata.name+")"
             except:
-                M_name=model.name+"= "+name
-            self.index_model += 1  
-            
-            # save model name
+                M_name = model.name+"= "+name
             # save the name containing the data name with the appropriate model
             self.page_finder[current_pg].set_model(model,M_name)
+            
+                
+            # save model name
             self.plot_helper(currpage= current_pg,qmin= None,qmax= None)
-            ## draw  self.sim_page and store information on the selected model
             if self.sim_page!=None:
                 self.sim_page.add_model(self.page_finder)
@@ -719,7 +737,6 @@
         for page, value in self.page_finder.iteritems():
             if page ==current_pg :
-                self.plot_helper(currpage=page,qmin= qmin,qmax= qmax)
                 break 
-        
+        self.plot_helper(currpage=page,qmin= qmin,qmax= qmax)
         
         
@@ -734,21 +751,20 @@
         if self.fit_panel.GetPageCount() >1:
             for page in self.page_finder.iterkeys():
-                if  page==currpage :  
+                if  page == currpage :  
                     data= self.page_finder[page].get_plotted_data()
                     list= self.page_finder[page].get_model()
-                    smearer= self.page_finder[page].get_smearer()
-                    model=list[0]
+                    smearer = self.page_finder[page].get_smearer()
+                    model = list[0]
                     break 
             ## create Model 1D
-            if data!=None and data.__class__.__name__ != 'Data2D':
+            if data != None and data.__class__.__name__ != 'Data2D':
                 x= numpy.zeros(len(data.x))  
-                y= numpy.zeros(len(data.x)) 
+                y= numpy.zeros(len(data.y)) 
                 
                 theory = Theory1D(x=x, y=y)
                 theory.name = model.name
-                theory.group_id = data.group_id
+                if hasattr(data ,"group_id"):
+                    theory.group_id = data.group_id
                 theory.id = "Model"
-                
-                 
                 
                 x_name, x_units = data.get_xaxis() 
@@ -757,7 +773,8 @@
                 theory.yaxis(y_name, y_units)
                 if qmin == None :
-                   qmin = min(data.x)
+                    qmin = min(data.x)
                 if qmax == None :
-                   qmax = max(data.x)
+                    qmax = max(data.x)
+                
                 j=0
                 try:
@@ -865,8 +882,8 @@
             @param evt: wx.menu event
         """
-        name = evt.model.__name__
+        name = evt.model.__class__.__name__
         if hasattr(evt.model, "name"):
             name = evt.model.name
-        model=evt.model()
+        model=evt.model
         description=model.description
         
@@ -875,6 +892,59 @@
         # the content will be updated and the plot refreshed
         self.fit_panel.add_model_page(model,description,name,topmenu=True)
-        
-        
+    
+    def complete1D_from_data(self, output,model, data, x, elapsed, name):
+        """
+             plot model 1D with data info 
+        """
+        y= output
+        x= data.x
+        theory = Theory1D(x=x, y=y)
+        theory.name = model.name
+        theory.group_id = data.group_id
+        theory.id = "Model"
+        
+        x_name, x_units = data.get_xaxis() 
+        y_name, y_units = data.get_yaxis() 
+        theory.xaxis(x_name, x_units)
+        theory.yaxis(y_name, y_units)
+        wx.PostEvent(self.parent, NewPlotEvent(plot=theory,
+                                                title=str(data.name)))
+        
+    def draw_model1D_from_Data(self, data, model,name=None,
+                                qmin=None, qmax=None, smearer= None):
+        """
+            Draw model 1D from loaded data1D
+            @param data: loaded data
+            @param model: the model to plot
+        """
+        x = data.x
+        self.model= model
+        if qmin == None :
+           qmin = min(data.x)
+        if qmax == None :
+           qmax = max(data.x)
+        if name ==None:
+            name=model.name
+        try:
+            from model_thread import Calc1D
+            ## If a thread is already started, stop it
+            if self.calc_thread != None and self.calc_thread.isrunning():
+                self.calc_thread.stop()
+            self.calc_thread = Calc1D( x= x,
+                                      model= self.model, 
+                                       qmin= qmin,
+                                       qmax= qmax,
+                                       name= name,
+                                       smearer= smearer,
+                            completefn= self.complete1D_from_data,
+                            updatefn= self.update1D)
+            self.calc_thread.queue()
+            
+        except:
+            msg= " Error occurred when drawing %s Model 1D: "%self.model.name
+            msg+= " %s"%sys.exc_value
+            wx.PostEvent( self.parent, StatusEvent(status= msg ))
+            return  
+            
     def draw_model(self, model, name, data= None, description= None,
                    enable1D= True, enable2D= False,
@@ -907,5 +977,35 @@
                            qstep=qstep)
         
-              
+    
+    def update1D(self,x, output):
+        """
+            Update the output of plotting model 1D
+        """
+        self.calc_thread.ready(1)
+    
+    def complete1D(self, x,output, elapsed, name,data=None):
+        """
+            Complete plotting 1D data
+        """ 
+        try:
+            y = output
+            new_plot = Theory1D(x, y)
+            new_plot.name = name
+            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
+            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
+            new_plot.id ="Model"
+            new_plot.group_id ="Model"
+            # Pass the reset flag to let the plotting event handler
+            # know that we are replacing the whole plot
+            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
+                             title="Analytical model 1D ", reset=True ))
+            
+        except:
+            msg= " Error occurred when drawing %s Model 1D: "%new_plot.name
+            msg+= " %s"%sys.exc_value
+            wx.PostEvent( self.parent, StatusEvent(status= msg ))
+            return  
+        
+                 
     def _draw_model1D(self, model, name, description= None, enable1D= True,
                       qmin= DEFAULT_QMIN, qmax= DEFAULT_QMAX, qstep= DEFAULT_NPTS):
@@ -925,37 +1025,41 @@
                            endpoint=True
                            )      
-        xlen= len(x)
-        y = numpy.zeros(xlen)
-        
-        if  enable1D:
-            for i in range(xlen):
-                y[i] = model.run(x[i]) 
+        self.model= model
+        if enable1D:
             try:
-                new_plot = Theory1D(x, y)
-                new_plot.name = name
-                new_plot.xaxis("\\rm{Q}", 'A^{-1}')
-                new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
-                new_plot.id ="Model"
-                new_plot.group_id ="Model"
-                # Pass the reset flag to let the plotting event handler
-                # know that we are replacing the whole plot
-                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
-                                 title="Analytical model 1D ", reset=True ))
+                from model_thread import Calc1D
+                ## If a thread is already started, stop it
+                if self.calc_thread != None and self.calc_thread.isrunning():
+                    self.calc_thread.stop()
+                self.calc_thread = Calc1D( x= x,
+                                          model= self.model, 
+                                           qmin= qmin,
+                                           qmax= qmax,
+                                           name= name,
+                                           data=None,
+                                        smearer=None,
+                                completefn= self.complete1D,
+                                updatefn= self.update1D)
+                self.calc_thread.queue()
                 
             except:
-                msg= " Error occurred when drawing %s Model 1D: "%new_plot.name
+                msg= " Error occurred when drawing %s Model 1D: "%self.model.name
                 msg+= " %s"%sys.exc_value
                 wx.PostEvent( self.parent, StatusEvent(status= msg ))
-                return
-
-
-    
-    def update(self, output,time):
+                return  
+                
+
+
+        
+    def update2D(self, output,time=None):
         """
             Update the output of plotting model
         """
-        pass
-    
-    def complete(self, output, elapsed, model, qmin, qmax,qstep=DEFAULT_NPTS):
+        wx.PostEvent(self.parent, StatusEvent(status="Plot \
+        #updating ... ",type="update"))
+        self.calc_thread.ready(0.01)
+        
+        
+    def complete2D(self, output, elapsed, model, qmin, qmax,qstep=DEFAULT_NPTS):
         """
             Complete get the result of modelthread and create model 2D
@@ -971,4 +1075,5 @@
     
         from DataLoader.data_info import Detector, Source
+        
         detector = Detector()
         theory.detector=[]
@@ -1047,21 +1152,20 @@
         if enable2D:
             try:
-                from sans.guiframe.model_thread import Calc2D
-                self.calc_thread = Calc2D(parent =self.parent,x=x,
-                                           y=y,model= self.model, 
-                                           qmin=qmin,
-                                           qmax=qmax,
-                                           qstep=qstep,
-                                completefn=self.complete,
-                                updatefn=None)
+                from model_thread import Calc2D
+                ## If a thread is already started, stop it
+                if self.calc_thread != None and self.calc_thread.isrunning():
+                    self.calc_thread.stop()
+                self.calc_thread = Calc2D( x= x,
+                                           y= y, model= self.model, 
+                                           qmin= qmin,
+                                           qmax= qmax,
+                                           qstep= qstep,
+                                completefn= self.complete2D,
+                                updatefn= self.update2D )
                 self.calc_thread.queue()
-                self.calc_thread.ready(2.5)
+                
             except:
-                msg= "Draw model 2D error: "
-                wx.PostEvent(self.parent, StatusEvent(status="%s %s" % sys.exc_value))
-                return
-            
-  
-           
+                raise
+    
    
 if __name__ == "__main__":
Index: sansview/perspectives/fitting/model_thread.py
===================================================================
--- sansview/perspectives/fitting/model_thread.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
+++ sansview/perspectives/fitting/model_thread.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
@@ -0,0 +1,347 @@
+import time
+from calcthread import CalcThread
+import sys
+
+class Calc2D_all(CalcThread):
+    """
+        Compute 2D model
+        This calculation assumes a 2-fold symmetry of the model
+        where points are computed for one half of the detector
+        and I(qx, qy) = I(-qx, -qy) is assumed.
+    """
+    
+    def __init__(self, x, y, model,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        CalcThread.__init__(self,completefn,
+                 updatefn,
+                 yieldtime,
+                 worktime)
+        
+        self.x = x
+        self.y = y
+        self.model = model
+        self.starttime = 0
+        
+    def isquit(self):
+        try:
+            CalcThread.isquit(self)
+        except KeyboardInterrupt:
+            wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Calc %s interrupted" % self.model.name))
+            raise KeyboardInterrupt
+        
+    def compute(self):
+        import numpy
+        x = self.x
+        y = self.y
+        output = numpy.zeros((len(x),len(y)))
+            
+        self.starttime = time.time()
+        lx = len(self.x)
+        
+        #for i_x in range(int(len(self.x)/2)):
+        for i_x in range(len(self.x)):
+            if i_x%2==1:
+                continue
+            
+            # Check whether we need to bail out
+            self.update(output=output)
+            self.isquit()
+                
+            for i_y in range(len(self.y)):
+                value = self.model.runXY([self.x[i_x], self.y[i_y]])
+                output[i_y][i_x] = value
+                #output[lx-i_y-1][lx-i_x-1] = value
+                
+        if lx%2==1:
+            i_x = int(len(self.x)/2)
+            for i_y in range(len(self.y)):
+                value = self.model.runXY([self.x[i_x], self.y[i_y]])
+                output[i_y][i_x] = value
+                
+        #for i_x in range(int(len(self.x)/2)):
+        for i_x in range(len(self.x)):
+            if not i_x%2==1:
+                continue
+
+            # Check whether we need to bail out
+            self.update(output=output)
+            self.isquit()
+            
+            for i_y in range(len(self.y)):
+                value = self.model.runXY([self.x[i_x], self.y[i_y]])
+                output[i_y][i_x] = value
+                #output[lx-i_y-1][lx-i_x-1] = value
+            
+        elapsed = time.time()-self.starttime
+        self.complete(output=output, elapsed=elapsed)
+
+
+class Calc2D(CalcThread):
+    """
+        Compute 2D model
+        This calculation assumes a 2-fold symmetry of the model
+        where points are computed for one half of the detector
+        and I(qx, qy) = I(-qx, -qy) is assumed.
+    """
+    
+    def __init__(self, x, y, model,qmin, qmax,qstep,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        CalcThread.__init__(self,completefn,
+                 updatefn,
+                 yieldtime,
+                 worktime)
+        self.qmin= qmin
+        self.qmax=qmax
+        self.qstep= qstep
+        self.x = x
+        self.y = y
+        ## the model on to calculate
+        self.model = model
+        self.starttime = 0
+      
+      
+    def isquit(self):
+        try:
+            CalcThread.isquit(self)
+        except KeyboardInterrupt:
+            wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Calc %s interrupted" % self.model.name))
+           
+            raise KeyboardInterrupt
+        
+        
+    def compute(self):
+        """
+            Compute the data given a model function
+        """
+        import numpy
+        x = self.x
+        y = self.y
+        output = numpy.zeros((len(x),len(y)))
+      
+        center_x=0
+        center_y=0
+        
+        self.starttime = time.time()
+        
+        
+        lx = len(self.x)
+       
+        for i_x in range(len(self.x)):
+            # Check whether we need to bail out
+            self.update(output=output )
+            self.isquit()
+       
+            for i_y in range(int(len(self.y))):
+           
+                if (self.x[i_x]*self.x[i_x]+self.y[i_y]*self.y[i_y]) \
+                    < self.qmin * self.qmin:
+                    
+                    output[i_x] [i_y]=0   
+                else:
+                    value = self.model.runXY([self.x[i_x]-center_x, self.y[i_y]-center_y])
+                    output[i_x] [i_y]=value   
+            
+        elapsed = time.time()-self.starttime
+        self.complete(
+                      output=output, elapsed=elapsed,model= self.model,
+                      qmin= self.qmin,
+                      qmax=self.qmax,
+                      qstep=self.qstep)
+
+
+class Calc2D_4fold(CalcThread):
+    """
+        Compute 2D model
+        This calculation assumes a 4-fold symmetry of the model.
+        Really is the same calculation time since we have to 
+        calculate points for 0<phi<pi anyway.
+    """
+    
+    def __init__(self, x, y, model,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        CalcThread.__init__(self,completefn,
+                 updatefn,
+                 yieldtime,
+                 worktime)
+        self.x = x
+        self.y = y
+        self.model = model
+        self.starttime = 0
+        
+    def isquit(self):
+        try:
+            CalcThread.isquit(self)
+        except KeyboardInterrupt:
+            #printEVT("Calc %s interrupted" % self.model.name)
+            wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Calc %s interrupted" % self.model.name))
+           
+            raise KeyboardInterrupt
+        
+    def compute(self):
+        import numpy
+        x = self.x
+        y = self.y
+        output = numpy.zeros((len(x),len(y)))
+            
+        self.starttime = time.time()
+        lx = len(self.x)
+        
+        for i_x in range(int(len(self.x)/2)):
+            if i_x%2==1:
+                continue
+            
+            # Check whether we need to bail out
+            self.update(output=output)
+            self.isquit()
+                
+            for i_y in range(int(len(self.y)/2)):
+                value1 = self.model.runXY([self.x[i_x], self.y[i_y]])
+                value2 = self.model.runXY([self.x[i_x], self.y[lx-i_y-1]])
+                output[i_y][i_x] = value1 + value2
+                output[lx-i_y-1][lx-i_x-1] = value1 + value2
+                output[lx-i_y-1][i_x] = value1 + value2
+                output[i_y][lx-i_x-1] = value1 + value2
+                
+        if lx%2==1:
+            i_x = int(len(self.x)/2)
+            for i_y in range(int(len(self.y)/2)):
+                value1 = self.model.runXY([self.x[i_x], self.y[i_y]])
+                value2 = self.model.runXY([self.x[i_x], self.y[lx-i_y-1]])
+                output[i_y][i_x] = value1 + value2
+                output[lx-i_y-1][lx-i_x-1] = value1 + value2
+                output[lx-i_y-1][i_x] = value1 + value2
+                output[i_y][lx-i_x-1] = value1 + value2
+                
+        for i_x in range(int(len(self.x)/2)):
+            if not i_x%2==1:
+                continue
+
+            # Check whether we need to bail out
+            self.update(output=output)
+            self.isquit()
+            
+            for i_y in range(int(len(self.y)/2)):
+                value1 = self.model.runXY([self.x[i_x], self.y[i_y]])
+                value2 = self.model.runXY([self.x[i_x], self.y[lx-i_y-1]])
+                output[i_y][i_x] = value1 + value2
+                output[lx-i_y-1][lx-i_x-1] = value1 + value2
+                output[lx-i_y-1][i_x] = value1 + value2
+                output[i_y][lx-i_x-1] = value1 + value2
+            
+        elapsed = time.time()-self.starttime
+        self.complete(output=output, elapsed=elapsed)
+
+
+
+class Calc1D(CalcThread):
+    """Compute 1D data"""
+    
+    def __init__(self, x, model,
+                 data=None,
+                 qmin=None,
+                 qmax=None,
+                 name=None,
+                 smearer=None,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        CalcThread.__init__(self,completefn,
+                 updatefn,
+                 yieldtime,
+                 worktime)
+        self.x = x
+        self.data= data
+        self.qmin= qmin
+        self.qmax= qmax
+        self.model = model
+        self.name= name
+        self.smearer= smearer
+        self.starttime = 0
+        
+    def compute(self):
+        import numpy
+        
+        output = numpy.zeros(len(self.x))
+        if self.qmin==None:
+            self.qmin= min(self.x)
+        if self.qmax==None:
+            self.qmax= max(self.x) 
+               
+        self.starttime = time.time()
+        
+        for i_x in range(len(self.x)):
+            self.update(x= self.x, output=output )
+            # Check whether we need to bail out
+            self.isquit()
+            if self.qmin <= self.x[i_x] and self.x[i_x] <= self.qmax:
+                value = self.model.run(self.x[i_x])
+                output[i_x] = value
+        if self.smearer!=None:
+            output = self.smearer(output)
+                    
+        elapsed = time.time()-self.starttime
+        self.complete(x= self.x, output=output, 
+                      elapsed=elapsed, name=self.name, data=self.data)
+        
+        
+
+class CalcCommandline:
+    def __init__(self, n=20000):
+        #print thread.get_ident()
+        from sans.models.CylinderModel import CylinderModel
+        from sans.models.DisperseModel import DisperseModel
+        import pylab
+        
+        submodel = CylinderModel()
+        
+        model = DisperseModel(submodel, ['cyl_phi', 'cyl_theta', 'length'],
+                                        [0.2, 0.2, 10.0])
+        model.setParam('n_pts', 10)
+         
+        print model.runXY([0.01, 0.02])
+        
+        qmax = 0.01
+        qstep = 0.0001
+        self.done = False
+        
+        x = pylab.arange(-qmax, qmax+qstep*0.01, qstep)
+        y = pylab.arange(-qmax, qmax+qstep*0.01, qstep)
+    
+        calc_thread_2D = Calc2D(x, y, model.clone(),-qmax, qmax,qstep,
+                                        completefn=self.complete,
+                                        updatefn=self.update ,
+                                        yieldtime=0.0)
+     
+        calc_thread_2D.queue()
+        calc_thread_2D.ready(2.5)
+        
+        while not self.done:
+            time.sleep(1)
+
+    def update(self,output):
+        print "update"
+
+    def complete(self, output, model, elapsed, qmin, qmax, qstep ):
+        print "complete"
+        self.done = True
+
+if __name__ == "__main__":
+    CalcCommandline()
+   
Index: sansview/perspectives/fitting/modelpage.py
===================================================================
--- sansview/perspectives/fitting/modelpage.py	(revision aae8d230f621cee2c473f36e74c8852df5447ff2)
+++ sansview/perspectives/fitting/modelpage.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
@@ -1,5 +1,5 @@
 import sys
 import wx
-import wx.lib
+import wx.lib.newevent
 import numpy
 import copy
@@ -28,5 +28,4 @@
     window_caption = "Fit Page"
     name=""
-    
     def __init__(self, parent,model,name, *args, **kwargs):
         wx.ScrolledWindow.__init__(self, parent, *args, **kwargs)
@@ -36,8 +35,7 @@
         # model on which the fit would be performed
         self.model=model
-        
-        ## Data member to store the dispersion object created
+        # Data member to store the dispersion object created
         self._disp_obj_dict = {}
-
+        self.back_up_model= model.clone()
         #list of dispersion paramaters
         self.disp_list=[]
@@ -86,13 +84,12 @@
         #------------------ sizer 4  draw------------------------  
        
-       
+        ## structure combox box
+        self.structbox = wx.ComboBox(self, -1)
         # define combox box
         self.modelbox = wx.ComboBox(self, -1)
-         # preview selected model name
-        self.prevmodel_name=name
-        #print "model view prev_model",name
-        self.modelbox.SetValue(self.prevmodel_name)
+        
         #enable model 2D draw
         self.enable2D= False
+        self.fitrange= True
         #filling sizer2
         ix = 0
@@ -102,4 +99,21 @@
         ix += 1
         self.sizer4.Add(self.modelbox,(iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        ix +=1
+        self.text_mult= wx.StaticText(self,-1,' x ')
+        self.sizer4.Add(self.text_mult,(iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        ix += 1
+        self.sizer4.Add(self.structbox,(iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+        
+        if hasattr(model ,"model2"):
+            name= model.model2.name
+
+            self.structbox.SetValue(name)          
+        if hasattr(model ,"model1"):
+            name= model.model1.name
+            items = self.modelbox.GetItems()
+            self.modelbox.SetValue(name)
+        else:
+            #print "model view prev_model",name
+            self.modelbox.SetValue( name )
         ix += 1
         id = wx.NewId()
@@ -190,20 +204,5 @@
         iy+=1 
         self.sizer9.Add((20,20),(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-        #----------sizer 10 draw------------------------------------------------------
-        """
-        id = wx.NewId()
-        self.btClose =wx.Button(self,id,'Close')
-        self.btClose.Bind(wx.EVT_BUTTON, self.onClose,id=id)
-        self.btClose.SetToolTipString("Close page.")
-        
-        ix= 3
-        iy= 1
-        self.sizer10.Add((20,20),(iy,ix),(1,1),wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
-        ix +=1
-        self.sizer10.Add( self.btClose,(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-        ix =0
-        iy+=1
-        self.sizer10.Add((20,20),(iy,ix),(1,1),wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
-        """
+        
         # contains link between  model ,all its parameters, and panel organization
         self.parameters=[]
@@ -221,5 +220,5 @@
             self.set_panel(self.model)
         self.theta_cb=None
-       
+        
        
         self.vbox.Layout()
@@ -231,29 +230,18 @@
         self.Layout()
         self.parent.GetSizer().Layout()
-        
-    def _set_dispersion(self, par, disp_model):
-        """
-            Utility method to set a dispersion model while making
-            sure that the dispersion model object doesn't go out
-            of scope. The models should be cleaned up so we don't
-            have to do this.
-        """
-        # Store the object to make it persist outside the scope of this method
-        #TODO: refactor model to clean this up?
-        self._disp_obj_dict[par] = disp_model
-                    
-        # Set the new model as the dispersion object for the selected parameter
-        self.model.set_dispersion(par, disp_model)
-        
-    def set_model_description(self, model):
-        
-        if model !=None and str(model.description)!=""and self.data==None:
-            self.sizer11.Clear(True)
-            self.box_description= wx.StaticBox(self, -1, 'Model Description')
-            boxsizer1 = wx.StaticBoxSizer(self.box_description, wx.VERTICAL)
-            boxsizer1.SetMinSize((320,20))
-            self.description = wx.StaticText(self,-1,str(model.description))
-            boxsizer1.Add(self.description, 0, wx.EXPAND)  
-            self.sizer11.Add(boxsizer1,1, wx.EXPAND | wx.ALL, 2)
+    def set_model_description(self, model=None):
+        
+        if model !=None:
+            description="description"
+        else:
+            description=""
+            if hasattr(model,description.lower())and self.data==None:
+                self.sizer11.Clear(True)
+                self.box_description= wx.StaticBox(self, -1, 'Model Description')
+                boxsizer1 = wx.StaticBoxSizer(self.box_description, wx.VERTICAL)
+                boxsizer1.SetMinSize((320,20))
+                self.description = wx.StaticText(self,-1,str(model.description))
+                boxsizer1.Add(self.description, 0, wx.EXPAND)  
+                self.sizer11.Add(boxsizer1,1, wx.EXPAND | wx.ALL, 2)
       
         
@@ -278,32 +266,38 @@
             @param page: the page to populate
         """
-        id=0
-        self.model_list_box=dict
-        list_name=[]
-        for item in  self.model_list_box.itervalues():
-            name = item.__name__
-            if hasattr(item, "name"):
-                name = item.name
-            list_name.append(name)
-        list_name.sort() 
-         
-        for name in list_name:
-            self.modelbox.Insert(name,int(id))
-            id+=1
-        wx.EVT_COMBOBOX(self.modelbox,-1, self._on_select_model) 
+        
+        self.model_list_box = dict.get_list()
+       
+        for item , mylist in self.model_list_box.iteritems():
+            separator= "---%s---"%item
+            self.modelbox.Append(separator,"separator")
+            
+            for models in mylist:
+                model= models()
+                name = model.__class__.__name__
+                if hasattr(model, "name"):
+                    name = model.name
+                self.modelbox.Append(name,models)
+            wx.EVT_COMBOBOX(self.modelbox,-1, self._on_select_model)
+            if item == "Structure Factors" :
+                for structs in mylist:
+                    struct= structs()
+                    name = struct.__class__.__name__
+                    if hasattr(struct, "name"):
+                        name = struct.name
+                    self.structbox.Append(name,structs)
+                wx.EVT_COMBOBOX(self.structbox,-1, self._on_select_model)
+        
+        
         return 0
     
 
     def Set_DipersParam(self, event):
-        """
-            This method is called when the user changes the state 
-            of the "dispersity" radio buttons.
-            
-            #TODO: correct the spelling mistake in the name of this method, start name with lowercase.
-        """
+        if self.model ==None:
+            msg= " Select non - model value:%s !"%self.model
+            wx.PostEvent(self.parent.parent, StatusEvent(status= msg))
+            return 
         if self.enable_disp.GetValue():
-            # The user selected to use dispersion/averaging
             if len(self.disp_list)==0:
-                # This model contains no parameter to which we can apply dispersion/averaging
                 ix=0
                 iy=1
@@ -319,18 +313,27 @@
                 return 
             else:
-                # Show the default dispersion/averaging sub-panel
+                if self.data !=None and self.model !=None: # allow to recognize data panel from model panel
+                    
+                
+                    self.cb1.SetValue(False)
+                    self.select_all_param_helper()
+                
                 self.populate_disp_box()
                 self.set_panel_dispers(self.disp_list)
                 
         else:
-            # The user selected not to use dispersion/averaging            
-            # Make sure all parameters have the default Gaussian
-            # dispersion object with only a single point (no dispersion).
-            for p in self.model.dispersion.keys():
-                disp_model = GaussianDispersion()
-                self._set_dispersion(p, disp_model)
-                    
-            # Redraw the model
-            self._draw_model()
+            if self.data !=None and self.model!=None:
+                if self.cb1.GetValue():
+                    self.select_all_param_helper()
+            
+            if self.back_up_model!=None:
+                keys = self.back_up_model.getDispParamList()
+                keys.sort()
+                #disperse param into the initial state
+                for item in keys:
+                    value= self.back_up_model.getParam(item)
+                    self.model.setParam(item, value)
+                self._draw_model() 
+            
                 
             self.fittable_param=[]        
@@ -359,5 +362,5 @@
             for k,v in self.polydisp.iteritems():
                 if str(v)=="MyModel":
-                    # Remove the option until the rest of the code is ready for it
+    				# Remove the option until the rest of the code is ready for it
                     #self.disp_box.Insert("Select customized Model",id)
                     pass  
@@ -433,8 +436,11 @@
         # If the 2D display is not currently enabled, plot the model in 2D 
         # and set the enable2D flag.
-        if self.enable2D==False:
-            self.enable2D=True
+        if self.fitrange:
+            self.enable2D = True
+            
+        if self.enable2D:
             self._draw_model()
             self.model_view.Disable()
+       
             
     
@@ -449,12 +455,28 @@
         
         self.set_panel(model)
-        self._draw_model(name)
-        
-        # Select the model from the combo box
-        items = self.modelbox.GetItems()
-        for i in range(len(items)):
-            if items[i]==name:
-                self.modelbox.SetSelection(i)
-                self.model_view.SetFocus()
+        self._draw_model()
+       
+        if hasattr(model ,"model2"):
+            name= model.model2.name
+            items = self.structbox.GetItems()
+            for i in range(len(items)):
+                if items[i]==name:
+                    self.structbox.SetSelection(i)
+                    
+        if hasattr(model ,"model1"):
+            name= model.model1.name
+            items = self.modelbox.GetItems()
+            for i in range(len(items)):
+                if items[i]==name:
+                    self.modelbox.SetSelection(i)
+        else:
+            # Select the model from the combo box
+            items = self.modelbox.GetItems()
+            for i in range(len(items)):
+                if items[i]==name:
+                    self.modelbox.SetSelection(i)
+            self.structbox.SetValue("No Structure")
+                    
+        self.model_view.SetFocus()
                 
     def _on_select_Disp(self,event):
@@ -478,19 +500,25 @@
         self.Layout()
         self.parent.GetSizer().Layout()
-        for item in self.model_list_box.itervalues():
-            name = item.__name__
-            if hasattr(item, "name"):
-                name = item.name
-            if name ==event.GetString():
-                model=item()
-                self.model= model
-                self.set_panel(model)
-                self.name= name
-                self.model_view.SetFocus()
-                self.parent.model_page.name=name
-                self.parent.draw_model_name=name
+        form_factor =self.modelbox.GetClientData(self.modelbox.GetCurrentSelection())
+        struct_factor =self.structbox.GetClientData(self.structbox.GetCurrentSelection())
+       
+        if form_factor!="separator":
+            if struct_factor != None and struct_factor.__name__ != "NoStructure":
+                from sans.models.MultiplicationModel import MultiplicationModel
+                self.model= MultiplicationModel(form_factor(),struct_factor())
+            else:
+                 self.model= form_factor()
+        else:
+            self.model=None 
+            msg= " Select non - model value:%s !Please select another model"%name 
+            wx.PostEvent(self.parent.parent, StatusEvent(status= msg))
                
-                self._draw_model(name)
-            
+        self.set_model_description(self.model)
+        self.set_panel(self.model)
+        self.name= self.model.name
+        self.model_view.SetFocus()
+        self.parent.model_page.name= self.name
+        self.parent.draw_model_name= self.name
+        self._draw_model()
             
     def get_model_box(self): 
@@ -522,97 +550,98 @@
         self.param_toFit=[]
         self.fixed_param=[]
-        self.model = model
-        
-        self.set_model_description( self.model) 
-        
-        keys = self.model.getParamList()
-        #list of dispersion paramaters
-        self.disp_list=self.model.getDispParamList()
-       
-        keys.sort()
-        ik=0
-        im=1
-        
-        iy = 1
-        ix = 0
-        self.cb1 = wx.CheckBox(self, -1,"Select all", (10, 10))
-        if self.data!=None:
-            wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_param)
-            self.cb1.SetValue(False)
-        else:
-            self.cb1.Disable()
-            self.cb1.Hide()
-       
-        self.sizer5.Add(self.cb1,(iy, ix),(1,1),\
-                          wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
-        ix +=1
-        self.text2_2 = wx.StaticText(self, -1, 'Values')
-        self.sizer5.Add(self.text2_2,(iy, ix),(1,1),\
-                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
-        ix +=2
-        self.text2_3 = wx.StaticText(self, -1, 'Errors')
-        self.sizer5.Add(self.text2_3,(iy, ix),(1,1),\
-                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-        self.text2_3.Hide() 
-        
-       
-        ix +=1
-        self.text2_4 = wx.StaticText(self, -1, 'Units')
-        self.sizer5.Add(self.text2_4,(iy, ix),(1,1),\
-                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
-        self.text2_4.Hide()
-        disp_list=self.model.getDispParamList()
-        for item in keys:
-            if not item in disp_list:
-                iy += 1
-                ix = 0
-    
-                cb = wx.CheckBox(self, -1, item, (10, 10))
-                if self.data!=None:
-                    cb.SetValue(False)
-                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
+        if model !=None:
+            self.model = model
+            
+            self.set_model_description( self.model) 
+            
+            keys = self.model.getParamList()
+            #list of dispersion paramaters
+            self.disp_list=self.model.getDispParamList()
+           
+            keys.sort()
+            ik=0
+            im=1
+            
+            iy = 1
+            ix = 0
+            self.cb1 = wx.CheckBox(self, -1,"Select all", (10, 10))
+            if self.data!=None:
+                wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_param)
+                self.cb1.SetValue(False)
+            else:
+                self.cb1.Disable()
+                self.cb1.Hide()
+           
+            self.sizer5.Add(self.cb1,(iy, ix),(1,1),\
+                              wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+            ix +=1
+            self.text2_2 = wx.StaticText(self, -1, 'Values')
+            self.sizer5.Add(self.text2_2,(iy, ix),(1,1),\
+                                wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
+            ix +=2
+            self.text2_3 = wx.StaticText(self, -1, 'Errors')
+            self.sizer5.Add(self.text2_3,(iy, ix),(1,1),\
+                                wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+            self.text2_3.Hide() 
+            
+           
+            ix +=1
+            self.text2_4 = wx.StaticText(self, -1, 'Units')
+            self.sizer5.Add(self.text2_4,(iy, ix),(1,1),\
+                                wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
+            self.text2_4.Hide()
+            disp_list=self.model.getDispParamList()
+            for item in keys:
+                if not item in disp_list:
+                    iy += 1
+                    ix = 0
+        
+                    cb = wx.CheckBox(self, -1, item, (10, 10))
+                    if self.data!=None:
+                        cb.SetValue(False)
+                        wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
+                    else:
+                        cb.Disable()
+                    self.sizer5.Add( cb,( iy, ix),(1,1),  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+                   
+                    ix += 1
+                    value= self.model.getParam(item)
+                    ctl1 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=wx.TE_PROCESS_ENTER)
+                    ctl1.SetValue(str (format_number(value)))
+                    ctl1.Bind(wx.EVT_KILL_FOCUS, self._onparamEnter)
+                    ctl1.Bind(wx.EVT_TEXT_ENTER,self._onparamEnter)
+                    self.sizer5.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
+                    
+                    ix += 1
+                    text2=wx.StaticText(self, -1, '+/-')
+                    self.sizer5.Add(text2,(iy, ix),(1,1),\
+                                    wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
+                    text2.Hide()  
+                    ix += 1
+                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=wx.TE_PROCESS_ENTER)
+                    self.sizer5.Add(ctl2, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+                    ctl2.Hide()
+                   
+                    ix +=1
+                    # Units
+                    try:
+                        units = wx.StaticText(self, -1, self.model.details[item][0], style=wx.ALIGN_LEFT)
+                    except:
+                        units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
+                    self.sizer5.Add(units, (iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+               
+                    self.parameters.append([cb,ctl1,text2,ctl2])
+                    
+            iy+=1
+            self.sizer5.Add((20,20),(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
+            
+            #Display units text on panel
+            for item in keys:   
+                if self.model.details[item][0]!='':
+                    self.text2_4.Show()
+                    break
                 else:
-                    cb.Disable()
-                self.sizer5.Add( cb,( iy, ix),(1,1),  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
-               
-                ix += 1
-                value= self.model.getParam(item)
-                ctl1 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=wx.TE_PROCESS_ENTER)
-                ctl1.SetValue(str (format_number(value)))
-                ctl1.Bind(wx.EVT_KILL_FOCUS, self._onparamEnter)
-                ctl1.Bind(wx.EVT_TEXT_ENTER,self._onparamEnter)
-                self.sizer5.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
-                
-                ix += 1
-                text2=wx.StaticText(self, -1, '+/-')
-                self.sizer5.Add(text2,(iy, ix),(1,1),\
-                                wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
-                text2.Hide()  
-                ix += 1
-                ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=wx.TE_PROCESS_ENTER)
-                self.sizer5.Add(ctl2, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-                ctl2.Hide()
-               
-                ix +=1
-                # Units
-                try:
-                    units = wx.StaticText(self, -1, self.model.details[item][0], style=wx.ALIGN_LEFT)
-                except:
-                    units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
-                self.sizer5.Add(units, (iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
-           
-                self.parameters.append([cb,ctl1,text2,ctl2])
-                
-        iy+=1
-        self.sizer5.Add((20,20),(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
-        
-        #Display units text on panel
-        for item in keys:   
-            if self.model.details[item][0]!='':
-                self.text2_4.Show()
-                break
-            else:
-                self.text2_4.Hide()
-        
+                    self.text2_4.Hide()
+            
         self.vbox.Layout()
         self.SetScrollbars(20,20,55,40)
@@ -700,11 +729,13 @@
                     
                     # Create the dispersion objects
-                    # Store the objects to make them persist outside the scope of this method
-			        #TODO: refactor model to clean this up?
-                    self._disp_obj_dict[p+'values']  = values
-                    self._disp_obj_dict[p+'weights'] = weights
                     disp_model = ArrayDispersion()
                     disp_model.set_weights(values, weights)
-                    self._set_dispersion(p, disp_model)
+                    # 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
+                    
+                    # Set the new model as the dispersion object for the selected parameter
+                    self.model.set_dispersion(p, disp_model)
+                    
                     
                     # Redraw the model
@@ -714,5 +745,10 @@
                     # The parameter was un-selected. Go back to Gaussian model (with 0 pts)
                     disp_model = GaussianDispersion()
-                    self._set_dispersion(p, disp_model)
+                    # 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
+                    
+                    # Set the new model as the dispersion object for the selected parameter
+                    self.model.set_dispersion(p, disp_model)
                     
                     # Redraw the model
@@ -733,5 +769,4 @@
         iy=1
                 ### this will become a separate method
-        #TODO: don't hard code text values to be shown on the interface
         if type== "Select customized Model":
             ix=0
@@ -787,11 +822,4 @@
                 name3=item+".nsigmas"
                 iy += 1
-                
-                # Make sure the dispersion model is Gaussian
-                if not self.model.dispersion[item]['type'] == 'gaussian': 
-                    disp_model = GaussianDispersion()
-                    self._set_dispersion(item, disp_model)
-                
-                # Create the interface
                 for p in self.model.dispersion[item].keys():
                     #print "name 1 2 3", name1, name2, name3
@@ -966,11 +994,15 @@
             # If qmin and qmax have been modified, update qmin and qmax and 
             # set the is_modified flag to True
-            if float(self.qmin.GetValue()) != self.qmin_x:
-                self.qmin_x = float(self.qmin.GetValue())
-                is_modified = True
-            if float(self.qmax.GetValue()) != self.qmax_x:
-                self.qmax_x = float(self.qmax.GetValue())
-                is_modified = True
-            
+            from sans.guiframe.utils import check_value
+            if check_value( self.qmin, self.qmax):
+                if float(self.qmin.GetValue()) != self.qmin_x:
+                    self.qmin_x = float(self.qmin.GetValue())
+                    is_modified = True
+                if float(self.qmax.GetValue()) != self.qmax_x:
+                    self.qmax_x = float(self.qmax.GetValue())
+                    is_modified = True
+                self.fitrange = True
+            else:
+                self.fitrange = False
             if float(self.npts.GetValue()) !=  self.num_points:
                 self.num_points = float(self.npts.GetValue())
@@ -980,5 +1012,5 @@
                 self._draw_model()            
             
-    def _draw_model(self, name=None):
+    def _draw_model(self):
         """
             Method to draw or refresh a plotted model.
@@ -988,11 +1020,9 @@
             [Note to coder: This way future changes will be done in only one place.] 
         """
-        if name==None:
-            name= self.model.name
-       
-        self.manager.draw_model(self.model, name, data=self.data,
-                                qmin=self.qmin_x, qmax=self.qmax_x,
-                                qstep= self.num_points,
-                                enable2D=self.enable2D)
+        if self.model !=None:
+            self.manager.draw_model(self.model, self.model.name, data=self.data,
+                                    qmin=self.qmin_x, qmax=self.qmax_x,
+                                    qstep= self.num_points,
+                                    enable2D=self.enable2D)
        
     def select_param(self,event):
Index: sansview/perspectives/fitting/models.py
===================================================================
--- sansview/perspectives/fitting/models.py	(revision 43eb424f5a09e03e91b6684e745efac7ac8dcb2f)
+++ sansview/perspectives/fitting/models.py	(revision bb18ef1c74ed79eb0630f198735ad2b14e7913ab)
@@ -10,4 +10,5 @@
 
 import wx
+import wx.lib.newevent
 import imp
 import os,sys,math
@@ -66,14 +67,43 @@
         pass
     return plugins
+
+class ModelList(object):
+    """
+        Contains dictionary of model and their type
+    """
+    def __init__(self):
+        self.mydict={}
+        
+    def set_list(self, name, mylist):
+        """
+            @param name: the type of the list
+            @param mylist: the list to add
+        """
+        if name not in self.mydict.keys():
+            self.mydict[name] = mylist
+            
+            
+    def get_list(self):
+        """
+         return all the list stored in a dictionary object
+        """
+        return self.mydict
+        
 class ModelManager:
-    
-    ## Dictionary of models
-    model_list = {}
-    indep_model_list = {}
-    model_list_box = {}
-    custom_models={}
+    ## external dict for models
+    model_combobox = ModelList()
+    ## Dictionary of form models
+    form_factor_dict = {}
+    ## dictionary of other
+    struct_factor_dict = {}
+    ##list of form factors
+    shape_list =[]
+    ## independent shape model list
+    shape_indep_list = []
+    ##list of structure factors 
+    struct_list= []
+    ## list of added models
     plugins=[]
-    indep_model=[]
-    ## Event owner
+    ## Event owner (guiframe)
     event_owner = None
     
@@ -86,55 +116,58 @@
             @return: the next free event ID following the new menu events
         """
-        self.model_list = {}
-        self.model_list_box = {}
-       
-        
+        ## form factor
         from sans.models.SphereModel import SphereModel
-        self.model_list[str(wx.NewId())] =  SphereModel
+        self.shape_list.append(SphereModel)
         
         from sans.models.CylinderModel import CylinderModel
-        self.model_list[str(wx.NewId())] =CylinderModel
+        self.shape_list.append(CylinderModel)
       
         from sans.models.CoreShellModel import CoreShellModel
-        self.model_list[str(wx.NewId())] = CoreShellModel 
+        self.shape_list.append(CoreShellModel)
         
         from sans.models.CoreShellCylinderModel import CoreShellCylinderModel
-        self.model_list[str(wx.NewId())] =CoreShellCylinderModel
+        self.shape_list.append(CoreShellCylinderModel)
         
         from sans.models.EllipticalCylinderModel import EllipticalCylinderModel
-        self.model_list[str(wx.NewId())] =EllipticalCylinderModel
+        self.shape_list.append(EllipticalCylinderModel)
         
         from sans.models.EllipsoidModel import EllipsoidModel
-        self.model_list[str(wx.NewId())] = EllipsoidModel 
+        self.shape_list.append(EllipsoidModel)
+         
+        from sans.models.LineModel import LineModel
+        self.shape_list.append(LineModel)
+        
+        ## Structure factor 
+        from sans.models.NoStructure import NoStructure
+        self.struct_list.append(NoStructure)
         
         from sans.models.SquareWellStructure import SquareWellStructure
-        self.model_list[str(wx.NewId())] =  SquareWellStructure
+        self.struct_list.append(SquareWellStructure)
         
         from sans.models.HardsphereStructure import HardsphereStructure
-        self.model_list[str(wx.NewId())] =  HardsphereStructure
-        
+        self.struct_list.append(HardsphereStructure)
+         
         from sans.models.StickyHSStructure import StickyHSStructure
-        self.model_list[str(wx.NewId())] =  StickyHSStructure
+        self.struct_list.append(StickyHSStructure)
         
         from sans.models.HayterMSAStructure import HayterMSAStructure
-        self.model_list[str(wx.NewId())] =  HayterMSAStructure
-        
-        from sans.models.LineModel import LineModel
-        self.model_list[str(wx.NewId())]  = LineModel
-        
-        
-        model_info="shape-independent models"
-        
+        self.struct_list.append(HayterMSAStructure)
+        
+        
+        ##shape-independent models
         from sans.models.BEPolyelectrolyte import BEPolyelectrolyte
-        self.indep_model.append(BEPolyelectrolyte )
-        
+        self.shape_indep_list.append(BEPolyelectrolyte )
+        self.form_factor_dict[str(wx.NewId())] =  [SphereModel]
         from sans.models.DABModel import DABModel
-        self.indep_model.append(DABModel )
+        self.shape_indep_list.append(DABModel )
         
         from sans.models.GuinierModel import GuinierModel
-        self.indep_model.append(GuinierModel )
+        self.shape_indep_list.append(GuinierModel )
         
         from sans.models.DebyeModel import DebyeModel
-        self.indep_model.append(DebyeModel )
+        self.shape_indep_list.append(DebyeModel )
+        
+        from sans.models.PorodModel import PorodModel
+        self.shape_indep_list.append(PorodModel )
         
         from sans.models.FractalModel import FractalModel
@@ -142,8 +175,8 @@
             def _Fractal(self, x):
                 return FractalModel._Fractal(self, math.fabs(x))
-        self.indep_model.append(FractalAbsModel)
+        self.shape_indep_list.append(FractalAbsModel)
         
         from sans.models.LorentzModel import LorentzModel
-        self.indep_model.append( LorentzModel) 
+        self.shape_indep_list.append( LorentzModel) 
             
         from sans.models.PowerLawModel import PowerLawModel
@@ -154,7 +187,7 @@
                 except:
                     print sys.exc_value  
-        self.indep_model.append( PowerLawAbsModel )
+        self.shape_indep_list.append( PowerLawAbsModel )
         from sans.models.TeubnerStreyModel import TeubnerStreyModel
-        self.indep_model.append(TeubnerStreyModel )
+        self.shape_indep_list.append(TeubnerStreyModel )
     
         #Looking for plugins
@@ -173,49 +206,102 @@
             @return: the next free event ID following the new menu events
         """
+        ## Fill model lists
         self._getModelList()
+        ## store reference to model menu of guiframe
+        self.modelmenu = modelmenu
+        ## guiframe reference
         self.event_owner = event_owner
-        shape_submenu= wx.Menu() 
-        indep_submenu = wx.Menu()
+        
+        
+        shape_submenu = wx.Menu()
+        shape_indep_submenu = wx.Menu()
+        structure_factor = wx.Menu()
         added_models = wx.Menu()
-        for id_str,value in self.model_list.iteritems():
-            item = self.model_list[id_str]()
-            name = item.__class__.__name__
-            if hasattr(item, "name"):
-                name = item.name
-            self.model_list_box[name] =value
-            shape_submenu.Append(int(id_str), name, name)
-            wx.EVT_MENU(event_owner, int(id_str), self._on_model)
-        modelmenu.AppendMenu(wx.NewId(), "Shapes...", shape_submenu, "List of shape-based models")
-        id = wx.NewId()
-        if len(self.indep_model_list) == 0:
-            for items in self.indep_model:
-                #if item not in self.indep_model_list.values():
-                    #self.indep_model_list[str(id)] = item
-                self.model_list[str(id)]=items
-                item=items()
-                name = item.__class__.__name__
-                if hasattr(item, "name"):
-                    name = item.name
-                indep_submenu.Append(id,name, name)
-                self.model_list_box[name] =items
-                wx.EVT_MENU(event_owner, int(id), self._on_model)
-                id = wx.NewId()         
-        modelmenu.AppendMenu(wx.NewId(), "Shape-independent...", indep_submenu, "List of shape-independent models")
-        id = wx.NewId()
-        if len(self.custom_models) == 0:
-            for items in self.plugins:
-                #if item not in self.custom_models.values():
-                    #self.custom_models[str(id)] = item
-                self.model_list[str(id)]=items
-                name = items.__name__
-                if hasattr(items, "name"):
-                    name = items.name
-                added_models.Append(id, name, name)
-                self.model_list_box[name] =items
-                wx.EVT_MENU(event_owner, int(id), self._on_model)
-                id = wx.NewId()
-        modelmenu.AppendMenu(wx.NewId(),"Added models...", added_models, "List of additional models")
+        ## create menu with shape
+        self._fill_menu( menuinfo = ["shapes",shape_submenu," simple shape"],
+                         list1 = self.shape_list,
+                         list2 = self.struct_list )
+        self._fill_menu( menuinfo = ["Shape-independent",shape_indep_submenu,
+                                    "List of shape-independent models"],
+                         list1 = self.shape_indep_list,
+                         list2 = self.struct_list )
+        
+        self._fill_simple_menu( menuinfo= ["Structure Factors",structure_factor,
+                                          "List of Structure factors models" ],
+                                list1= self.struct_list )
+        
+        self._fill_simple_menu( menuinfo = ["Added models", added_models,
+                                            "List of additional models"],
+                                 list1= self.plugins)
         return 0
     
+    def _fill_simple_menu(self,menuinfo, list1):
+        """
+            Fill the menu with list item
+            @param modelmenu: the menu to fill
+            @param menuinfo: submenu item for the first column of this modelmenu
+                             with info.Should be a list :
+                             [name(string) , menu(wx.menu), help(string)]
+            @param list1: contains item (form factor )to fill modelmenu second column
+        """
+        if len(list1)>0:
+            self.model_combobox.set_list(menuinfo[0],list1)
+              
+            for item in list1:
+                id = wx.NewId() 
+                struct_factor=item()
+                struct_name = struct_factor.__class__.__name__
+                if hasattr(struct_factor, "name"):
+                    struct_name = struct_factor.name
+                    
+                menuinfo[1].Append(int(id),struct_name,struct_name)
+                if not  item in self.struct_factor_dict.itervalues():
+                    self.struct_factor_dict[str(id)]= item
+                wx.EVT_MENU(self.event_owner, int(id), self._on_model)
+                
+        id = wx.NewId()         
+        self.modelmenu.AppendMenu(id, menuinfo[0],menuinfo[1],menuinfo[2])
+        
+        
+        
+    def _fill_menu(self,menuinfo, list1,list2  ):
+        """
+            Fill the menu with list item
+            @param menuinfo: submenu item for the first column of this modelmenu
+                             with info.Should be a list :
+                             [name(string) , menu(wx.menu), help(string)]
+            @param list1: contains item (form factor )to fill modelmenu second column
+            @param list2: contains item (Structure factor )to fill modelmenu third column
+        """
+        if len(list1)>0:
+            self.model_combobox.set_list(menuinfo[0],list1)
+            
+            for item in list1:   
+                form_factor= item()
+                form_name = form_factor.__class__.__name__
+                if hasattr(form_factor, "name"):
+                    form_name = form_factor.name
+                ### store form factor to return to other users   
+                newmenu= wx.Menu()
+                if len(list2)>0:
+                    for model  in list2:
+                        id = wx.NewId()
+                        struct_factor = model()
+                        name = struct_factor.__class__.__name__
+                        if hasattr(struct_factor, "name"):
+                            name = struct_factor.name
+                        newmenu.Append(id,name, name)
+                        wx.EVT_MENU(self.event_owner, int(id), self._on_model)
+                        ## save form_fact and struct_fact
+                        self.form_factor_dict[int(id)] = [form_factor,struct_factor]
+                        
+                form_id= wx.NewId()    
+                menuinfo[1].AppendMenu(int(form_id), form_name,newmenu,menuinfo[2])
+        id=wx.NewId()
+        self.modelmenu.AppendMenu(id,menuinfo[0],menuinfo[1], menuinfo[2])
+        
+        
+        
+        
     def _on_model(self, evt):
         """
@@ -223,20 +309,25 @@
             @param event: wx menu event
         """
-        if str(evt.GetId()) in self.model_list.keys():
-            # Notify the application manager that a new model has been set
-            #self.app_manager.set_model(self.model_list[str(evt.GetId())]())
-            
-            #TODO: post a model event to update all panels that need
-            #evt = ModelEvent(model=self.model_list[str(evt.GetId())]())
-           
-            model = self.model_list[str(evt.GetId())]
-            evt = ModelEvent(model= model )
-            wx.PostEvent(self.event_owner, evt)
+        if int(evt.GetId()) in self.form_factor_dict.keys():
+            from sans.models.MultiplicationModel import MultiplicationModel
+            model1, model2 = self.form_factor_dict[int(evt.GetId())]
+            model = MultiplicationModel(model1, model2)
+               
+        else:
+            model= self.struct_factor_dict[str(evt.GetId())]()
+            
+        evt = ModelEvent( model= model )
+        wx.PostEvent(self.event_owner, evt)
         
     def get_model_list(self):    
         """ @ return dictionary of models for fitpanel use """
-        return self.model_list_box
-    
-    
-    
- 
+        return self.model_combobox
+    
+    
+    def get_form_struct(self):
+        """ retunr list of form structures"""
+        return self.struct_list
+        
+    
+    
+  
