Index: src/sas/sasgui/perspectives/fitting/fitting.py
===================================================================
--- src/sas/sasgui/perspectives/fitting/fitting.py	(revision ca4d9854c75a5344e770dec25221dfeb5a270915)
+++ src/sas/sasgui/perspectives/fitting/fitting.py	(revision e89aed5c946bf39b3cb963b0c7805341c30d2432)
@@ -593,9 +593,11 @@
         : param datainfo: data
         """
-        #state = self.state_reader.get_state()
-        if state != None:
+        from pagestate import PageState
+        from simfitpage import SimFitPageState
+        if isinstance(state, PageState):
             state = state.clone()
-            # store fitting state in temp_state
             self.temp_state.append(state)
+        elif isinstance(state, SimFitPageState):
+            state.load_from_save_state(self)
         else:
             self.temp_state = []
Index: src/sas/sasgui/perspectives/fitting/pagestate.py
===================================================================
--- src/sas/sasgui/perspectives/fitting/pagestate.py	(revision a95ae9a74d8ba4ec9ee4b79e7e55739860f0b63f)
+++ src/sas/sasgui/perspectives/fitting/pagestate.py	(revision e89aed5c946bf39b3cb963b0c7805341c30d2432)
@@ -860,5 +860,4 @@
         :param file: .fitv file
         :param node: node of a XML document to read from
-
         """
         if file is not None:
@@ -867,5 +866,5 @@
             raise RuntimeError, msg
 
-        if node.get('version')and node.get('version') == '1.0':
+        if node.get('version') and node.get('version') == '1.0':
 
             # Get file name
@@ -1272,5 +1271,4 @@
 
         :param entry: XML node to read from
-
         :return: PageState object
         """
@@ -1281,5 +1279,5 @@
             nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME,
                                 namespaces={'ns': CANSAS_NS})
-            if nodes != []:
+            if nodes:
                 # Create an empty state
                 state = PageState()
@@ -1291,4 +1289,43 @@
 
         return state
+
+    def _parse_simfit_state(self, entry):
+        """
+        Parses the saved data for a simultaneous fit
+        :param entry: XML object to read from
+        :return: XML object for a simultaneous fit or None
+        """
+        nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME,
+                            namespaces={'ns': CANSAS_NS})
+        if nodes:
+            simfitstate = nodes[0].xpath('ns:simultaneous_fit',
+                                         namespaces={'ns': CANSAS_NS})
+            if simfitstate:
+                from simfitpage import SimFitPageState
+                sim_fit_state = SimFitPageState()
+                simfitstate_0 = simfitstate[0]
+                all = simfitstate_0.xpath('ns:select_all',
+                                        namespaces={'ns': CANSAS_NS})
+                atts = all[0].attrib
+                checked = atts.get('checked')
+                sim_fit_state.select_all = bool(checked)
+                model_list = simfitstate_0.xpath('ns:model_list',
+                                               namespaces={'ns': CANSAS_NS})
+                model_list_items = model_list[0].xpath('ns:model_list_item',
+                                                       namespaces={'ns': CANSAS_NS})
+                for model in model_list_items:
+                    attrs = model.attrib
+                    sim_fit_state.model_list.append(attrs)
+                constraints = simfitstate_0.xpath('ns:constraints',
+                                                namespaces={'ns': CANSAS_NS})
+                constraint_list = constraints[0].xpath('ns:constraint',
+                                                       namespaces={'ns': CANSAS_NS})
+                for constraint in constraint_list:
+                    attrs = constraint.attrib
+                    sim_fit_state.constraints_list.append(attrs)
+
+                return sim_fit_state
+            else:
+                return None
 
     def _parse_save_state_entry(self, dom):
@@ -1552,17 +1589,15 @@
     def _read_cansas(self, path):
         """
-        Load data and P(r) information from a CanSAS XML file.
+        Load data and fitting information from a CanSAS XML file.
 
         :param path: file path
-
         :return: Data1D object if a single SASentry was found,
                     or a list of Data1D objects if multiple entries were found,
                     or None of nothing was found
-
         :raise RuntimeError: when the file can't be opened
         :raise ValueError: when the length of the data vectors are inconsistent
-
         """
         output = []
+        simfitstate = None
         basename = os.path.basename(path)
         root, extension = os.path.splitext(basename)
@@ -1584,4 +1619,5 @@
                             raise
                         fitstate = self._parse_state(entry)
+                        simfitstate = self._parse_simfit_state(entry)
 
                         # state could be None when .svs file is loaded
@@ -1591,4 +1627,5 @@
                             sas_entry.filename = fitstate.file
                             output.append(sas_entry)
+
             else:
                 self.call_back(format=ext)
@@ -1634,4 +1671,7 @@
                                    datainfo=output[ind], format=ext)
                     self.state = state
+                if simfitstate is not None:
+                    self.call_back(state=simfitstate)
+
                 return output
         except:
Index: src/sas/sasgui/perspectives/fitting/simfitpage.py
===================================================================
--- src/sas/sasgui/perspectives/fitting/simfitpage.py	(revision a95ae9a74d8ba4ec9ee4b79e7e55739860f0b63f)
+++ src/sas/sasgui/perspectives/fitting/simfitpage.py	(revision e89aed5c946bf39b3cb963b0c7805341c30d2432)
@@ -768,4 +768,5 @@
         """
         Show constraint fields
+        :param dict: dictionary mapping constraint values
         """
         self.btAdd.Show(True)
@@ -871,5 +872,5 @@
     def _on_select_model(self, event):
         """
-        fill combox box with list of parameters
+        fill combo box with list of parameters
         """
         if not self.constraints_list:
@@ -1041,2 +1042,88 @@
         # List of constraints
         self.constraints_list = []
+
+    def load_from_save_state(self, fit):
+        """
+        Load in a simultaneous/constrained fit from a save state
+        :param fit: Fitpanel object
+        :return: None
+        """
+
+        model_map = {}
+        fit.fit_panel.add_sim_page()
+
+        # Process each model and associate old M# with new M#
+        i = 0
+        for model in fit.fit_panel.sim_page.model_list:
+            model_id = self._format_id(model[1].keys()[0])
+            for saved_model in self.model_list:
+                save_id = saved_model.pop('name')
+                saved_model['name'] = save_id
+                save_id = self._format_id(save_id)
+                if save_id == model_id:
+                    model_map[saved_model.pop('fit_page_source')] = \
+                        model[3].name
+                    check = bool(saved_model.pop('checked'))
+                    fit.fit_panel.sim_page.model_list[i][0].SetValue(check)
+                    continue
+            i += 1
+        fit.fit_panel.sim_page.check_model_name(None)
+
+        if len(self.constraints_list) > 0:
+            fit.fit_panel.sim_page.hide_constraint.SetValue(False)
+            fit.fit_panel.sim_page.show_constraint.SetValue(True)
+            fit.fit_panel.sim_page._display_constraint(None)
+
+        for constraint in self.constraints_list:
+            model_cbox = constraint.pop('model_cbox')
+            constraint_value = constraint.pop('constraint')
+            for key, value in model_map.iteritems():
+                model_cbox.replace(key, value)
+                constraint_value.replace(key, value)
+
+            bt_remove = wx.Button(fit.fit_panel.sim_page,
+                                  fit.fit_panel.sim_page._ids.next(), 'Remove')
+            bt_remove.Bind(wx.EVT_BUTTON, fit.fit_panel.sim_page.on_remove,
+                           id=bt_remove.GetId())
+            bt_remove.SetToolTipString("Remove constraint.")
+            param_cbox = wx.ComboBox(fit.fit_panel.sim_page, wx.ID_ANY,
+                                     style=wx.CB_READONLY, size=(100, -1))
+            egal_txt = wx.StaticText(fit.fit_panel.sim_page, wx.ID_ANY, " = ")
+            # Model list
+            model_cbox_sizer = wx.ComboBox(fit.fit_panel.sim_page,
+                                           wx.ID_ANY, style=wx.CB_READONLY)
+            model_cbox_sizer.Clear()
+            wx.EVT_COMBOBOX(model_cbox_sizer, wx.ID_ANY,
+                            fit.fit_panel.sim_page._on_select_model)
+            constraint_sizer = wx.TextCtrl(fit.fit_panel.sim_page, wx.ID_ANY)
+            sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
+            sizer_constraint.Add((5, -1))
+            sizer_constraint.Add(model_cbox_sizer, flag=wx.RIGHT | wx.EXPAND,
+                                 border=10)
+            sizer_constraint.Add(param_cbox, flag=wx.RIGHT | wx.EXPAND,
+                                 border=5)
+            sizer_constraint.Add(egal_txt, flag=wx.RIGHT | wx.EXPAND, border=5)
+            sizer_constraint.Add(constraint_sizer, flag=wx.RIGHT | wx.EXPAND,
+                                 border=10)
+            sizer_constraint.Add(bt_remove, flag=wx.RIGHT | wx.EXPAND,
+                                 border=10)
+            new_const = ConstraintLine(model_cbox=model_cbox_sizer,
+                                       param_cbox=constraint.pop('param_cbox'),
+                                       egal_txt=constraint.pop('egal_txt'),
+                                       constraint=constraint_value,
+                                       btRemove=bt_remove,
+                                       sizer=sizer_constraint
+                                       )
+            # ConstraintLine = namedtuple('ConstraintLine',
+            #      'model_cbox param_cbox egal_txt constraint btRemove sizer')
+            fit.fit_panel.sim_page.sizer_constraints.Insert(
+                before=fit.fit_panel.sim_page.nb_constraint,
+                item=sizer_constraint, flag=wx.TOP | wx.BOTTOM | wx.EXPAND,
+                border=5)
+            fit.fit_panel.sim_page.constraints_list.append(new_const)
+
+    def _format_id(self, original_id):
+        original_id = original_id.rstrip('1234567890.')
+        new_id_list = original_id.split()
+        new_id = ' '.join(new_id_list)
+        return new_id
