Index: src/sas/qtgui/MainWindow/AboutBox.py
===================================================================
--- src/sas/qtgui/MainWindow/AboutBox.py	(revision b3e8629bf18b74f4214d6552e620fcbc4e73a28c)
+++ src/sas/qtgui/MainWindow/AboutBox.py	(revision 4992ff2626be19df7de9e5dfc0078b96bf47a75e)
@@ -1,4 +1,4 @@
 import functools
-from PyQt4 import QtGui
+from PyQt5 import QtWidgets
 
 import sas.sasview
@@ -10,5 +10,5 @@
 from .UI.AboutUI import Ui_AboutUI
 
-class AboutBox(QtGui.QDialog, Ui_AboutUI):
+class AboutBox(QtWidgets.QDialog, Ui_AboutUI):
     def __init__(self, parent=None):
         super(AboutBox, self).__init__(parent)
Index: src/sas/qtgui/MainWindow/DataExplorer.py
===================================================================
--- src/sas/qtgui/MainWindow/DataExplorer.py	(revision 7fb471d81b5d11daed3df86a4e8427e6a832cf7a)
+++ src/sas/qtgui/MainWindow/DataExplorer.py	(revision 4992ff2626be19df7de9e5dfc0078b96bf47a75e)
@@ -5,8 +5,8 @@
 import logging
 
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-from PyQt4 import QtWebKit
-from PyQt4.Qt import QMutex
+from PyQt5 import QtCore
+from PyQt5 import QtGui
+from PyQt5 import QtWidgets
+from PyQt5 import QtWebKitWidgets
 
 from twisted.internet import threads
@@ -48,8 +48,8 @@
         self.loader = Loader()
         self.manager = manager if manager is not None else DataManager()
-        self.txt_widget = QtGui.QTextEdit(None)
+        self.txt_widget = QtWidgets.QTextEdit(None)
 
         # Be careful with twisted threads.
-        self.mutex = QMutex()
+        self.mutex = QtCore.QMutex()
 
         # Active plots
@@ -69,5 +69,5 @@
 
         # Display HTML content
-        self._helpView = QtWebKit.QWebView()
+        self._helpView = QtWebKitWidgets.QWebView()
 
         # Fill in the perspectives combo
@@ -98,5 +98,5 @@
 
         # Proxy model for showing a subset of Data1D/Data2D content
-        self.data_proxy = QtGui.QSortFilterProxyModel(self)
+        self.data_proxy = QtCore.QSortFilterProxyModel(self)
         self.data_proxy.setSourceModel(self.model)
 
@@ -108,5 +108,5 @@
 
         # Proxy model for showing a subset of Theory content
-        self.theory_proxy = QtGui.QSortFilterProxyModel(self)
+        self.theory_proxy = QtCore.QSortFilterProxyModel(self)
         self.theory_proxy.setSourceModel(self.theory_model)
 
@@ -182,4 +182,5 @@
         Opens the Qt "Open File..." dialog
         """
+        print("A")
         path_str = self.chooseFiles()
         if not path_str:
@@ -192,6 +193,6 @@
         Opens the Qt "Open Folder..." dialog
         """
-        folder = QtGui.QFileDialog.getExistingDirectory(self, "Choose a directory", "",
-              QtGui.QFileDialog.ShowDirsOnly | QtGui.QFileDialog.DontUseNativeDialog)
+        folder = QtWidgets.QFileDialog.getExistingDirectory(self, "Choose a directory", "", None,
+              QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontUseNativeDialog)
         if folder is None:
             return
@@ -216,11 +217,17 @@
             'caption'   : 'Open Project',
             'filter'    : 'Project (*.json);;All files (*.*)',
-            'options'   : QtGui.QFileDialog.DontUseNativeDialog
+            'options'   : QtWidgets.QFileDialog.DontUseNativeDialog
         }
-        filename = str(QtGui.QFileDialog.getOpenFileName(**kwargs))
+        filename = str(QtWidgets.QFileDialog.getOpenFileName(**kwargs))
         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):
@@ -248,8 +255,9 @@
 
         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.reset()
+        self.model.endResetModel()
 
     def saveProject(self):
@@ -261,7 +269,7 @@
             'caption'   : 'Save Project',
             'filter'    : 'Project (*.json)',
-            'options'   : QtGui.QFileDialog.DontUseNativeDialog
+            'options'   : QtWidgets.QFileDialog.DontUseNativeDialog
         }
-        filename = str(QtGui.QFileDialog.getSaveFileName(**kwargs))
+        filename = str(QtWidgets.QFileDialog.getSaveFileName(**kwargs))
         if filename:
             self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename))
@@ -617,6 +625,6 @@
         # Location is automatically saved - no need to keep track of the last dir
         # But only with Qt built-in dialog (non-platform native)
-        paths = QtGui.QFileDialog.getOpenFileNames(self, "Choose a file", "",
-                wlist, QtGui.QFileDialog.DontUseNativeDialog)
+        paths = QtWidgets.QFileDialog.getOpenFileNames(self, "Choose a file", "",
+                wlist, None, QtWidgets.QFileDialog.DontUseNativeDialog)
         if paths is None:
             return
@@ -835,5 +843,5 @@
         """
         # Create a custom menu based on actions defined in the UI file
-        self.context_menu = QtGui.QMenu(self)
+        self.context_menu = QtWidgets.QMenu(self)
         self.context_menu.addAction(self.actionDataInfo)
         self.context_menu.addAction(self.actionSaveAs)
@@ -1071,5 +1079,6 @@
         # If so, delete them
         # TODO: fix this to resemble GuiUtils.updateModelItemWithPlot
-        # 
+        #
+        self.model.beginResetModel()
         current_tab_name = model_item.text()[:2]
         for current_index in range(self.theory_model.rowCount()):
@@ -1079,5 +1088,5 @@
 
         # Reset the view
-        self.model.reset()
+        self.model.endResetModel()
 
         # Reset the view
Index: src/sas/qtgui/MainWindow/DroppableDataLoadWidget.py
===================================================================
--- src/sas/qtgui/MainWindow/DroppableDataLoadWidget.py	(revision cd2cc7458970e179039a783e9409f48c4c1fca0d)
+++ src/sas/qtgui/MainWindow/DroppableDataLoadWidget.py	(revision 4992ff2626be19df7de9e5dfc0078b96bf47a75e)
@@ -1,4 +1,6 @@
 # global
-from PyQt4 import QtGui, QtCore
+from PyQt5 import QtCore
+from PyQt5 import QtGui
+from PyQt5 import QtWidgets
 
 # UI
@@ -6,5 +8,5 @@
 from sas.qtgui.MainWindow.UI.DataExplorerUI import Ui_DataLoadWidget
 
-class DroppableDataLoadWidget(QtGui.QTabWidget, Ui_DataLoadWidget):
+class DroppableDataLoadWidget(QtWidgets.QTabWidget, Ui_DataLoadWidget):
     """
     Overwrite drag and drop methods in the base class
Index: src/sas/qtgui/MainWindow/GuiManager.py
===================================================================
--- src/sas/qtgui/MainWindow/GuiManager.py	(revision cee5c78929349ae10afc88cb8b95e0c907f1826a)
+++ src/sas/qtgui/MainWindow/GuiManager.py	(revision 4992ff2626be19df7de9e5dfc0078b96bf47a75e)
@@ -6,7 +6,8 @@
 import webbrowser
 
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-from PyQt4 import QtWebKit
+from PyQt5.QtWidgets import *
+from PyQt5.QtGui import *
+from PyQt5.QtCore import Qt
+from PyQt5.QtWebKitWidgets import QWebView
 
 from twisted.internet import reactor
@@ -38,7 +39,7 @@
 from sas.qtgui.MainWindow.DataExplorer import DataExplorerWindow
 
-class Acknowledgements(QtGui.QDialog, Ui_Acknowledgements):
+class Acknowledgements(QDialog, Ui_Acknowledgements):
     def __init__(self, parent=None):
-        QtGui.QDialog.__init__(self, parent)
+        QDialog.__init__(self, parent)
         self.setupUi(self)
 
@@ -77,5 +78,4 @@
         # Invoke the initial perspective
         self.perspectiveChanged("Fitting")
-
         self.addWidgets()
 
@@ -94,8 +94,8 @@
         # Show the Welcome panel
         self.welcomePanel = WelcomePanel()
-        self._workspace.workspace.addWindow(self.welcomePanel)
+        self._workspace.workspace.addSubWindow(self.welcomePanel)
 
         # Current help file
-        self._helpView = QtWebKit.QWebView()
+        self._helpView = QWebView()
         # Needs URL like path, so no path.join() here
         self._helpLocation = GuiUtils.HELP_DIRECTORY_LOCATION + "/index.html"
@@ -116,19 +116,21 @@
         ObjectLibrary.addObject('DataExplorer', self.filesWidget)
 
-        self.dockedFilesWidget = QtGui.QDockWidget("Data Explorer", self._workspace)
+        self.dockedFilesWidget = QDockWidget("Data Explorer", self._workspace)
+        self.dockedFilesWidget.setFloating(True)
         self.dockedFilesWidget.setWidget(self.filesWidget)
 
         # Disable maximize/minimize and close buttons
-        self.dockedFilesWidget.setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures)
-        self._workspace.addDockWidget(QtCore.Qt.LeftDockWidgetArea,
-                                      self.dockedFilesWidget)
+        self.dockedFilesWidget.setFeatures(QDockWidget.NoDockWidgetFeatures)
+        self.dockedFilesWidget.setFeatures(Qt.LeftDockWidgetArea)
+
+        self._workspace.workspace.addDockWidget(Qt.LeftDockWidgetArea, self.dockedFilesWidget)
 
         # Add the console window as another docked widget
-        self.logDockWidget = QtGui.QDockWidget("Log Explorer", self._workspace)
+        self.logDockWidget = QDockWidget("Log Explorer", self._workspace)
         self.logDockWidget.setObjectName("LogDockWidget")
-        self.listWidget = QtGui.QTextBrowser()
+
+        self.listWidget = QTextBrowser()
         self.logDockWidget.setWidget(self.listWidget)
-        self._workspace.addDockWidget(QtCore.Qt.BottomDockWidgetArea,
-                                      self.logDockWidget)
+        self._workspace.workspace.addDockWidget(Qt.BottomDockWidgetAre, self.logDockWidget) 
 
         # Add other, minor widgets
@@ -152,8 +154,8 @@
         Progress bar invisible until explicitly shown
         """
-        self.progress = QtGui.QProgressBar()
+        self.progress = QProgressBar()
         self._workspace.statusbar.setSizeGripEnabled(False)
 
-        self.statusLabel = QtGui.QLabel()
+        self.statusLabel = QLabel()
         self.statusLabel.setText("Welcome to SasView")
         self._workspace.statusbar.addPermanentWidget(self.statusLabel, 1)
@@ -194,6 +196,6 @@
         self._current_perspective = Perspectives.PERSPECTIVES[str(perspective_name)](parent=self)
 
-        self.setupPerspectiveMenubarOptions(self._current_perspective)
-        self._workspace.workspace.addWindow(self._current_perspective)
+        self._workspace.workspace.addSubWindow(self._current_perspective)
+
         # Resize to the workspace height
         workspace_height = self._workspace.workspace.sizeHint().height()
@@ -265,13 +267,13 @@
         # Display confirmation messagebox
         quit_msg = "Are you sure you want to exit the application?"
-        reply = QtGui.QMessageBox.question(
+        reply = QMessageBox.question(
             self._parent,
             'Information',
             quit_msg,
-            QtGui.QMessageBox.Yes,
-            QtGui.QMessageBox.No)
+            QMessageBox.Yes,
+            QMessageBox.No)
 
         # Exit if yes
-        if reply == QtGui.QMessageBox.Yes:
+        if reply == QMessageBox.Yes:
             reactor.callFromThread(reactor.stop)
             return True
@@ -587,9 +589,8 @@
 
         # Add the console window as another docked widget
-        self.ipDockWidget = QtGui.QDockWidget("IPython", self._workspace)
+        self.ipDockWidget = QDockWidget("IPython", self._workspace)
         self.ipDockWidget.setObjectName("IPythonDockWidget")
         self.ipDockWidget.setWidget(terminal)
-        self._workspace.addDockWidget(QtCore.Qt.RightDockWidgetArea,
-                                      self.ipDockWidget)
+        self._workspace.workspace.addSubWindow(self.ipDockWidget, Qt.RightDockWidgetArea)
 
     def actionImage_Viewer(self):
@@ -716,5 +717,5 @@
         TODO: use QNetworkAccessManager to assure _helpLocation is valid
         """
-        self._helpView.load(QtCore.QUrl(self._helpLocation))
+        self._helpView.load(QUrl(self._helpLocation))
         self._helpView.show()
 
@@ -761,5 +762,5 @@
         :param new_datalist_item:
         """
-        if not isinstance(new_item, QtGui.QStandardItem) or \
+        if not isinstance(new_item, QStandardItem) or \
                 not isinstance(new_datalist_item, dict):
             msg = "Wrong data type returned from calculations."
Index: src/sas/qtgui/MainWindow/MainWindow.py
===================================================================
--- src/sas/qtgui/MainWindow/MainWindow.py	(revision b3e8629bf18b74f4214d6552e620fcbc4e73a28c)
+++ src/sas/qtgui/MainWindow/MainWindow.py	(revision 4992ff2626be19df7de9e5dfc0078b96bf47a75e)
@@ -1,5 +1,7 @@
 # UNLESS EXEPTIONALLY REQUIRED TRY TO AVOID IMPORTING ANY MODULES HERE
 # ESPECIALLY ANYTHING IN SAS, SASMODELS NAMESPACE
-from PyQt4 import QtGui
+#from PyQt4 import QtGui
+from PyQt5.QtWidgets import *
+from PyQt5.QtGui import *
 
 # Local UI
@@ -10,5 +12,5 @@
 import sas.qtgui.Utilities.SasviewLogger
 
-class MainSasViewWindow(QtGui.QMainWindow, Ui_MainWindow):
+class MainSasViewWindow(QMainWindow, Ui_MainWindow):
     # Main window of the application
     def __init__(self, parent=None):
@@ -17,10 +19,13 @@
 
         # define workspace for dialogs.
-        self.workspace = QtGui.QWorkspace(self)
+        self.workspace = QMdiArea(self)
         self.setCentralWidget(self.workspace)
 
         # Create the gui manager
         from .GuiManager import GuiManager
-        self.guiManager = GuiManager(self)
+        try:
+            self.guiManager = GuiManager(self)
+        except Exception as ex:
+            print("EXCEPTION: ", ex)
 
     def closeEvent(self, event):
@@ -37,10 +42,10 @@
     """
     # TODO: standardize path to images
-    pixmap = QtGui.QPixmap("src/sas/qtgui/images/SVwelcome_mini.png")
-    splashScreen = QtGui.QSplashScreen(pixmap)
+    pixmap = QPixmap("src/sas/qtgui/images/SVwelcome_mini.png")
+    splashScreen = QSplashScreen(pixmap)
     return splashScreen
 
 def run():
-    app = QtGui.QApplication([])
+    app = QApplication([])
 
     # Main must have reference to the splash screen, so making it explicit
@@ -55,7 +60,7 @@
     # DO NOT move the following import to the top!
     # (unless you know what you're doing)
-    import qt4reactor
+    import qt5reactor
     # Using the Qt4 reactor wrapper from https://github.com/ghtdak/qtreactor
-    qt4reactor.install()
+    qt5reactor.install()
 
     # DO NOT move the following import to the top!
Index: src/sas/qtgui/MainWindow/WelcomePanel.py
===================================================================
--- src/sas/qtgui/MainWindow/WelcomePanel.py	(revision cd2cc7458970e179039a783e9409f48c4c1fca0d)
+++ src/sas/qtgui/MainWindow/WelcomePanel.py	(revision 4992ff2626be19df7de9e5dfc0078b96bf47a75e)
@@ -2,7 +2,6 @@
 import sys
 import os
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-from PyQt4 import QtWebKit
+
+from PyQt5 import QtWidgets
 
 import sas.sasview
@@ -13,5 +12,5 @@
 from sas.qtgui.MainWindow.UI.WelcomePanelUI import Ui_WelcomePanelUI
 
-class WelcomePanel(QtGui.QDialog, Ui_WelcomePanelUI):
+class WelcomePanel(QtWidgets.QDialog, Ui_WelcomePanelUI):
     def __init__(self, parent=None):
         super(WelcomePanel, self).__init__(parent)
