Index: src/sas/qtgui/MainWindow/DataExplorer.py
===================================================================
--- src/sas/qtgui/MainWindow/DataExplorer.py	(revision 3b95b3bf18e0282898b94748d7c29f60e7fb5b20)
+++ src/sas/qtgui/MainWindow/DataExplorer.py	(revision 345b3b382101552fe1f6febd4afefb152aa1765e)
@@ -233,43 +233,5 @@
         filename = QtWidgets.QFileDialog.getOpenFileName(**kwargs)[0]
         if filename:
-            load_thread = threads.deferToThread(self.readProject, filename)
-            load_thread.addCallback(self.readProjectComplete)
-            load_thread.addErrback(self.readProjectFailed)
-
-    def loadFailed(self, reason):
-        """
-        """
-        print("file load FAILED: ", reason)
-        pass
-
-    def readProjectFailed(self, reason):
-        """
-        """
-        print("readProjectFailed FAILED: ", reason)
-        pass
-
-    def readProject(self, filename):
-        self.communicator.statusBarUpdateSignal.emit("Loading Project... %s" % os.path.basename(filename))
-        try:
-            manager = DataManager()
-            with open(filename, 'r') as infile:
-                manager.load_from_readable(infile)
-
-            self.communicator.statusBarUpdateSignal.emit("Loaded Project: %s" % os.path.basename(filename))
-            return manager
-
-        except:
-            self.communicator.statusBarUpdateSignal.emit("Failed: %s" % os.path.basename(filename))
-            raise
-
-    def readProjectComplete(self, manager):
-        self.model.clear()
-
-        self.manager.assign(manager)
-        self.model.beginResetModel()
-        for id, item in self.manager.get_all_data().items():
-            self.updateModel(item.data, item.path)
-
-        self.model.endResetModel()
+            self.readProject(filename)
 
     def saveProject(self):
@@ -285,11 +247,94 @@
         name_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs)
         filename = name_tuple[0]
-        if filename:
-            _, extension = os.path.splitext(filename)
-            if not extension:
-                filename = '.'.join((filename, 'json'))
-            self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename))
-            with open(filename, 'w') as outfile:
-                self.manager.save_to_writable(outfile)
+        if not filename:
+            return
+        _, extension = os.path.splitext(filename)
+        if not extension:
+            filename = '.'.join((filename, 'json'))
+        self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename))
+
+        with open(filename, 'w') as outfile:
+            self.saveDataToFile(outfile)
+
+    def allDataForModel(self, model):
+        # data model
+        all_data = {}
+        for i in range(model.rowCount()):
+            properties = {}
+            item = model.item(i)
+            data = GuiUtils.dataFromItem(item)
+            if data is None: continue
+            # Now, all plots under this item
+            filename = data.filename
+            is_checked = item.checkState()
+            properties['checked'] = is_checked
+            other_datas = GuiUtils.plotsFromFilename(filename, model)
+            # skip the main plot
+            other_datas = list(other_datas.values())[1:]
+            all_data[data.id] = [data, properties, other_datas]
+        return all_data
+
+    def saveDataToFile(self, outfile):
+        """
+        Save every dataset to a json file
+        """
+        data = self.allDataForModel(self.model)
+        theory = self.allDataForModel(self.theory_model)
+
+        all_data = {}
+        for key, value in data.items():
+            all_data[key] = value
+        for key, value in theory.items():
+            if key in all_data:
+                raise ValueError("Inconsistent data in Project file.")
+            all_data[key] = value
+
+        # perspectives
+        current_perspective = self._perspective()
+        try:
+            perspective_dump = current_perspective.getCurrentStateAsXml()
+        except Exception:
+            ex = "State of " + current_perspective.windowTitle() + \
+                " cannot be saved."
+            logging.error(ex)
+        if perspective_dump is not None:
+            assert(isinstance(perspective_dump, dict))
+            all_data['perspective'] = perspective_dump
+        # save datas
+        GuiUtils.saveData(outfile, all_data)
+        return
+
+    def readProject(self, filename):
+        """
+        Read out datasets and fitpages from file
+        """
+        with open(filename, 'r') as infile:
+            all_data = GuiUtils.readDataFromFile(infile)
+        # clear the model
+        self.model.clear()
+
+        #self.model.beginResetModel()
+        for key, value in all_data.items():
+            # key - cardinal number of dataset
+            # value - main dataset, [dependant filesets]
+            # add the main index
+            new_data = value[0]
+            assert isinstance(new_data, (Data1D, Data2D))
+            properties = value[1]
+            is_checked = properties['checked']
+            new_item = GuiUtils.createModelItemWithPlot(new_data, new_data.filename)
+            new_item.setCheckState(is_checked)
+            model = self.theory_model
+            if new_data.is_data:
+                model = self.model
+            model.appendRow(new_item)
+            self.manager.add_data(data_list={new_data.id:new_data})
+
+            # Add the underlying data
+            if not value[2]:
+                continue
+            for plot in value[2]:
+                assert isinstance(plot, (Data1D, Data2D))
+                GuiUtils.updateModelItemWithPlot(new_item, plot, plot.name)
 
     def deleteFile(self, event):
@@ -1394,5 +1439,6 @@
         checkbox_item.setCheckable(True)
         checkbox_item.setCheckState(QtCore.Qt.Checked)
-        checkbox_item.setText(os.path.basename(p_file))
+        if p_file is not None:
+            checkbox_item.setText(os.path.basename(p_file))
 
         # Add the actual Data1D/Data2D object
Index: src/sas/qtgui/MainWindow/DataManager.py
===================================================================
--- src/sas/qtgui/MainWindow/DataManager.py	(revision e2e5f3d84e3cde792395c3cd184a5bba1eeb5873)
+++ src/sas/qtgui/MainWindow/DataManager.py	(revision 345b3b382101552fe1f6febd4afefb152aa1765e)
@@ -29,5 +29,4 @@
 from sas.qtgui.Plotting.PlotterData import Data1D
 from sas.qtgui.Plotting.PlotterData import Data2D
-from sas.qtgui.Plotting.Plottables import Plottable
 from sas.qtgui.Plotting.Plottables import PlottableTheory1D
 from sas.qtgui.Plotting.Plottables import PlottableFit1D
