Index: setup.py
===================================================================
--- setup.py	(revision 0261bc13615593f5eb2e08941252c044b8bb2e3b)
+++ setup.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -53,7 +53,7 @@
     if os.path.isfile(f_path):
         os.remove(f_path)
-    f_path = os.path.join(sas_dir, "categories.json")
-    if os.path.isfile(f_path):
-        os.remove(f_path)
+    #f_path = os.path.join(sas_dir, "categories.json")
+    #if os.path.isfile(f_path):
+    #    os.remove(f_path)
     f_path = os.path.join(sas_dir, 'config', "custom_config.py")
     if os.path.isfile(f_path):
Index: src/sas/qtgui/MainWindow/GuiManager.py
===================================================================
--- src/sas/qtgui/MainWindow/GuiManager.py	(revision 676f1378496edab35bd11ed8e0ce2614c0db17b6)
+++ src/sas/qtgui/MainWindow/GuiManager.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -9,5 +9,4 @@
 from PyQt5.QtGui import *
 from PyQt5.QtCore import Qt, QLocale, QUrl
-from PyQt5.QtWebKitWidgets import QWebView
 
 from twisted.internet import reactor
Index: src/sas/qtgui/MainWindow/UnitTesting/GuiManagerTest.py
===================================================================
--- src/sas/qtgui/MainWindow/UnitTesting/GuiManagerTest.py	(revision 8353d908545a5d1d1ac66b2e075d0ec49b5a7cc2)
+++ src/sas/qtgui/MainWindow/UnitTesting/GuiManagerTest.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -272,19 +272,16 @@
     #### HELP ####
     # test when PyQt5 works with html
-    def notestActionDocumentation(self):
+    def testActionDocumentation(self):
         """
         Menu Help/Documentation
         """
-        #Mock the QWebView method
-        QWebView.show = MagicMock()
-
-        # Assure the filename is correct
-        self.assertIn("index.html", self.manager._helpLocation)
+        webbrowser.open = MagicMock()
 
         # Invoke the action
         self.manager.actionDocumentation()
 
-        # Check if show() got called
-        self.assertTrue(QWebView.show.called)
+        # see that webbrowser open was attempted
+        webbrowser.open.assert_called_once()
+
 
     def skip_testActionTutorial(self):
Index: src/sas/qtgui/Perspectives/Fitting/ComplexConstraint.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/ComplexConstraint.py	(revision da9a07226e9e59e05151f1ed443b9554788d1294)
+++ src/sas/qtgui/Perspectives/Fitting/ComplexConstraint.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -15,5 +15,5 @@
 # Local UI
 from sas.qtgui.Perspectives.Fitting.UI.ComplexConstraintUI import Ui_ComplexConstraintUI
-from sas.qtgui.Perspectives.Fitting.Constraints import Constraint
+from sas.qtgui.Perspectives.Fitting.Constraint import Constraint
 
 class ComplexConstraint(QtWidgets.QDialog, Ui_ComplexConstraintUI):
@@ -36,4 +36,7 @@
 
         self.setFixedSize(self.minimumSizeHint())
+
+        # Default focus is on OK
+        self.cmdOK.setFocus()
 
     def setupData(self):
Index: src/sas/qtgui/Perspectives/Fitting/Constraint.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/Constraint.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
+++ src/sas/qtgui/Perspectives/Fitting/Constraint.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -0,0 +1,54 @@
+class Constraint(object):
+    """
+    Internal representation of a single parameter constraint
+    Currently just a data structure, might get expaned with more functionality,
+    hence made into a class.
+    """
+    def __init__(self, parent=None, param=None, value=0.0, min=None, max=None, func=None):
+        self._value = value
+        self._param = param
+        self._func = func
+        self.active = True
+        self._min = min
+        self._max = max
+
+    @property
+    def value(self):
+        return self._value
+
+    @value.setter
+    def value(self, val):
+        self._value = val
+
+    @property
+    def param(self):
+        return self._param
+
+    @param.setter
+    def param(self, val):
+        self._param = val
+
+    @property
+    def func(self):
+        return self._func
+
+    @func.setter
+    def func(self, val):
+        self._func = val
+
+    @property
+    def min(self):
+        return self._min
+
+    @min.setter
+    def min(self, val):
+        self._min = val
+
+    @property
+    def max(self):
+        return self._max
+
+    @max.setter
+    def max(self, val):
+        self._max = val
+
Index: src/sas/qtgui/Perspectives/Fitting/ConstraintWidget.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/ConstraintWidget.py	(revision da9a07226e9e59e05151f1ed443b9554788d1294)
+++ src/sas/qtgui/Perspectives/Fitting/ConstraintWidget.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -5,4 +5,6 @@
 
 import sas.qtgui.Utilities.GuiUtils as GuiUtils
+import sas.qtgui.Utilities.LocalConfig as LocalConfig
+
 from PyQt5 import QtGui, QtCore, QtWidgets
 
@@ -15,5 +17,5 @@
 from sas.qtgui.Perspectives.Fitting.ConsoleUpdate import ConsoleUpdate
 from sas.qtgui.Perspectives.Fitting.ComplexConstraint import ComplexConstraint
-from sas.qtgui.Perspectives.Fitting.Constraints import Constraint
+from sas.qtgui.Perspectives.Fitting.Constraint import Constraint
 
 class ConstraintWidget(QtWidgets.QWidget, Ui_ConstraintWidgetUI):
@@ -22,13 +24,12 @@
     """
 
-    def __init__(self, parent=None, tab_id=1):
+    def __init__(self, parent=None):
         super(ConstraintWidget, self).__init__()
         self.parent = parent
         self.setupUi(self)
         self.currentType = "FitPage"
-        self.tab_id = tab_id
         # Page id for fitting
         # To keep with previous SasView values, use 300 as the start offset
-        self.page_id = 300 + self.tab_id
+        self.page_id = 301
 
         # Remember previous content of modified cell
@@ -118,4 +119,10 @@
         pass
 
+    def getTabsForFit(self):
+        """
+        Returns list of tab names selected for fitting
+        """
+        return [tab for tab in self.tabs_for_fitting if self.tabs_for_fitting[tab]]
+
     def onFit(self):
         """
@@ -123,9 +130,12 @@
         """
         # Find out all tabs to fit
-        tabs_to_fit = [tab for tab in self.tabs_for_fitting if self.tabs_for_fitting[tab]]
+        tabs_to_fit = self.getTabsForFit()
 
         # Single fitter for the simultaneous run
         sim_fitter = Fit()
         sim_fitter.fitter_id = self.page_id
+
+        # Notify the parent about fitting started
+        self.parent.fittingStartedSignal.emit(tabs_to_fit)
 
         # prepare fitting problems for each tab
@@ -157,12 +167,12 @@
         completefn = self.onBatchFitComplete if self.currentType=='BatchPage' else self.onFitComplete
 
-        #if USING_TWISTED:
-        handler = None
-        updater = None
-        #else:
-        #    handler = ConsoleUpdate(parent=self.parent,
-        #                            manager=self,
-        #                            improvement_delta=0.1)
-        #    updater = handler.update_fit
+        if LocalConfig.USING_TWISTED:
+            handler = None
+            updater = None
+        else:
+            handler = ConsoleUpdate(parent=self.parent,
+                                    manager=self,
+                                    improvement_delta=0.1)
+            updater = handler.update_fit
 
         batch_inputs = {}
@@ -178,13 +188,13 @@
                              completefn=completefn)
 
-        #if USING_TWISTED:
-        # start the trhrhread with twisted
-        calc_thread = threads.deferToThread(calc_fit.compute)
-        calc_thread.addCallback(completefn)
-        calc_thread.addErrback(self.onFitFailed)
-        #else:
-        #    # Use the old python threads + Queue
-        #    calc_fit.queue()
-        #    calc_fit.ready(2.5)
+        if LocalConfig.USING_TWISTED:
+            # start the trhrhread with twisted
+            calc_thread = threads.deferToThread(calc_fit.compute)
+            calc_thread.addCallback(completefn)
+            calc_thread.addErrback(self.onFitFailed)
+        else:
+            # Use the old python threads + Queue
+            calc_fit.queue()
+            calc_fit.ready(2.5)
 
 
@@ -300,4 +310,7 @@
         self.cmdFit.setEnabled(True)
 
+        # Notify the parent about completed fitting
+        self.parent.fittingStoppedSignal.emit(self.getTabsForFit())
+
         # get the elapsed time
         elapsed = result[1]
@@ -330,4 +343,7 @@
         self.cmdFit.setEnabled(True)
 
+        # Notify the parent about completed fitting
+        self.parent.fittingStoppedSignal.emit(self.getTabsForFit())
+
         # get the elapsed time
         elapsed = result[1]
@@ -348,4 +364,7 @@
         self.cmdFit.setText("Fit")
         self.cmdFit.setEnabled(True)
+
+        # Notify the parent about completed fitting
+        self.parent.fittingStoppedSignal.emit(self.getTabsForFit())
 
         msg = "Fitting failed: %s s.\n" % reason
Index: c/sas/qtgui/Perspectives/Fitting/Constraints.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/Constraints.py	(revision ba01ad131050e05053ee2ab2bf5c139e9617c9d9)
+++ 	(revision )
@@ -1,54 +1,0 @@
-class Constraint(object):
-    """
-    Internal representation of a single parameter constraint
-    """
-    def __init__(self, parent=None, param=None, value=0.0, min=None, max=None, func=None):
-        self._value = value
-        self._param = param
-        self._func = func
-        self.active = True
-        self._min = min
-        self._max = max
-
-    @property
-    def value(self):
-        return self._value
-
-    @value.setter
-    def value(self, val):
-        self._value = val
-
-    @property
-    def param(self):
-        return self._param
-
-    @param.setter
-    def param(self, val):
-        self._param = val
-
-    @property
-    def func(self):
-        return self._func
-
-    @func.setter
-    def func(self, val):
-        self._func = val
-
-    @property
-    def min(self):
-        return self._min
-
-    @min.setter
-    def min(self, val):
-        self._min = val
-
-    @property
-    def max(self):
-        return self._max
-
-    @max.setter
-    def max(self, val):
-        self._max = val
-
-    def delete(self, constraint=None):
-        pass
Index: src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py	(revision 63319b0e1635f70a44346bc676740b77b0aa7102)
+++ src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -19,4 +19,7 @@
     """
     tabsModifiedSignal = QtCore.pyqtSignal()
+    fittingStartedSignal = QtCore.pyqtSignal(list)
+    fittingStoppedSignal = QtCore.pyqtSignal(list)
+
     name = "Fitting" # For displaying in the combo box in DataExplorer
     def __init__(self, parent=None, data=None):
@@ -32,5 +35,4 @@
         # Max index for adding new, non-clashing tab names
         self.maxIndex = 0
-        self.maxCSIndex = 0
 
         # Index of the current tab
@@ -40,9 +42,12 @@
         self.optimizer = 'Levenberg-Marquardt'
 
-        # Dataset inde -> Fitting tab mapping
+        # Dataset index -> Fitting tab mapping
         self.dataToFitTab = {}
 
         # The tabs need to be closeable
         self.setTabsClosable(True)
+
+        # The tabs need to be movabe
+        self.setMovable(True)
 
         self.communicate = self.parent.communicator()
@@ -54,4 +59,6 @@
         self.tabCloseRequested.connect(self.tabCloses)
         self.communicate.dataDeletedSignal.connect(self.dataDeleted)
+        self.fittingStartedSignal.connect(self.onFittingStarted)
+        self.fittingStoppedSignal.connect(self.onFittingStopped)
 
         # Perspective window not allowed to close by default
@@ -69,5 +76,4 @@
         self.gpu_options_widget = GPUOptions(self)
 
-        #self.setWindowTitle('Fit panel - Active Fitting Optimizer: %s' % self.optimizer)
         self.updateWindowTitle()
 
@@ -82,5 +88,5 @@
     def setClosable(self, value=True):
         """
-        Allow outsiders close this widget
+        Allow outsiders to close this widget
         """
         assert isinstance(value, bool)
@@ -124,10 +130,14 @@
         Add a new C&S fitting tab
         """
-        tab	= ConstraintWidget(parent=self, tab_id=self.maxCSIndex)
+        tabs = [isinstance(tab, ConstraintWidget) for tab in self.tabs]
+        if any(tabs):
+            # We already have a C&S tab: show it
+            self.setCurrentIndex(tabs.index(True))
+            return
+        tab	= ConstraintWidget(parent=self)
         # Add this tab to the object library so it can be retrieved by scripting/jupyter
         tab_name = self.getCSTabName() # TODO update the tab name scheme
         ObjectLibrary.addObject(tab_name, tab)
         self.tabs.append(tab)
-        self.maxCSIndex += 1
         self.addTab(tab, tab_name)
 
@@ -155,5 +165,4 @@
         """
         page_name = "Const. & Simul. Fit"
-        page_name = page_name + str(self.maxCSIndex)
         return page_name
 
@@ -263,3 +272,35 @@
         self.updateWindowTitle()
 
+    def onFittingStarted(self, tabs_for_fitting=None):
+        """
+        Notify tabs listed in tabs_for_fitting
+        that the fitting thread started
+        """
+        assert(isinstance(tabs_for_fitting, list))
+        assert(len(tabs_for_fitting)>0)
+
+        for tab_object in self.tabs:
+            if not isinstance(tab_object, FittingWidget):
+                continue
+            page_name = "Page%s"%tab_object.tab_id
+            if any([page_name in tab for tab in tabs_for_fitting]):
+                tab_object.setFittingStarted()
+
         pass
+
+    def onFittingStopped(self, tabs_for_fitting=None):
+        """
+        Notify tabs listed in tabs_for_fitting
+        that the fitting thread stopped
+        """
+        assert(isinstance(tabs_for_fitting, list))
+        assert(len(tabs_for_fitting)>0)
+
+        for tab_object in self.tabs:
+            if not isinstance(tab_object, FittingWidget):
+                continue
+            page_name = "Page%s"%tab_object.tab_id
+            if any([page_name in tab for tab in tabs_for_fitting]):
+                tab_object.setFittingStopped()
+
+        pass
Index: src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision 63319b0e1635f70a44346bc676740b77b0aa7102)
+++ src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -23,4 +23,6 @@
 
 import sas.qtgui.Utilities.GuiUtils as GuiUtils
+import sas.qtgui.Utilities.LocalConfig as LocalConfig
+
 from sas.qtgui.Utilities.CategoryInstaller import CategoryInstaller
 from sas.qtgui.Plotting.PlotterData import Data1D
@@ -41,5 +43,5 @@
 from sas.qtgui.Perspectives.Fitting.ViewDelegate import PolyViewDelegate
 from sas.qtgui.Perspectives.Fitting.ViewDelegate import MagnetismViewDelegate
-from sas.qtgui.Perspectives.Fitting.Constraints import Constraint
+from sas.qtgui.Perspectives.Fitting.Constraint import Constraint
 from sas.qtgui.Perspectives.Fitting.MultiConstraint import MultiConstraint
 
@@ -53,6 +55,4 @@
 DEFAULT_POLYDISP_FUNCTION = 'gaussian'
 
-USING_TWISTED = True
-#USING_TWISTED = False
 
 class ToolTippedItemModel(QtGui.QStandardItemModel):
@@ -1086,5 +1086,5 @@
         batch_outputs = {}
         #---------------------------------
-        if USING_TWISTED:
+        if LocalConfig.USING_TWISTED:
             handler = None
             updater = None
@@ -1114,8 +1114,8 @@
                             completefn=completefn)
 
-        if USING_TWISTED:
+        if LocalConfig.USING_TWISTED:
             # start the trhrhread with twisted
             calc_thread = threads.deferToThread(calc_fit.compute)
-            calc_thread.addCallback(self.fitComplete)
+            calc_thread.addCallback(completefn)
             calc_thread.addErrback(self.fitFailed)
         else:
@@ -1124,9 +1124,7 @@
             calc_fit.ready(2.5)
 
-
-        #disable the Fit button
-        self.cmdFit.setText('Running...')
         self.communicate.statusBarUpdateSignal.emit('Fitting started...')
-        self.cmdFit.setEnabled(False)
+        # Disable some elements
+        self.setFittingStarted()
 
     def updateFit(self):
@@ -1147,6 +1145,5 @@
         """
         #re-enable the Fit button
-        self.cmdFit.setText("Fit")
-        self.cmdFit.setEnabled(True)
+        self.setFittingStopped()
 
         print ("BATCH FITTING FINISHED")
@@ -1160,6 +1157,5 @@
         """
         #re-enable the Fit button
-        self.cmdFit.setText("Fit")
-        self.cmdFit.setEnabled(True)
+        self.setFittingStopped()
 
         assert result is not None
@@ -2232,4 +2228,20 @@
         self.setMagneticModel()
 
+    def setFittingStarted(self):
+        """
+        Set item enablement on fitting start
+        """
+        #disable the Fit button
+        self.cmdFit.setText('Running...')
+        self.cmdFit.setEnabled(False)
+
+    def setFittingStopped(self):
+        """
+        Set item enablement on fitting stop
+        """
+        #enable the Fit button
+        self.cmdFit.setText("Fit")
+        self.cmdFit.setEnabled(True)
+
     def readFitPage(self, fp):
         """
Index: src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py	(revision 5e667388d944fe97aa1a2f1493a9fa986e5b6ff5)
+++ src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -43,4 +43,7 @@
         self.cmdRevert.clicked.connect(self.revert)
         self.txtConstraint.editingFinished.connect(self.validateFormula)
+
+        # Default focus is on OK
+        self.cmdOK.setFocus()
 
     def revert(self):
Index: src/sas/qtgui/Perspectives/Fitting/UI/ComplexConstraintUI.ui
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UI/ComplexConstraintUI.ui	(revision 2d466e4b832e803d9f9cf7561ec93be0e476045a)
+++ src/sas/qtgui/Perspectives/Fitting/UI/ComplexConstraintUI.ui	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -7,6 +7,6 @@
     <x>0</x>
     <y>0</y>
-    <width>359</width>
-    <height>166</height>
+    <width>406</width>
+    <height>167</height>
    </rect>
   </property>
@@ -92,5 +92,5 @@
          <widget class="QPushButton" name="cmdRevert">
           <property name="text">
-           <string>Revert</string>
+           <string>Swap</string>
           </property>
          </widget>
@@ -165,4 +165,7 @@
         <string>OK</string>
        </property>
+       <property name="default">
+        <bool>true</bool>
+       </property>
       </widget>
      </item>
Index: src/sas/qtgui/Perspectives/Fitting/UI/MultiConstraintUI.ui
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UI/MultiConstraintUI.ui	(revision d3c0b9586dd15f08a6d08159dc5c41bfae457c3b)
+++ src/sas/qtgui/Perspectives/Fitting/UI/MultiConstraintUI.ui	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -10,6 +10,6 @@
     <x>0</x>
     <y>0</y>
-    <width>369</width>
-    <height>143</height>
+    <width>426</width>
+    <height>162</height>
    </rect>
   </property>
@@ -85,5 +85,5 @@
       <widget class="QPushButton" name="cmdRevert">
        <property name="text">
-        <string>Revert</string>
+        <string>Swap</string>
        </property>
       </widget>
@@ -150,4 +150,7 @@
        <property name="text">
         <string>OK</string>
+       </property>
+       <property name="default">
+        <bool>true</bool>
        </property>
       </widget>
Index: src/sas/qtgui/Perspectives/Fitting/UnitTesting/ConstraintWidgetTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UnitTesting/ConstraintWidgetTest.py	(revision da9a07226e9e59e05151f1ed443b9554788d1294)
+++ src/sas/qtgui/Perspectives/Fitting/UnitTesting/ConstraintWidgetTest.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -15,5 +15,5 @@
 # Local
 from sas.qtgui.Perspectives.Fitting.ConstraintWidget import ConstraintWidget
-from sas.qtgui.Perspectives.Fitting.Constraints import Constraint
+from sas.qtgui.Perspectives.Fitting.Constraint import Constraint
 
 if not QtWidgets.QApplication.instance():
Index: src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingOptionsTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingOptionsTest.py	(revision 53c771ed573b1c8716ecc969b54a1d617a4cb931)
+++ src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingOptionsTest.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -1,4 +1,5 @@
 import sys
 import unittest
+import webbrowser
 from bumps import options
 
@@ -114,16 +115,14 @@
 
     # test disabled until pyQt5 works well
-    def notestOnHelp(self):
+    def testOnHelp(self):
         ''' Test help display'''
-        #Mock the QWebView method
-        QtWebKit.QWebView.show = MagicMock()
-        QtWebKit.QWebView.load = MagicMock()
+        webbrowser.open = MagicMock()
 
         # Invoke the action on default tab
         self.widget.onHelp()
         # Check if show() got called
-        self.assertTrue(QtWebKit.QWebView.show.called)
+        self.assertTrue(webbrowser.open.called)
         # Assure the filename is correct
-        self.assertIn("optimizer.html", QtWebKit.QWebView.load.call_args[0][0].toString())
+        self.assertIn("optimizer.html", webbrowser.open.call_args[0][0])
 
         # Change the combo index
@@ -131,7 +130,7 @@
         self.widget.onHelp()
         # Check if show() got called
-        self.assertEqual(QtWebKit.QWebView.show.call_count, 2)
+        self.assertEqual(webbrowser.open.call_count, 2)
         # Assure the filename is correct
-        self.assertIn("fit-dream", QtWebKit.QWebView.load.call_args[0][0].toString())
+        self.assertIn("fit-dream", webbrowser.open.call_args[0][0])
 
         # Change the index again
@@ -139,7 +138,7 @@
         self.widget.onHelp()
         # Check if show() got called
-        self.assertEqual(QtWebKit.QWebView.show.call_count, 3)
+        self.assertEqual(webbrowser.open.call_count, 3)
         # Assure the filename is correct
-        self.assertIn("fit-lm", QtWebKit.QWebView.load.call_args[0][0].toString())
+        self.assertIn("fit-lm", webbrowser.open.call_args[0][0])
 
     def testWidgetFromOptions(self):
Index: src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py	(revision 63319b0e1635f70a44346bc676740b77b0aa7102)
+++ src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -17,5 +17,5 @@
 from sas.qtgui.Utilities.GuiUtils import *
 from sas.qtgui.Perspectives.Fitting.FittingWidget import *
-from sas.qtgui.Perspectives.Fitting.Constraints import Constraint
+from sas.qtgui.Perspectives.Fitting.Constraint import Constraint
 
 from sas.qtgui.UnitTesting.TestUtils import QtSignalSpy
@@ -787,19 +787,18 @@
             self.assertEqual(update_spy.count(), 1)
 
-    # test disabled until pyqt5 deals with html properly
-    def notestOnHelp(self):
+    def testOnHelp(self):
         """
         Test various help pages shown in this widget
         """
-        #Mock the QWebView method
-        QtWebKit.QWebView.show = MagicMock()
-        QtWebKit.QWebView.load = MagicMock()
+        #Mock the webbrowser.open method
+        self.widget.parent.showHelp = MagicMock()
+        #webbrowser.open = MagicMock()
 
         # Invoke the action on default tab
         self.widget.onHelp()
         # Check if show() got called
-        self.assertTrue(QtWebKit.QWebView.show.called)
+        self.assertTrue(self.widget.parent.showHelp.called)
         # Assure the filename is correct
-        self.assertIn("fitting_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
+        self.assertIn("fitting_help.html", self.widget.parent.showHelp.call_args[0][0])
 
         # Change the tab to options
@@ -807,7 +806,7 @@
         self.widget.onHelp()
         # Check if show() got called
-        self.assertEqual(QtWebKit.QWebView.show.call_count, 2)
+        self.assertEqual(self.widget.parent.showHelp.call_count, 2)
         # Assure the filename is correct
-        self.assertIn("residuals_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
+        self.assertIn("residuals_help.html", self.widget.parent.showHelp.call_args[0][0])
 
         # Change the tab to smearing
@@ -815,7 +814,7 @@
         self.widget.onHelp()
         # Check if show() got called
-        self.assertEqual(QtWebKit.QWebView.show.call_count, 3)
+        self.assertEqual(self.widget.parent.showHelp.call_count, 3)
         # Assure the filename is correct
-        self.assertIn("sm_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
+        self.assertIn("resolution.html", self.widget.parent.showHelp.call_args[0][0])
 
         # Change the tab to poly
@@ -823,7 +822,7 @@
         self.widget.onHelp()
         # Check if show() got called
-        self.assertEqual(QtWebKit.QWebView.show.call_count, 4)
+        self.assertEqual(self.widget.parent.showHelp.call_count, 4)
         # Assure the filename is correct
-        self.assertIn("pd_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
+        self.assertIn("polydispersity.html", self.widget.parent.showHelp.call_args[0][0])
 
         # Change the tab to magnetism
@@ -831,7 +830,7 @@
         self.widget.onHelp()
         # Check if show() got called
-        self.assertEqual(QtWebKit.QWebView.show.call_count, 5)
+        self.assertEqual(self.widget.parent.showHelp.call_count, 5)
         # Assure the filename is correct
-        self.assertIn("mag_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
+        self.assertIn("magnetism.html", self.widget.parent.showHelp.call_args[0][0])
 
     def testReadFitPage(self):
Index: src/sas/qtgui/Plotting/UnitTesting/SlicerParametersTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/SlicerParametersTest.py	(revision 53c771ed573b1c8716ecc969b54a1d617a4cb931)
+++ src/sas/qtgui/Plotting/UnitTesting/SlicerParametersTest.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -1,4 +1,5 @@
 import sys
 import unittest
+import webbrowser
 from unittest.mock import MagicMock
 
@@ -72,7 +73,6 @@
         self.widget.show()
 
-        #Mock the QWebView method
-        QtWebKit.QWebView.show = MagicMock()
-        QtWebKit.QWebView.load = MagicMock()
+        #Mock the webbrowser.open method
+        webbrowser.open = MagicMock()
 
         # Invoke the action
@@ -80,8 +80,8 @@
 
         # Check if show() got called
-        self.assertTrue(QtWebKit.QWebView.show.called)
+        self.assertTrue(webbrowser.open.called)
 
         # Assure the filename is correct
-        self.assertIn("graph_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
+        self.assertIn("graph_help.html", webbrowser.open.call_args[0][0])
         
     def testSetModel(self):
Index: src/sas/qtgui/Utilities/LocalConfig.py
===================================================================
--- src/sas/qtgui/Utilities/LocalConfig.py	(revision b3e8629bf18b74f4214d6552e620fcbc4e73a28c)
+++ src/sas/qtgui/Utilities/LocalConfig.py	(revision 14ec91c506393c404c69a71e75131fb3d62e4230)
@@ -132,4 +132,7 @@
 DEFAULT_PERSPECTIVE = 'None'
 
+# Default threading model
+USING_TWISTED = True
+
 # Time out for updating sasview
 UPDATE_TIMEOUT = 2
