Index: src/sas/qtgui/Perspectives/Invariant/InvariantDetails.py
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/InvariantDetails.py	(revision 4992ff2626be19df7de9e5dfc0078b96bf47a75e)
+++ src/sas/qtgui/Perspectives/Invariant/InvariantDetails.py	(revision f1f3e6a66c47bce134b59fe9f166fe14eac3a61d)
@@ -2,6 +2,5 @@
 import os
 from PyQt5 import QtCore
-from PyQt5 import QtGui
-from PyQt5 import QtWidgets
+from PyQt5 import QtGui, QtWidgets
 
 # local
@@ -9,6 +8,13 @@
 from .InvariantUtils import WIDGETS
 
+# ERROR_COLOR = wx.Colour(255, 0, 0, 128)
+# EXTRAPOLATION_COLOR = wx.Colour(169, 169, 168, 128)
+# INVARIANT_COLOR = wx.Colour(67, 208, 128, 128)
+
 class DetailsDialog(QtWidgets.QDialog, Ui_Dialog):
     """
+    This class stores some values resulting from invariant calculations.
+    Given the value of total invariant, this class can also
+    determine the percentage of invariants resulting from extrapolation.
     """
     def __init__(self, parent):
@@ -17,53 +23,174 @@
         self.setupUi(self)
 
-        self.progressBar.setMinimum(0)
-        self.progressBar.setMaximum(100)
+        DEFAULT_STYLE = """
+        QProgressBar{
+            border: 2px solid grey;
+            border-radius: 5px;
+            text-align: center
+        }
 
-        self.progressBar_2.setMinimum(0)
-        self.progressBar_2.setMaximum(100)
+        QProgressBar::chunk {
+            background-color: #b1daf9;
+            width: 10px;
+            margin: 1px;
+        }
+        """
+        self.progressBarLowQ.setStyleSheet(DEFAULT_STYLE)
+        self.progressBarData.setStyleSheet(DEFAULT_STYLE)
+        self.progressBarHighQ.setStyleSheet(DEFAULT_STYLE)
 
-        self.progressBar_3.setMinimum(0)
-        self.progressBar_3.setMaximum(100)
+        self.progressBarLowQ.setMinimum(0)
+        self.progressBarLowQ.setMaximum(100)
+
+        self.progressBarData.setMinimum(0)
+        self.progressBarData.setMaximum(100)
+
+        self.progressBarHighQ.setMinimum(0)
+        self.progressBarHighQ.setMaximum(100)
+
+        # Modify font in order to display Angstrom symbol correctly
+        new_font = 'font-family: -apple-system, "Helvetica Neue", "Ubuntu";'
+        self.lblQLowQUnits.setStyleSheet(new_font)
+        self.lblQDataUnits.setStyleSheet(new_font)
+        self.lblQHighQUnits.setStyleSheet(new_font)
+
+        self.cmdOK.clicked.connect(self.accept)
+
+        self.warning_msg = "No Details on calculations available...\n"
+
+        # invariant total
+        self.qstar_total = None
+        self.qhigh = None
+        self.qlow = None
+        self._model = None
+
+        self.progress_low_qstar = 0.0
+        self.progress_high_qstar = 0.0
+        self.progress_qstar = 100.0
 
     def setModel(self, model):
-        """
-        """
+        """ """
         self._model = model
 
     def showDialog(self):
-        """
-        """
+        """ Fill the dialog with values of calculated Q, progress bars"""
         # Pull out data from the model
-        qstar_total = float(self._model.item(WIDGETS.W_INVARIANT).text())
-        self.lineEdit_3.setText(str(qstar_total))
-        self.lineEdit_4.setText(self._model.item(WIDGETS.W_INVARIANT_ERR).text())
+        self.qstar_total = float(self._model.item(WIDGETS.W_INVARIANT).text())
 
-        progress_low_qstar = 0.0
-        progress_high_qstar = 0.0
-        progress_qstar = 100.0
+        self.txtQData.setText(str(self.qstar_total))
+        self.txtQDataErr.setText(self._model.item(WIDGETS.W_INVARIANT_ERR).text())
 
+        # Low-Q
         if self._model.item(WIDGETS.W_ENABLE_LOWQ).text() == "true":
-            qlow = float(self._model.item(WIDGETS.D_LOW_QSTAR).text())
-            self.lineEdit.setText(str(qlow))
-            self.lineEdit_2.setText(self._model.item(WIDGETS.D_LOW_QSTAR_ERR).text())
-            progress_low_qstar = (qlow/qstar_total)*100.0
+            self.qlow = float(self._model.item(WIDGETS.D_LOW_QSTAR).text())
 
+            self.txtQLowQ.setText(str(self.qlow))
+            self.txtQLowQErr.setText(self._model.item(WIDGETS.D_LOW_QSTAR_ERR).text())
+            try:
+                self.progress_low_qstar = (self.qlow/self.qstar_total)*100.0
+            except:
+                self.progress_low_qstar = 'error'
+
+        # High-Q
         if self._model.item(WIDGETS.W_ENABLE_HIGHQ).text() == "true":
-            qhigh = float(self._model.item(WIDGETS.D_LOW_QSTAR).text())
-            self.lineEdit.setText(str(qhigh))
-            self.lineEdit_2.setText(self._model.item(WIDGETS.D_HIGH_QSTAR_ERR).text())
-            progress_high_qstar = (qhigh/qstar_total)*100.0
+            self.qhigh = float(self._model.item(WIDGETS.D_HIGH_QSTAR).text())
 
+            self.txtQHighQ.setText(str(self.qhigh))
+            self.txtQHighQErr.setText(self._model.item(WIDGETS.D_HIGH_QSTAR_ERR).text())
+            try:
+                self.progress_high_qstar = (self.qhigh/self.qstar_total)*100.0
+            except:
+                self.progress_high_qstar = 'error'
 
-        progress_qstar -= progress_low_qstar + progress_high_qstar
+        try:
+            self.progress_qstar -= self.progress_low_qstar + self.progress_high_qstar
+        except:
+            self.progress_qstar = 'error'
 
-        self.progressBar.setValue(progress_low_qstar)
-        self.progressBar_2.setValue(progress_qstar)           
-        self.progressBar_3.setValue(progress_high_qstar)
+        # check values and display warning
+        if self.checkValues():
+            self.lblWarning.setText(self.checkValues())
 
-        new_font = 'font-family: -apple-system, "Helvetica Neue", "Ubuntu";'
-        self.label_3.setStyleSheet(new_font)
-        self.label_4.setStyleSheet(new_font)
-        self.label_7.setStyleSheet(new_font)
+        # update progress bars
+        if self.progress_low_qstar == 'error':
+            self.progressBarLowQ.setValue(0)
+        else:
+            self.progressBarLowQ.setValue(self.progress_low_qstar)
+
+        if self.progress_high_qstar == 'error':
+            self.progressBarHighQ.setValue(0)
+        else:
+            self.progressBarHighQ.setValue(self.progress_high_qstar)
+
+        if self.progress_qstar == 'error':
+            self.progressBarData.setValue(0)
+        else:
+            self.progressBarData.setValue(self.progress_qstar)
 
         self.show()
+
+    def checkValues(self):
+        """
+        Create a warning message to be displayed in panel
+        if problems with values
+        """
+
+        if self.qstar_total is None:
+            warning_msg = "Invariant not calculated.\n"
+            return warning_msg
+        elif self.qstar_total == 0:
+            warning_msg = "Invariant is zero. \n " \
+                          "The calculations are likely to be unreliable!\n"
+            return warning_msg
+
+        msg = ''
+        if self.progress_qstar == 'error':
+            msg += 'Error occurred when computing invariant from data.\n '
+        if self.progress_qstar > 100:
+            msg += "Invariant Q contribution is greater than 100% .\n"
+
+        if self.progress_low_qstar == 'error':
+            try:
+                float(self.qlow)
+            except:
+                msg += "Error occurred when computing extrapolated invariant"
+                msg += " at low-Q region.\n"
+
+        elif self.progress_low_qstar is not None:
+            if self.progress_low_qstar >= 5:
+                msg += "Extrapolated contribution at Low Q is higher "
+                msg += "than 5% of the invariant.\n"
+            elif self.progress_low_qstar < 0:
+                msg += "Extrapolated contribution at Low Q < 0.\n"
+            elif self.progress_low_qstar > 100:
+                msg += "Extrapolated contribution at Low Q is greater "
+                msg += "than 100% .\n"
+
+        # High-Q
+        if self.progress_high_qstar == 'error':
+            try:
+                float(self.qhigh)
+            except:
+                msg += 'Error occurred when computing extrapolated'
+                msg += ' invariant at high-Q region.\n'
+
+        elif self.progress_high_qstar is not None:
+            if self.progress_high_qstar >= 5:
+                msg += "Extrapolated contribution at High Q is higher " \
+                       "than 5% of the invariant.\n"
+            elif self.progress_high_qstar < 0:
+
+                msg += "Extrapolated contribution at High Q < 0.\n"
+            elif self.progress_high_qstar > 100:
+
+                msg += "Extrapolated contribution at High Q is greater " \
+                       "than 100% .\n"
+
+        if (self.progress_low_qstar not in [None, "error"]) and \
+            (self.progress_high_qstar not in [None, "error"])\
+            and self.progress_low_qstar + self.progress_high_qstar >= 5:
+
+            msg += "The sum of all extrapolated contributions is higher " \
+                   "than 5% of the invariant.\n"
+
+        return msg
Index: src/sas/qtgui/Perspectives/Invariant/InvariantPerspective.py
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/InvariantPerspective.py	(revision 4992ff2626be19df7de9e5dfc0078b96bf47a75e)
+++ src/sas/qtgui/Perspectives/Invariant/InvariantPerspective.py	(revision f1f3e6a66c47bce134b59fe9f166fe14eac3a61d)
@@ -2,8 +2,11 @@
 import sys
 import os
+import logging
+import copy
+import webbrowser
+
 from PyQt5 import QtCore
-from PyQt5 import QtGui
-from PyQt5 import QtWidgets
-from PyQt5 import QtWebKitWidgets
+from PyQt5 import QtGui, QtWidgets
+from PyQt5 import QtWebKit
 
 from twisted.internet import threads
@@ -14,4 +17,6 @@
 from sas.qtgui.Plotting.PlotterData import Data1D
 import sas.qtgui.Utilities.GuiUtils as GuiUtils
+
+# import sas.qtgui.Plotting.PlotHelper as PlotHelper
 
 # local
@@ -26,21 +31,19 @@
 # the ratio of maximum q value/(qmax of data) to plot the theory data
 Q_MAXIMUM_PLOT = 3
-
-
-class MyModel(object):
-    def __init__(self):
-        self._model = QtGui.QStandardItemModel(self)
-
-    def addItem(self, item):
-        item = QtGui.QStandardItem(str(item))
-        self._model.appendRow(item)
+# Default number of points of interpolation: high and low range
+NPOINTS_Q_INTERP = 10
+# Default power law for interpolation
+DEFAULT_POWER_LOW = 4
+
+# Background of line edits if settings OK or wrong
+BG_WHITE = "background-color: rgb(255, 255, 255);"
+BG_RED = "background-color: rgb(244, 170, 164);"
 
 class InvariantWindow(QtWidgets.QDialog, Ui_tabbedInvariantUI):
     # The controller which is responsible for managing signal slots connections
     # for the gui and providing an interface to the data model.
-    name = "Invariant" # For displaying in the combo box
-    #def __init__(self, manager=None, parent=None):
+    name = "Invariant"  # For displaying in the combo box in DataExplorer
+
     def __init__(self, parent=None):
-        #super(InvariantWindow, self).__init__(parent)
         super(InvariantWindow, self).__init__()
         self.setupUi(self)
@@ -52,27 +55,33 @@
         self._scale = 1.0
         self._contrast = 1.0
-        self._porod = 1.0
-        self._npoints_low = 10
-        self._npoints_high = 10
-        self._power_low = 4
+        self._porod = None
+
+        self.parent = parent
 
         self._manager = parent
-        #self._manager = manager
         self._reactor = reactor
         self._model_item = QtGui.QStandardItem()
 
-        self._helpView = QtWebKitWidgets.QWebView()
+        #self._helpView = QtWebKit.QWebView()
         self.detailsDialog = DetailsDialog(self)
+        self.detailsDialog.cmdOK.clicked.connect(self.enabling)
 
         self._low_extrapolate = False
-        self._low_guinier  = True
-        self._low_fit  = True
+        self._low_guinier = True
+        self._low_fit = False
+        self._low_power_value = False
+        self._low_points = NPOINTS_Q_INTERP
+        self._low_power_value = DEFAULT_POWER_LOW
+
         self._high_extrapolate = False
-        self._high_power_value  = False
+        self._high_power_value = False
+        self._high_fit = False
+        self._high_points = NPOINTS_Q_INTERP
+        self._high_power_value = DEFAULT_POWER_LOW
 
         # no reason to have this widget resizable
         self.setFixedSize(self.minimumSizeHint())
 
-        self.communicate = GuiUtils.Communicate()
+        self.communicate = self._manager.communicator()
 
         self._data = None
@@ -81,17 +90,25 @@
         self._allow_close = False
 
-        # Mask file selector
-        ###################################################
-        #self._path = "cyl_400_20.txt"
-        #from sas.sascalc.dataloader.loader import  Loader
-        #loader = Loader()
-        #try:
-        #    self._data = loader.load(self._path)
-        #except:
-        #    raise
-        ###################################################
-
-        self.lineEdit_8.setText(str(Q_MINIMUM))
-        self.lineEdit_9.setText(str(Q_MAXIMUM))
+        # Modify font in order to display Angstrom symbol correctly
+        new_font = 'font-family: -apple-system, "Helvetica Neue", "Ubuntu";'
+        self.lblTotalQUnits.setStyleSheet(new_font)
+        self.lblSpecificSurfaceUnits.setStyleSheet(new_font)
+        self.lblInvariantTotalQUnits.setStyleSheet(new_font)
+        self.lblContrastUnits.setStyleSheet(new_font)
+        self.lblPorodCstUnits.setStyleSheet(new_font)
+        self.lblExtrapolQUnits.setStyleSheet(new_font)
+
+        # To remove blue square around line edits
+        self.txtBackgd.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False)
+        self.txtContrast.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False)
+        self.txtScale.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False)
+        self.txtPorodCst.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False)
+        self.txtNptsHighQ.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False)
+        self.txtNptsLowQ.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False)
+        self.txtPowerLowQ.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False)
+        self.txtPowerHighQ.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False)
+
+        self.txtExtrapolQMin.setText(str(Q_MINIMUM))
+        self.txtExtrapolQMax.setText(str(Q_MAXIMUM))
 
         # Let's choose the Standard Item Model.
@@ -108,13 +125,27 @@
         self.setupMapper()
 
-        new_font = 'font-family: -apple-system, "Helvetica Neue", "Ubuntu";'
-        self.label_2.setStyleSheet(new_font)
-        self.label_24.setStyleSheet(new_font)
-        self.label_27.setStyleSheet(new_font)
+        # validator: double
+        self.txtBackgd.setValidator(QtGui.QDoubleValidator())
+        self.txtContrast.setValidator(QtGui.QDoubleValidator())
+        self.txtScale.setValidator(QtGui.QDoubleValidator())
+        self.txtPorodCst.setValidator(QtGui.QDoubleValidator())
+
+        # validator: integer number
+        valid_regex_int = QtCore.QRegExp('^[+]?(\d+[.][0]*)$')
+        self.txtNptsLowQ.setValidator(QtGui.QRegExpValidator(valid_regex_int,
+                                                             self.txtNptsLowQ))
+        self.txtNptsHighQ.setValidator(QtGui.QRegExpValidator(valid_regex_int,
+                                                             self.txtNptsHighQ))
+        self.txtPowerLowQ.setValidator(QtGui.QRegExpValidator(valid_regex_int,
+                                                             self.txtPowerLowQ))
+        self.txtPowerHighQ.setValidator(QtGui.QRegExpValidator(valid_regex_int,
+                                                             self.txtPowerHighQ))
+
+    def enabling(self):
+        """ """
+        self.cmdStatus.setEnabled(True)
 
     def setClosable(self, value=True):
-        """
-        Allow outsiders close this widget
-        """
+        """ Allow outsiders close this widget """
         assert isinstance(value, bool)
 
@@ -134,86 +165,94 @@
             self.setWindowState(QtCore.Qt.WindowMinimized)
 
-    def communicator(self):
-        """ Getter for the communicator """
-        return self.communicate
-
     def updateFromModel(self):
-        """
-        update the globals based on the data in the model
-        """
+        """ Update the globals based on the data in the model """
         self._background = float(self.model.item(WIDGETS.W_BACKGROUND).text())
-        self._contrast   = float(self.model.item(WIDGETS.W_CONTRAST).text())
-        self._scale      = float(self.model.item(WIDGETS.W_SCALE).text())
-
-        # High extrapolate
-        self._low_extrapolate = ( str(self.model.item(WIDGETS.W_ENABLE_LOWQ).text()) == 'true')
+        self._contrast = float(self.model.item(WIDGETS.W_CONTRAST).text())
+        self._scale = float(self.model.item(WIDGETS.W_SCALE).text())
+        if self.model.item(WIDGETS.W_POROD_CST).text() != 'None' \
+                and self.model.item(WIDGETS.W_POROD_CST).text() != '':
+            self._porod = float(self.model.item(WIDGETS.W_POROD_CST).text())
+
+        # Low extrapolating
+        self._low_extrapolate = str(self.model.item(WIDGETS.W_ENABLE_LOWQ).text()) == 'true'
         self._low_points = float(self.model.item(WIDGETS.W_NPTS_LOWQ).text())
-        self._low_guinier  = ( str(self.model.item(WIDGETS.W_LOWQ_GUINIER).text()) == 'true')
-        self._low_fit  = ( str(self.model.item(WIDGETS.W_LOWQ_FIT).text()) == 'true')
-        self._low_power_value  = float(self.model.item(WIDGETS.W_LOWQ_POWER_VALUE).text())
+        self._low_guinier = str(self.model.item(WIDGETS.W_LOWQ_GUINIER).text()) == 'true'
+        self._low_fit = str(self.model.item(WIDGETS.W_LOWQ_FIT).text()) == 'true'
+        self._low_power_value = float(self.model.item(WIDGETS.W_LOWQ_POWER_VALUE).text())
 
         # High extrapolating
-        self._high_extrapolate = ( str(self.model.item(WIDGETS.W_ENABLE_HIGHQ).text()) == 'true')
-        self._high_points  = float(self.model.item(WIDGETS.W_NPTS_HIGHQ).text())
-        self._high_fit  = ( str(self.model.item(WIDGETS.W_HIGHQ_FIT).text()) == 'true')
-        self._high_power_value  = float(self.model.item(WIDGETS.W_HIGHQ_POWER_VALUE).text())
+        self._high_extrapolate = str(self.model.item(WIDGETS.W_ENABLE_HIGHQ).text()) == 'true'
+        self._high_points = float(self.model.item(WIDGETS.W_NPTS_HIGHQ).text())
+        self._high_fit = str(self.model.item(WIDGETS.W_HIGHQ_FIT).text()) == 'true'
+        self._high_power_value = float(self.model.item(WIDGETS.W_HIGHQ_POWER_VALUE).text())
 
     def calculateInvariant(self):
-        """
-        Use twisted to thread the calculations away.
-        """
+        """ Use twisted to thread the calculations away """
         # Find out if extrapolation needs to be used.
         extrapolation = None
-        if self._low_extrapolate  and not self._high_extrapolate:
+        if self._low_extrapolate and not self._high_extrapolate:
             extrapolation = "low"
-        elif not self._low_extrapolate  and self._high_extrapolate:
+        elif not self._low_extrapolate and self._high_extrapolate:
             extrapolation = "high"
         elif self._low_extrapolate and self._high_extrapolate:
             extrapolation = "both"
-        try:
-            # modify the Calculate button to indicate background process
-            self.pushButton.setText("Calculating...")
-            self.pushButton.setEnabled(False)
-            self.style = self.pushButton.styleSheet()
-            self.pushButton.setStyleSheet("background-color: rgb(255, 255, 0); color: rgb(0, 0, 0)")
-            # Send the calculations to separate thread.
-            d = threads.deferToThread(self.calculateThread, extrapolation)
-            # Add deferred callback for call return
-            d.addCallback(self.plotResult)
-            d.addErrback(self.plotFailed)
-        except Exception as ex:
-            # Set the button back to available
-            self.pushButton.setEnabled(True)
-            self.pushButton.setText("Calculate")
-            self.pushButton.setStyleSheet(self.style)
-
-    def plotFailed(self, reason):
-        """
-        """
-        print("plotFailed FAILED: ", reason)
+
+        # modify the Calculate button to indicate background process
+        self.cmdCalculate.setText("Calculating...")
+        self.cmdCalculate.setEnabled(False)
+
+        # Send the calculations to separate thread.
+        d = threads.deferToThread(self.calculateThread, extrapolation)
+
+        # Add deferred callback for call return
+        d.addCallback(self.deferredPlot)
+        d.addErrback(self.calculationFailed)
+
+    def calculationFailed(self, reason):
+        print("calculation failed: ", reason)
         pass
 
+    def deferredPlot(self, model):
+        """
+        Run the GUI/model update in the main thread
+        """
+        reactor.callFromThread(lambda: self.plotResult(model))
+
     def plotResult(self, model):
-        """
-        """
+        """ Plot result of calculation """
+        # Set the button back to available
+        self.cmdCalculate.setEnabled(True)
+        self.cmdCalculate.setText("Calculate")
+        self.cmdStatus.setEnabled(True)
+
         self.model = model
         self.mapper.toFirst()
-
-        # Set the button back to available
-        self.pushButton.setEnabled(True)
-        self.pushButton.setText("Calculate")
-        self.pushButton.setStyleSheet(self.style)
+        self._data = GuiUtils.dataFromItem(self._model_item)
 
         # Send the modified model item to DE for keeping in the model
-        self.communicate.updateModelFromPerspectiveSignal.emit(self._model_item)
-
+        # Currently -unused
+        #self.communicate.updateModelFromPerspectiveSignal.emit(self._model_item)
+
+        plot_data = GuiUtils.plotsFromCheckedItems(self._manager.filesWidget.model)
+
+        self._manager.filesWidget.plotData(plot_data)
+
+        # Update the details dialog in case it is open
+        self.updateDetailsWidget(model)
+
+    def updateDetailsWidget(self, model):
+        """
+        On demand update of the details widget
+        """
+        if self.detailsDialog.isVisible():
+            self.onStatus()
 
     def calculateThread(self, extrapolation):
         """
         Perform Invariant calculations.
-
         TODO: Create a dictionary of results to be sent to DE on completion.
         """
         self.updateFromModel()
+        msg = ''
 
         qstar_low = 0.0
@@ -222,12 +261,14 @@
         qstar_high_err = 0.0
         qstar_total = 0.0
-        qstar_total_low_err = 0.0
+        qstar_total_error = 0.0
+
+        temp_data = copy.deepcopy(self._data)
 
         # Prepare the invariant object
-        inv = invariant.InvariantCalculator(data=self._data,
-                                            background = self._background,
-                                            scale = self._scale)
-
+        inv = invariant.InvariantCalculator(data=temp_data,
+                                            background=self._background,
+                                            scale=self._scale)
         if self._low_extrapolate:
+
             function_low = "power_law"
             if self._low_guinier:
@@ -235,6 +276,7 @@
             if self._low_fit:
                 self._low_power_value = None
+
             inv.set_extrapolation(range="low",
-                                  npts=self._low_points,
+                                  npts=int(self._low_points),
                                   function=function_low,
                                   power=self._low_power_value)
@@ -243,15 +285,14 @@
             function_low = "power_law"
             inv.set_extrapolation(range="high",
-                                  npts=self._high_points,
+                                  npts=int(self._high_points),
                                   function=function_low,
-                                  power=self._low_power_value)
-
-        #Compute invariant
-        # TODO: proper exception handling and logic -
-        # display info, update lineedits, don't run extrapolations etc.
+                                  power=self._high_power_value)
+        # Compute invariant
         calculation_failed = False
+
         try:
-            qstar_total, qstar_total_error         = inv.get_qstar_with_error()
+            qstar_total, qstar_total_error = inv.get_qstar_with_error()
         except Exception as ex:
+            msg += str(ex)
             calculation_failed = True
             # Display relevant information
@@ -260,9 +301,12 @@
             item = QtGui.QStandardItem("ERROR")
             self.model.setItem(WIDGETS.W_INVARIANT_ERR, item)
+
         try:
             volume_fraction, volume_fraction_error = \
                 inv.get_volume_fraction_with_error(self._contrast)
+
         except Exception as ex:
             calculation_failed = True
+            msg += str(ex)
             # Display relevant information
             item = QtGui.QStandardItem("ERROR")
@@ -270,134 +314,208 @@
             item = QtGui.QStandardItem("ERROR")
             self.model.setItem(WIDGETS.W_VOLUME_FRACTION_ERR, item)
-        try:
-            surface, surface_error = \
-                inv.get_surface_with_error(self._contrast, self._porod)
-        except Exception as ex:
-            calculation_failed = True
-            # Display relevant information
-            item = QtGui.QStandardItem("ERROR")
-            self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE, item)
-            item = QtGui.QStandardItem("ERROR")
-            self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE_ERR, item)
-
-        if(calculation_failed):
-            # TODO: NOTIFY THE GUI MANAGER!!
+
+        if self._porod:
+            try:
+                surface, surface_error = \
+                    inv.get_surface_with_error(self._contrast, self._porod)
+            except Exception as ex:
+                calculation_failed = True
+                msg += str(ex)
+                # Display relevant information
+                item = QtGui.QStandardItem("ERROR")
+                self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE, item)
+                item = QtGui.QStandardItem("ERROR")
+                self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE_ERR, item)
+        else:
+            surface = None
+
+        if (calculation_failed):
             self.mapper.toFirst()
+            logging.warning('Calculation failed: {}'.format(msg))
             return self.model
-
-        if self._low_extrapolate:
-            # for presentation in InvariantDetails
-            qstar_low, qstar_low_err = inv.get_qstar_low()
-            extrapolated_data = inv.get_extra_data_low(self._low_points)
-            power_low = inv.get_extrapolation_power(range='low')
-
-            #inv.data = extrapolated_data
-            #qstar_total, qstar_total_error = inv.get_qstar_with_error()
-
-            # Plot the chart
-            title = "Low-Q extrapolation"
-
-            # Convert the data into plottable
-            extrapolated_data = self._manager.createGuiData(extrapolated_data)
-            extrapolated_data.name = title
-            extrapolated_data.title = title
-
-            # Add the plot to the model item
-            # This needs to run in the main thread
-            reactor.callFromThread(GuiUtils.updateModelItemWithPlot,
-                    self._model_item, extrapolated_data, title)
-
-        if self._high_extrapolate:
-            # for presentation in InvariantDetails
-            qmax_plot = Q_MAXIMUM_PLOT * max(self._data.x)
-            if qmax_plot > Q_MAXIMUM:
-                qmax_plot = Q_MAXIMUM
-            qstar_high, qstar_high_err = inv.get_qstar_high()
-            power_high = inv.get_extrapolation_power(range='high')
-            high_out_data = inv.get_extra_data_high(q_end=qmax_plot, npts=500)
-
-            # Plot the chart
-            title = "High-Q extrapolation"
-
-            # Convert the data into plottable
-            high_out_data = self._manager.createGuiData(high_out_data)
-            high_out_data.name = title
-            high_out_data.title = title
-
-            # Add the plot to the model item
-            # This needs to run in the main thread
-            reactor.callFromThread(GuiUtils.updateModelItemWithPlot,
-                    self._model_item, high_out_data, title)
-
-        item = QtGui.QStandardItem(str(float('%.5g'% volume_fraction)))
-        self.model.setItem(WIDGETS.W_VOLUME_FRACTION, item)
-        item = QtGui.QStandardItem(str(float('%.5g'% volume_fraction_error)))
-        self.model.setItem(WIDGETS.W_VOLUME_FRACTION_ERR, item)
-        item = QtGui.QStandardItem(str(float('%.5g'% surface)))
-        self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE, item)
-        item = QtGui.QStandardItem(str(float('%.5g'% surface_error)))
-        self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE_ERR, item)
-        item = QtGui.QStandardItem(str(float('%.5g'% qstar_total)))
-        self.model.setItem(WIDGETS.W_INVARIANT, item)
-        item = QtGui.QStandardItem(str(float('%.5g'% qstar_total_error)))
-        self.model.setItem(WIDGETS.W_INVARIANT_ERR, item)
-
-        #item = QtGui.QStandardItem(str(float('%.5g'% qstar_total)))
-        #self.model.setItem(WIDGETS.D_TOTAL_QSTAR, item)
-        #item = QtGui.QStandardItem(str(float('%.5g'% qstar_total_err)))
-        #self.model.setItem(WIDGETS.D_TOTAL_QSTAR_ERR, item)
-        item = QtGui.QStandardItem(str(float('%.5g'% qstar_low)))
-        self.model.setItem(WIDGETS.D_LOW_QSTAR, item)
-        item = QtGui.QStandardItem(str(float('%.5g'% qstar_low_err)))
-        self.model.setItem(WIDGETS.D_LOW_QSTAR_ERR, item)
-        item = QtGui.QStandardItem(str(float('%.5g'% qstar_high)))
-        self.model.setItem(WIDGETS.D_HIGH_QSTAR, item)
-        item = QtGui.QStandardItem(str(float('%.5g'% qstar_high_err)))
-        self.model.setItem(WIDGETS.D_HIGH_QSTAR_ERR, item)
-
-        self.mapper.toFirst()
-
-        return self.model
-                
+        else:
+
+            if self._low_extrapolate:
+                # for presentation in InvariantDetails
+                qstar_low, qstar_low_err = inv.get_qstar_low()
+                extrapolated_data = inv.get_extra_data_low(self._low_points)
+                power_low = inv.get_extrapolation_power(range='low')
+
+                # Plot the chart
+                title = "Low-Q extrapolation"
+
+                # Convert the data into plottable
+                extrapolated_data = self._manager.createGuiData(extrapolated_data)
+
+                extrapolated_data.name = title
+                extrapolated_data.title = title
+
+                # copy labels and units of axes for plotting
+                extrapolated_data._xaxis = temp_data._xaxis
+                extrapolated_data._xunit = temp_data._xunit
+                extrapolated_data._yaxis = temp_data._yaxis
+                extrapolated_data._yunit = temp_data._yunit
+
+                # Add the plot to the model item
+                # This needs to run in the main thread
+                reactor.callFromThread(GuiUtils.updateModelItemWithPlot,
+                                       self._model_item,
+                                       extrapolated_data,
+                                       title)
+
+            if self._high_extrapolate:
+                # for presentation in InvariantDetails
+                qmax_plot = Q_MAXIMUM_PLOT * max(temp_data.x) # self._data.x)
+
+                if qmax_plot > Q_MAXIMUM:
+                    qmax_plot = Q_MAXIMUM
+                qstar_high, qstar_high_err = inv.get_qstar_high()
+                power_high = inv.get_extrapolation_power(range='high')
+                high_out_data = inv.get_extra_data_high(q_end=qmax_plot, npts=500)
+
+                # Plot the chart
+                title = "High-Q extrapolation"
+
+                # Convert the data into plottable
+                high_out_data = self._manager.createGuiData(high_out_data)
+                high_out_data.name = title
+                high_out_data.title = title
+
+                # copy labels and units of axes for plotting
+                high_out_data._xaxis = temp_data._xaxis
+                high_out_data._xunit = temp_data._xunit
+                high_out_data._yaxis = temp_data._yaxis
+                high_out_data._yunit = temp_data._yunit
+
+                # Add the plot to the model item
+                # This needs to run in the main thread
+                reactor.callFromThread(GuiUtils.updateModelItemWithPlot,
+                                       self._model_item, high_out_data, title)
+
+            item = QtGui.QStandardItem(str(float('%.3g'% volume_fraction)))
+            self.model.setItem(WIDGETS.W_VOLUME_FRACTION, item)
+            item = QtGui.QStandardItem(str(float('%.3g'% volume_fraction_error)))
+            self.model.setItem(WIDGETS.W_VOLUME_FRACTION_ERR, item)
+            if surface:
+                item = QtGui.QStandardItem(str(float('%.3g'% surface)))
+                self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE, item)
+                item = QtGui.QStandardItem(str(float('%.3g'% surface_error)))
+                self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE_ERR, item)
+            item = QtGui.QStandardItem(str(float('%.3g'% qstar_total)))
+            self.model.setItem(WIDGETS.W_INVARIANT, item)
+            item = QtGui.QStandardItem(str(float('%.3g'% qstar_total_error)))
+            self.model.setItem(WIDGETS.W_INVARIANT_ERR, item)
+
+            item = QtGui.QStandardItem(str(float('%.3g'% qstar_low)))
+            self.model.setItem(WIDGETS.D_LOW_QSTAR, item)
+            item = QtGui.QStandardItem(str(float('%.3g'% qstar_low_err)))
+            self.model.setItem(WIDGETS.D_LOW_QSTAR_ERR, item)
+            item = QtGui.QStandardItem(str(float('%.3g'% qstar_high)))
+            self.model.setItem(WIDGETS.D_HIGH_QSTAR, item)
+            item = QtGui.QStandardItem(str(float('%.3g'% qstar_high_err)))
+            self.model.setItem(WIDGETS.D_HIGH_QSTAR_ERR, item)
+
+            self.mapper.toFirst()
+
+            return self.model
+
     def title(self):
-        """
-        Perspective name
-        """
+        """ Perspective name """
         return "Invariant panel"
 
-    def status(self):
-        """
+    def onStatus(self):
+        """
+        Display Invariant Details panel when clicking on Status button
         """
         self.detailsDialog.setModel(self.model)
         self.detailsDialog.showDialog()
-
-    def help(self):
-        """
-        """
-        _TreeLocation = GuiUtils.HELP_DIRECTORY_LOCATION + \
+        self.cmdStatus.setEnabled(False)
+
+    def onHelp(self):
+        """ Display help when clicking on Help button """
+        treeLocation = GuiUtils.HELP_DIRECTORY_LOCATION + \
             "/user/sasgui/perspectives/invariant/invariant_help.html"
-        self._helpView.load(QtCore.QUrl(_TreeLocation))
-        self._helpView.show()
+        webbrowser.open('file://' + treeLocation)
 
     def setupSlots(self):
-        self.pushButton.clicked.connect(self.calculateInvariant)
-        self.pushButton_2.clicked.connect(self.status)
-        self.pushButton_3.clicked.connect(self.help)
-
-        self.radioButton.toggled.connect(self.lowGuinierAndPowerToggle)
-        self.radioButton_8.toggled.connect(self.hiFitAndFixToggle)
-
-        self.radioButton_3.toggled.connect(self.lowFitAndFixToggle)
-
-        # Bug workaround for QDataWidgetMapper() not reacting to checkbox clicks.
-        # https://bugreports.qt.io/browse/QTBUG-1818
-        self.checkBox.clicked.connect(self.setFocus)
-        self.checkBox_2.clicked.connect(self.setFocus)
+        """ """
+        self.cmdCalculate.clicked.connect(self.calculateInvariant)
+        self.cmdStatus.clicked.connect(self.onStatus)
+        self.cmdHelp.clicked.connect(self.onHelp)
+
+        self.chkLowQ.stateChanged.connect(self.stateChanged)
+        self.chkLowQ.stateChanged.connect(self.checkQExtrapolatedData)
+
+        self.chkHighQ.stateChanged.connect(self.stateChanged)
+        self.chkHighQ.stateChanged.connect(self.checkQExtrapolatedData)
+
+        # slots for the Guinier and PowerLaw radio buttons at low Q
+        # since they are not auto-exclusive
+        self.rbGuinier.toggled.connect(self.lowGuinierAndPowerToggle)
+
+        self.rbPowerLawLowQ.toggled.connect(self.lowGuinierAndPowerToggle)
+
+        self.rbFitHighQ.toggled.connect(self.hiFitAndFixToggle)
+
+        self.rbFitLowQ.toggled.connect(self.lowFitAndFixToggle)
 
         self.model.itemChanged.connect(self.modelChanged)
 
+        # update model from gui editing by users
+        self.txtBackgd.textChanged.connect(self.updateFromGui)
+
+        self.txtScale.textChanged.connect(self.updateFromGui)
+
+        self.txtContrast.textChanged.connect(self.updateFromGui)
+
+        self.txtPorodCst.textChanged.connect(self.updateFromGui)
+
+        self.txtPowerLowQ.textChanged.connect(self.updateFromGui)
+
+        self.txtPowerHighQ.textChanged.connect(self.updateFromGui)
+
+        self.txtNptsLowQ.textChanged.connect(self.updateFromGui)
+
+        self.txtNptsHighQ.textChanged.connect(self.updateFromGui)
+
+        # check values of n_points compared to distribution length
+        if self.txtNptsLowQ.isEnabled():
+            self.txtNptsLowQ.textChanged.connect(self.checkLength)
+
+        if self.txtNptsHighQ.isEnabled():
+            self.txtNptsHighQ.textChanged.connect(self.checkLength)
+
+    def stateChanged(self):
+        """
+        Catch modifications from low- and high-Q extrapolation check boxes
+        """
+        sender = self.sender()
+
+        itemf = QtGui.QStandardItem(str(sender.isChecked()).lower())
+        if sender.text() == 'Enable Low-Q extrapolation':
+            self.model.setItem(WIDGETS.W_ENABLE_LOWQ, itemf)
+
+        if sender.text() == 'Enable High-Q extrapolation':
+            self.model.setItem(WIDGETS.W_ENABLE_HIGHQ, itemf)
+
+    def checkLength(self):
+        """
+        Validators of number of points for extrapolation.
+        Error if it is larger than the distribution length
+        """
+        if self._data:
+            if len(self._data.x) < int(self.sender().text()):
+                self.sender().setStyleSheet(QtCore.QString(BG_RED))
+                logging.warning('The number of points must be smaller than {}'.format(len(self._data.x)))
+                self.cmdCalculate.setEnabled(False)
+            else:
+                self.sender().setStyleSheet(QtCore.QString(BG_WHITE))
+                self.cmdCalculate.setEnabled(True)
+        else:
+            # logging.info('no data is loaded')
+            self.cmdCalculate.setEnabled(False)
+
     def modelChanged(self, item):
-        """
-        """
+        """ Update when model changed """
         if item.row() == WIDGETS.W_ENABLE_LOWQ:
             toggle = (str(item.text()) == 'true')
@@ -408,51 +526,117 @@
             self._high_extrapolate = toggle
             self.highQToggle(toggle)
-        
+
+    def checkQExtrapolatedData(self):
+        """
+        Match status of low or high-Q extrapolated data checkbox in
+        DataExplorer with low or high-Q extrapolation checkbox in invariant
+        panel
+        """
+        # name to search in DataExplorer
+        if 'Low' in str(self.sender().text()):
+            name = "Low-Q extrapolation"
+        if 'High' in str(self.sender().text()):
+            name = "High-Q extrapolation"
+
+        GuiUtils.updateModelItemStatus(self._manager.filesWidget.model,
+                                       self._path, name,
+                                       self.sender().checkState())
+
+    def updateFromGui(self):
+        """ Update model when new user inputs """
+        possible_senders = ['txtBackgd', 'txtContrast', 'txtPorodCst',
+                            'txtScale', 'txtPowerLowQ', 'txtPowerHighQ',
+                            'txtNptsLowQ', 'txtNptsHighQ']
+
+        related_widgets = [WIDGETS.W_BACKGROUND, WIDGETS.W_CONTRAST,
+                           WIDGETS.W_POROD_CST, WIDGETS.W_SCALE,
+                           WIDGETS.W_LOWQ_POWER_VALUE, WIDGETS.W_HIGHQ_POWER_VALUE,
+                           WIDGETS.W_NPTS_LOWQ, WIDGETS.W_NPTS_HIGHQ]
+
+        related_internal_values = [self._background, self._contrast,
+                                   self._porod, self._scale,
+                                   self._low_power_value,
+                                   self._high_power_value,
+                                   self._low_points, self._high_points]
+
+        item = QtGui.QStandardItem(self.sender().text())
+
+        index_elt = possible_senders.index(self.sender().objectName())
+
+        self.model.setItem(related_widgets[index_elt], item)
+
+        related_internal_values[index_elt] = float(self.sender().text())
+
+        # print possible_senders[index_elt], related_internal_values[index_elt]
+
+        self.mapper.toFirst()
+
     def lowGuinierAndPowerToggle(self, toggle):
         """
-        """
-        self._low_guinier = toggle
+        Guinier and Power radio buttons cannot be selected at the same time
+        If Power is selected, Fit and Fix radio buttons are visible and
+        Power line edit can be edited if Fix is selected
+        """
+        if self.sender().text() == 'Guinier':
+            self._low_guinier = toggle
+
+            toggle = not toggle
+            self.rbPowerLawLowQ.setChecked(toggle)
+
+            self.rbFitLowQ.toggled.connect(self.lowFitAndFixToggle)
+            self.rbFitLowQ.setVisible(toggle)
+            self.rbFixLowQ.setVisible(toggle)
+
+            self.txtPowerLowQ.setEnabled(toggle and (not self._low_fit))
+
+        else:
+            self._low_guinier = not toggle
+
+            self.rbGuinier.setChecked(not toggle)
+
+            self.rbFitLowQ.toggled.connect(self.lowFitAndFixToggle)
+            self.rbFitLowQ.setVisible(toggle)
+            self.rbFixLowQ.setVisible(toggle)
+
+            self.txtPowerLowQ.setEnabled(toggle and (not self._low_fit))
+
+    def lowFitAndFixToggle(self, toggle):
+        """ Fit and Fix radiobuttons cannot be selected at the same time """
+        self._low_fit = toggle
+
         toggle = not toggle
-        self.lineEdit_11.setEnabled(toggle)
-        self.radioButton_3.setEnabled(toggle)
-        self.radioButton_4.setEnabled(toggle)
-        self.lineEdit_11.setEnabled(toggle and (not self._low_fit))
-
-    def lowFitAndFixToggle(self, toggle):
-        """
-        """
-        self._low_fit = toggle
-        toggle = not toggle
-        self.lineEdit_11.setEnabled(toggle)
+        self.txtPowerLowQ.setEnabled(toggle)
 
     def hiFitAndFixToggle(self, toggle):
         """
-        """
-        self.lineEdit_13.setEnabled(toggle)
+        Enable editing of power exponent if Fix for high Q is checked
+        Disable otherwise
+        """
+        self.txtPowerHighQ.setEnabled(not toggle)
 
     def highQToggle(self, clicked):
-        """
-        Disable/enable High Q extrapolation
-        """
-        self.radioButton_7.setEnabled(clicked)
-        self.radioButton_8.setEnabled(clicked)
-        self.lineEdit_12.setEnabled(clicked)
-        self.lineEdit_13.setEnabled(clicked)
+        """ Disable/enable High Q extrapolation """
+        self.rbFitHighQ.setEnabled(clicked)
+        self.rbFixHighQ.setEnabled(clicked)
+        self.txtNptsHighQ.setEnabled(clicked)
+        self.txtPowerHighQ.setEnabled(clicked)
 
     def lowQToggle(self, clicked):
-        """
-        Disable/enable Low Q extrapolation
-        """
-        self.radioButton.setEnabled(clicked)
-        self.radioButton_2.setEnabled(clicked)
-        self.lineEdit_11.setEnabled(clicked and not self._low_fit)
-
+        """ Disable / enable Low Q extrapolation """
+        self.rbGuinier.setEnabled(clicked)
+        self.rbPowerLawLowQ.setEnabled(clicked)
+        self.txtNptsLowQ.setEnabled(clicked)
         # Enable subelements
-        self.radioButton_3.setEnabled(clicked and not self._low_guinier)
-        self.radioButton_4.setEnabled(clicked and not self._low_guinier)
-        self.lineEdit_10.setEnabled(clicked and not self._low_guinier)
+        self.rbFitLowQ.setVisible(self.rbPowerLawLowQ.isChecked())
+        self.rbFixLowQ.setVisible(self.rbPowerLawLowQ.isChecked())
+        self.rbFitLowQ.setEnabled(clicked)  # and not self._low_guinier)
+        self.rbFixLowQ.setEnabled(clicked)  # and not self._low_guinier)
+
+        self.txtPowerLowQ.setEnabled(clicked
+                                    and not self._low_guinier
+                                    and not self._low_fit)
 
     def setupModel(self):
-
+        """ """
         # filename
         item = QtGui.QStandardItem(self._path)
@@ -460,5 +644,4 @@
 
         # add Q parameters to the model
-        #qmin = min(self._data.x)
         qmin = 0.0
         item = QtGui.QStandardItem(str(qmin))
@@ -475,5 +658,11 @@
         item = QtGui.QStandardItem(str(self._scale))
         self.model.setItem(WIDGETS.W_SCALE, item)
-        
+        # leave line edit empty if Porod constant not defined
+        if self._porod != None:
+            item = QtGui.QStandardItem(str(self._porod))
+        else:
+            item = QtGui.QStandardItem(str(''))
+        self.model.setItem(WIDGETS.W_POROD_CST, item)
+
         # Dialog elements
         itemf = QtGui.QStandardItem("false")
@@ -482,7 +671,7 @@
         self.model.setItem(WIDGETS.W_ENABLE_LOWQ, itemf)
 
-        item = QtGui.QStandardItem(str(self._npoints_low))
+        item = QtGui.QStandardItem(str(NPOINTS_Q_INTERP))
         self.model.setItem(WIDGETS.W_NPTS_LOWQ, item)
-        item = QtGui.QStandardItem(str(self._npoints_high))
+        item = QtGui.QStandardItem(str(NPOINTS_Q_INTERP))
         self.model.setItem(WIDGETS.W_NPTS_HIGHQ, item)
 
@@ -492,12 +681,11 @@
         itemt = QtGui.QStandardItem("true")
         self.model.setItem(WIDGETS.W_LOWQ_FIT, itemt)
-        item = QtGui.QStandardItem(str(self._power_low))
+        item = QtGui.QStandardItem(str(DEFAULT_POWER_LOW))
         self.model.setItem(WIDGETS.W_LOWQ_POWER_VALUE, item)
 
         itemt = QtGui.QStandardItem("true")
         self.model.setItem(WIDGETS.W_HIGHQ_FIT, itemt)
-        item = QtGui.QStandardItem(str(self._power_low))
+        item = QtGui.QStandardItem(str(DEFAULT_POWER_LOW))
         self.model.setItem(WIDGETS.W_HIGHQ_POWER_VALUE, item)
-
 
     def setupMapper(self):
@@ -507,49 +695,57 @@
         self.mapper.setModel(self.model)
 
-        # Set up the view on the model for testing
-        # self.tableView.setModel(self.model)
-
         # Filename
-        self.mapper.addMapping(self.lineEdit, WIDGETS.W_FILENAME)
+        self.mapper.addMapping(self.txtName, WIDGETS.W_FILENAME)
+
         # Qmin/Qmax
-        self.mapper.addMapping(self.lineEdit_2, WIDGETS.W_QMIN)
-        self.mapper.addMapping(self.lineEdit_3, WIDGETS.W_QMAX)
+        self.mapper.addMapping(self.txtTotalQMin, WIDGETS.W_QMIN)
+        self.mapper.addMapping(self.txtTotalQMax, WIDGETS.W_QMAX)
 
         # Background
-        self.mapper.addMapping(self.lineEdit_4, WIDGETS.W_BACKGROUND)
+        self.mapper.addMapping(self.txtBackgd, WIDGETS.W_BACKGROUND)
+
         # Scale
-        self.mapper.addMapping(self.lineEdit_5, WIDGETS.W_SCALE)
+        self.mapper.addMapping(self.txtScale, WIDGETS.W_SCALE)
+
         # Contrast
-        self.mapper.addMapping(self.lineEdit_6, WIDGETS.W_CONTRAST)
+        self.mapper.addMapping(self.txtContrast, WIDGETS.W_CONTRAST)
+
+        # Porod constant
+        self.mapper.addMapping(self.txtPorodCst, WIDGETS.W_POROD_CST)
 
         # Lowq/Highq items
-        self.mapper.addMapping(self.checkBox, WIDGETS.W_ENABLE_LOWQ)
-        self.mapper.addMapping(self.checkBox_2, WIDGETS.W_ENABLE_HIGHQ)
-
-        self.mapper.addMapping(self.lineEdit_10, WIDGETS.W_NPTS_LOWQ)
-        self.mapper.addMapping(self.radioButton, WIDGETS.W_LOWQ_GUINIER)
-
-        self.mapper.addMapping(self.radioButton_3, WIDGETS.W_LOWQ_FIT)
-        self.mapper.addMapping(self.lineEdit_11, WIDGETS.W_LOWQ_POWER_VALUE)
-
-        self.mapper.addMapping(self.radioButton_7, WIDGETS.W_HIGHQ_FIT)
-        self.mapper.addMapping(self.lineEdit_13, WIDGETS.W_HIGHQ_POWER_VALUE)
+        self.mapper.addMapping(self.chkLowQ, WIDGETS.W_ENABLE_LOWQ)
+        self.mapper.addMapping(self.chkHighQ, WIDGETS.W_ENABLE_HIGHQ)
+
+        self.mapper.addMapping(self.txtNptsLowQ, WIDGETS.W_NPTS_LOWQ)
+        self.mapper.addMapping(self.rbGuinier, WIDGETS.W_LOWQ_GUINIER)
+        self.mapper.addMapping(self.rbFitLowQ, WIDGETS.W_LOWQ_FIT)
+        self.mapper.addMapping(self.txtPowerLowQ, WIDGETS.W_LOWQ_POWER_VALUE)
+
+        self.mapper.addMapping(self.txtNptsHighQ, WIDGETS.W_NPTS_HIGHQ)
+        self.mapper.addMapping(self.rbFitHighQ, WIDGETS.W_HIGHQ_FIT)
+        self.mapper.addMapping(self.txtPowerHighQ, WIDGETS.W_HIGHQ_POWER_VALUE)
     
         # Output
-        self.mapper.addMapping(self.lineEdit_14, WIDGETS.W_VOLUME_FRACTION)
-        self.mapper.addMapping(self.lineEdit_15, WIDGETS.W_VOLUME_FRACTION_ERR)
-        self.mapper.addMapping(self.lineEdit_16, WIDGETS.W_SPECIFIC_SURFACE)
-        self.mapper.addMapping(self.lineEdit_17, WIDGETS.W_SPECIFIC_SURFACE_ERR)
-        self.mapper.addMapping(self.lineEdit_19, WIDGETS.W_INVARIANT)
-        self.mapper.addMapping(self.lineEdit_18, WIDGETS.W_INVARIANT_ERR)
-
-        # FIXME DOESNT WORK WITH QT5
-        #self.mapper.toFirst()
-
-    def setData(self, data_item, is_batch=False):
+        self.mapper.addMapping(self.txtVolFract, WIDGETS.W_VOLUME_FRACTION)
+        self.mapper.addMapping(self.txtVolFractErr, WIDGETS.W_VOLUME_FRACTION_ERR)
+        self.mapper.addMapping(self.txtSpecSurf, WIDGETS.W_SPECIFIC_SURFACE)
+        self.mapper.addMapping(self.txtSpecSurfErr, WIDGETS.W_SPECIFIC_SURFACE_ERR)
+        self.mapper.addMapping(self.txtInvariantTot, WIDGETS.W_INVARIANT)
+        self.mapper.addMapping(self.txtInvariantTotErr, WIDGETS.W_INVARIANT_ERR)
+
+        self.mapper.toFirst()
+
+    def setData(self, data_item=None, is_batch=False):
         """
         Obtain a QStandardItem object and dissect it to get Data1D/2D
         Pass it over to the calculator
         """
+        assert data_item is not None
+
+        if self.txtName.text() == data_item[0].text():
+            logging.info('This file is already loaded in Invariant panel.')
+            return
+
         if not isinstance(data_item, list):
             msg = "Incorrect type passed to the Invariant Perspective"
@@ -560,84 +756,46 @@
             raise AttributeError(msg)
 
+        # only 1 file can be loaded
         self._model_item = data_item[0]
 
         # Extract data on 1st child - this is the Data1D/2D component
         data = GuiUtils.dataFromItem(self._model_item)
-        self.model.item(WIDGETS.W_FILENAME).setData(self._model_item.text())
-
-        ##### DEBUG ####
-        # set data in the debug tree view window
-        self.treeView.setModel(self.model)
-
-        self.calculate(data_list=[data])
-        
-    def calculate(self, data_list=None):
-        """
-        receive a list of data and compute invariant
-
-        TODO: pass warnings/messages to log
-        """
-        msg = ""
-        data = None
-        if data_list is None:
-            data_list = []
-        if len(data_list) >= 1:
-            if len(data_list) == 1:
-                data = data_list[0]
-            else:
-                data_1d_list = []
-                data_2d_list = []
-                error_msg = ""
-                # separate data into data1d and data2d list
-                for data in data_list:
-                    if data is not None:
-                        if issubclass(data.__class__, Data1D):
-                            data_1d_list.append(data)
-                        else:
-                            error_msg += " %s  type %s \n" % (str(data.name),
-                                                              str(data.__class__.__name__))
-                            data_2d_list.append(data)
-                if len(data_2d_list) > 0:
-                    msg = "Invariant does not support the following data types:\n"
-                    msg += error_msg
-                if len(data_1d_list) == 0:
-                    # remake this as a qt event
-                    #wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
-                    return
-
-                # TODO: add msgbox for data choice
-                #msg += "Invariant panel does not allow multiple data!\n"
-                #msg += "Please select one.\n"
-                #if len(data_list) > 1:
-                    #from invariant_widgets import DataDialog
-                    #dlg = DataDialog(data_list=data_1d_list, text=msg)
-                    #if dlg.ShowModal() == wx.ID_OK:
-                    #    data = dlg.get_data()
-                    #else:
-                    #    data = None
-                    #dlg.Destroy()
-
-            if data is None:
-                msg += "invariant receives no data. \n"
-                #wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
-                return
-            if not issubclass(data.__class__, Data1D):
-                msg += "invariant cannot be computed for data of "
-                msg += "type %s\n" % (data.__class__.__name__)
-                #wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
-                return
-            else:
-                #wx.PostEvent(self.parent, NewPlotEvent(plot=data, title=data.title))
-                try:
-                    self._data = data
-                    self._path = "unique path"
-                    self.calculateInvariant()
-                except:
-                    msg = "Invariant Set_data: " + str(sys.exc_info()[1])
-                    #wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
-        else:
-            msg = "invariant cannot be computed for data of "
-            msg += "type %s" % (data.__class__.__name__)
-            #wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
+        self.model.item(WIDGETS.W_FILENAME).setData(QtCore.QVariant(self._model_item.text()))
+        # update GUI and model with info from loaded data
+        self.updateGuiFromFile(data=data)
+
+    def updateGuiFromFile(self, data=None):
+        """
+        update display in GUI and plot
+        """
+        self._data = data
+
+        # plot loaded file
+        if not isinstance(self._data, Data1D):
+            msg = "Error(s) occurred: Invariant cannot be computed with 2D data."
+            raise AttributeError(msg)
+
+        try:
+            filename = data.filename
+        except:
+            msg = 'No filename'
+            raise ValueError(msg)
+        try:
+            qmin = min(self._data.x)
+            qmax = max(self._data.x)
+        except:
+            msg = "Unable to find q min/max of \n data named %s" % \
+                  data.filename
+            raise ValueError(msg)
+
+        # update model with input form files: filename, qmin, qmax
+        self.model.item(WIDGETS.W_FILENAME).setText(filename)
+        self.model.item(WIDGETS.W_QMIN).setText(str(qmin))
+        self.model.item(WIDGETS.W_QMAX).setText(str(qmax))
+        self._path = filename
+
+        # Calculate and add to GUI: volume fraction, invariant total,
+        # and specific surface if porod checked
+        self.calculateInvariant()
 
     def allowBatch(self):
Index: src/sas/qtgui/Perspectives/Invariant/InvariantUtils.py
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/InvariantUtils.py	(revision b3e8629bf18b74f4214d6552e620fcbc4e73a28c)
+++ src/sas/qtgui/Perspectives/Invariant/InvariantUtils.py	(revision f1f3e6a66c47bce134b59fe9f166fe14eac3a61d)
@@ -3,24 +3,25 @@
     return type('Enum', (), enums)
 
-WIDGETS = enum( 'W_FILENAME',           #0
-                'W_QMIN',               #1
-                'W_QMAX',               #2
-                'W_BACKGROUND',         #3
-                'W_SCALE',              #4
-                'W_CONTRAST',           #5
-                'W_EX_QMIN',            #6
-                'W_EX_QMAX',            #7
-                'W_ENABLE_LOWQ',        #8
-                'W_ENABLE_HIGHQ',       #9
-                'W_NPTS_LOWQ',          #10
-                'W_NPTS_HIGHQ',         #11
-                'W_LOWQ_GUINIER',       #12
-                'W_LOWQ_POWER',         #13
-                'W_LOWQ_FIT',           #14
-                'W_LOWQ_FIX',           #15
-                'W_LOWQ_POWER_VALUE',   #16
-                'W_HIGHQ_FIT',          #17
-                'W_HIGHQ_FIX',          #18
-                'W_HIGHQ_POWER_VALUE',  #19
+WIDGETS = enum( 'W_FILENAME',
+                'W_QMIN',
+                'W_QMAX',
+                'W_BACKGROUND',
+                'W_SCALE',
+                'W_CONTRAST',
+                'W_POROD_CST',
+                'W_EX_QMIN',
+                'W_EX_QMAX',
+                'W_ENABLE_LOWQ',
+                'W_ENABLE_HIGHQ',
+                'W_NPTS_LOWQ',
+                'W_NPTS_HIGHQ',
+                'W_LOWQ_GUINIER',
+                'W_LOWQ_POWER',
+                'W_LOWQ_FIT',
+                'W_LOWQ_FIX',
+                'W_LOWQ_POWER_VALUE',
+                'W_HIGHQ_FIT',
+                'W_HIGHQ_FIX',
+                'W_HIGHQ_POWER_VALUE',
                 # results
                 'W_VOLUME_FRACTION',
Index: src/sas/qtgui/Perspectives/Invariant/UI/InvariantDetailsUI.ui
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/UI/InvariantDetailsUI.ui	(revision 457d961a927e24e28718d1c1813be6b69130b5c1)
+++ src/sas/qtgui/Perspectives/Invariant/UI/InvariantDetailsUI.ui	(revision f1f3e6a66c47bce134b59fe9f166fe14eac3a61d)
@@ -7,7 +7,13 @@
     <x>0</x>
     <y>0</y>
-    <width>449</width>
+    <width>511</width>
     <height>458</height>
    </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
   </property>
   <property name="windowTitle">
@@ -29,5 +35,5 @@
       </item>
       <item row="0" column="1">
-       <widget class="QProgressBar" name="progressBar">
+       <widget class="QProgressBar" name="progressBarLowQ">
         <property name="value">
          <number>24</number>
@@ -43,5 +49,5 @@
       </item>
       <item row="1" column="1">
-       <widget class="QProgressBar" name="progressBar_2">
+       <widget class="QProgressBar" name="progressBarData">
         <property name="value">
          <number>24</number>
@@ -57,5 +63,5 @@
       </item>
       <item row="2" column="1">
-       <widget class="QProgressBar" name="progressBar_3">
+       <widget class="QProgressBar" name="progressBarHighQ">
         <property name="value">
          <number>24</number>
@@ -80,5 +86,9 @@
       </item>
       <item row="0" column="1">
-       <widget class="QLineEdit" name="lineEdit"/>
+       <widget class="QLineEdit" name="txtQLowQ">
+        <property name="toolTip">
+         <string>Extrapolated invariant from low-Q range.</string>
+        </property>
+       </widget>
       </item>
       <item row="0" column="2">
@@ -90,11 +100,15 @@
       </item>
       <item row="0" column="3">
-       <widget class="QLineEdit" name="lineEdit_2"/>
+       <widget class="QLineEdit" name="txtQLowQErr">
+        <property name="toolTip">
+         <string>Uncertainty on the invariant from low-Q range.</string>
+        </property>
+       </widget>
       </item>
       <item row="0" column="4">
-       <widget class="QLabel" name="label_3">
-        <property name="text">
-         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;[1/(cm*Ã
-&lt;span style=&quot; vertical-align:super;&quot;&gt;3&lt;/span&gt;)]&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+       <widget class="QLabel" name="lblQLowQUnits">
+        <property name="text">
+         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;(cm Ã
+&lt;span style=&quot; vertical-align:super;&quot;&gt;3&lt;/span&gt;)&lt;span style=&quot; vertical-align:super;&quot;&gt;-1&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
         </property>
        </widget>
@@ -108,5 +122,9 @@
       </item>
       <item row="1" column="1">
-       <widget class="QLineEdit" name="lineEdit_3"/>
+       <widget class="QLineEdit" name="txtQData">
+        <property name="toolTip">
+         <string>Invariant in the data set's Q range.</string>
+        </property>
+       </widget>
       </item>
       <item row="1" column="2">
@@ -118,11 +136,15 @@
       </item>
       <item row="1" column="3">
-       <widget class="QLineEdit" name="lineEdit_4"/>
+       <widget class="QLineEdit" name="txtQDataErr">
+        <property name="toolTip">
+         <string>Uncertainty on the invariant from data's range.</string>
+        </property>
+       </widget>
       </item>
       <item row="1" column="4">
-       <widget class="QLabel" name="label_4">
-        <property name="text">
-         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;[1/(cm*Ã
-&lt;span style=&quot; vertical-align:super;&quot;&gt;3&lt;/span&gt;)]&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+       <widget class="QLabel" name="lblQDataUnits">
+        <property name="text">
+         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;(cm Ã
+&lt;span style=&quot; vertical-align:super;&quot;&gt;3&lt;/span&gt;)&lt;span style=&quot; vertical-align:super;&quot;&gt;-1&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
         </property>
        </widget>
@@ -136,5 +158,9 @@
       </item>
       <item row="2" column="1">
-       <widget class="QLineEdit" name="lineEdit_5"/>
+       <widget class="QLineEdit" name="txtQHighQ">
+        <property name="toolTip">
+         <string>Extrapolated invariant from high-Q range.</string>
+        </property>
+       </widget>
       </item>
       <item row="2" column="2">
@@ -146,11 +172,15 @@
       </item>
       <item row="2" column="3">
-       <widget class="QLineEdit" name="lineEdit_6"/>
+       <widget class="QLineEdit" name="txtQHighQErr">
+        <property name="toolTip">
+         <string>Uncertainty on the invariant from high-Q range.</string>
+        </property>
+       </widget>
       </item>
       <item row="2" column="4">
-       <widget class="QLabel" name="label_7">
-        <property name="text">
-         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;[1/(cm*Ã
-&lt;span style=&quot; vertical-align:super;&quot;&gt;3&lt;/span&gt;)]&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+       <widget class="QLabel" name="lblQHighQUnits">
+        <property name="text">
+         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;(cm Ã
+&lt;span style=&quot; vertical-align:super;&quot;&gt;3&lt;/span&gt;)&lt;span style=&quot; vertical-align:super;&quot;&gt;-1&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
         </property>
        </widget>
@@ -179,5 +209,5 @@
    </item>
    <item row="3" column="0">
-    <widget class="QDialogButtonBox" name="buttonBox">
+    <widget class="QDialogButtonBox" name="cmdOK">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
@@ -193,5 +223,5 @@
  <connections>
   <connection>
-   <sender>buttonBox</sender>
+   <sender>cmdOK</sender>
    <signal>accepted()</signal>
    <receiver>Dialog</receiver>
@@ -209,5 +239,5 @@
   </connection>
   <connection>
-   <sender>buttonBox</sender>
+   <sender>cmdOK</sender>
    <signal>rejected()</signal>
    <receiver>Dialog</receiver>
Index: src/sas/qtgui/Perspectives/Invariant/UI/TabbedInvariantUI.ui
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/UI/TabbedInvariantUI.ui	(revision 469b4622e645f3163e4b64cfbeb2a49e591cc359)
+++ src/sas/qtgui/Perspectives/Invariant/UI/TabbedInvariantUI.ui	(revision f1f3e6a66c47bce134b59fe9f166fe14eac3a61d)
@@ -7,7 +7,13 @@
     <x>0</x>
     <y>0</y>
-    <width>466</width>
-    <height>408</height>
+    <width>601</width>
+    <height>473</height>
    </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
   </property>
   <property name="windowTitle">
@@ -15,4 +21,67 @@
   </property>
   <layout class="QGridLayout" name="gridLayout_11">
+   <item row="1" column="0">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>2</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout_8">
+     <item>
+      <widget class="QPushButton" name="cmdCalculate">
+       <property name="toolTip">
+        <string>Compute invariant</string>
+       </property>
+       <property name="text">
+        <string>Calculate</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="cmdStatus">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="toolTip">
+        <string>Get more details of computation such as fraction from extrapolation</string>
+       </property>
+       <property name="text">
+        <string>Status</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="cmdHelp">
+       <property name="toolTip">
+        <string/>
+       </property>
+       <property name="text">
+        <string>Help</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
    <item row="0" column="0">
     <widget class="QTabWidget" name="tabWidget">
@@ -34,5 +103,5 @@
            <layout class="QHBoxLayout" name="horizontalLayout_4">
             <item>
-             <widget class="QLabel" name="label">
+             <widget class="QLabel" name="lblName">
               <property name="text">
                <string>Name:</string>
@@ -41,7 +110,7 @@
             </item>
             <item>
-             <widget class="QLineEdit" name="lineEdit">
+             <widget class="QLineEdit" name="txtName">
               <property name="enabled">
-               <bool>true</bool>
+               <bool>false</bool>
               </property>
               <property name="frame">
@@ -64,5 +133,5 @@
               <layout class="QHBoxLayout" name="horizontalLayout">
                <item>
-                <widget class="QLabel" name="label_3">
+                <widget class="QLabel" name="lblTotalQMin">
                  <property name="text">
                   <string>Min:</string>
@@ -71,5 +140,5 @@
                </item>
                <item>
-                <widget class="QLineEdit" name="lineEdit_2">
+                <widget class="QLineEdit" name="txtTotalQMin">
                  <property name="enabled">
                   <bool>false</bool>
@@ -78,5 +147,5 @@
                </item>
                <item>
-                <widget class="QLabel" name="label_4">
+                <widget class="QLabel" name="lblTotalQMax">
                  <property name="text">
                   <string>Max:</string>
@@ -85,5 +154,5 @@
                </item>
                <item>
-                <widget class="QLineEdit" name="lineEdit_3">
+                <widget class="QLineEdit" name="txtTotalQMax">
                  <property name="enabled">
                   <bool>false</bool>
@@ -92,5 +161,5 @@
                </item>
                <item>
-                <widget class="QLabel" name="label_2">
+                <widget class="QLabel" name="lblTotalQUnits">
                  <property name="text">
                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ã
@@ -121,7 +190,7 @@
           </item>
           <item row="0" column="1">
-           <widget class="QLineEdit" name="lineEdit_14">
+           <widget class="QLineEdit" name="txtVolFract">
             <property name="enabled">
-             <bool>true</bool>
+             <bool>false</bool>
             </property>
             <property name="autoFillBackground">
@@ -150,7 +219,7 @@
           </item>
           <item row="0" column="3">
-           <widget class="QLineEdit" name="lineEdit_15">
+           <widget class="QLineEdit" name="txtVolFractErr">
             <property name="enabled">
-             <bool>true</bool>
+             <bool>false</bool>
             </property>
             <property name="frame">
@@ -173,7 +242,7 @@
           </item>
           <item row="1" column="1">
-           <widget class="QLineEdit" name="lineEdit_17">
+           <widget class="QLineEdit" name="txtSpecSurf">
             <property name="enabled">
-             <bool>true</bool>
+             <bool>false</bool>
             </property>
             <property name="frame">
@@ -196,7 +265,7 @@
           </item>
           <item row="1" column="3">
-           <widget class="QLineEdit" name="lineEdit_16">
+           <widget class="QLineEdit" name="txtSpecSurfErr">
             <property name="enabled">
-             <bool>true</bool>
+             <bool>false</bool>
             </property>
             <property name="frame">
@@ -212,5 +281,5 @@
           </item>
           <item row="1" column="4">
-           <widget class="QLabel" name="label_24">
+           <widget class="QLabel" name="lblSpecificSurfaceUnits">
             <property name="text">
              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ã
@@ -234,11 +303,10 @@
           </item>
           <item row="3" column="1">
-           <widget class="QLineEdit" name="lineEdit_19">
+           <widget class="QLineEdit" name="txtInvariantTot">
             <property name="enabled">
-             <bool>true</bool>
-            </property>
-            <property name="styleSheet">
-             <string notr="true">background-color: rgb(253, 253, 126);
-font: bold 8pt &quot;MS Shell Dlg 2&quot;;</string>
+             <bool>false</bool>
+            </property>
+            <property name="toolTip">
+             <string>Total invariant [Q*], including extrapolated regions.</string>
             </property>
             <property name="frame">
@@ -261,11 +329,7 @@
           </item>
           <item row="3" column="3">
-           <widget class="QLineEdit" name="lineEdit_18">
+           <widget class="QLineEdit" name="txtInvariantTotErr">
             <property name="enabled">
-             <bool>true</bool>
-            </property>
-            <property name="styleSheet">
-             <string notr="true">background-color: rgb(253, 253, 126);
-font: bold 8pt &quot;MS Shell Dlg 2&quot;;</string>
+             <bool>false</bool>
             </property>
             <property name="frame">
@@ -281,5 +345,5 @@
           </item>
           <item row="3" column="4">
-           <widget class="QLabel" name="label_27">
+           <widget class="QLabel" name="lblInvariantTotalQUnits">
             <property name="text">
              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;(cm Ã
@@ -314,5 +378,5 @@
             </item>
             <item row="0" column="1">
-             <widget class="QLineEdit" name="lineEdit_4"/>
+             <widget class="QLineEdit" name="txtBackgd"/>
             </item>
             <item row="0" column="2">
@@ -331,5 +395,5 @@
             </item>
             <item row="0" column="4">
-             <widget class="QLineEdit" name="lineEdit_6"/>
+             <widget class="QLineEdit" name="txtScale"/>
             </item>
             <item row="1" column="0">
@@ -341,8 +405,8 @@
             </item>
             <item row="1" column="1">
-             <widget class="QLineEdit" name="lineEdit_5"/>
+             <widget class="QLineEdit" name="txtContrast"/>
             </item>
             <item row="1" column="2">
-             <widget class="QLabel" name="label_7">
+             <widget class="QLabel" name="lblContrastUnits">
               <property name="text">
                <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ã
@@ -359,8 +423,12 @@
             </item>
             <item row="1" column="4">
-             <widget class="QLineEdit" name="lineEdit_7"/>
+             <widget class="QLineEdit" name="txtPorodCst">
+              <property name="toolTip">
+               <string>Porod constant (optional)</string>
+              </property>
+             </widget>
             </item>
             <item row="1" column="5">
-             <widget class="QLabel" name="label_11">
+             <widget class="QLabel" name="lblPorodCstUnits">
               <property name="text">
                <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;(cm Ã
@@ -397,8 +465,11 @@
             </item>
             <item>
-             <widget class="QLineEdit" name="lineEdit_8">
+             <widget class="QLineEdit" name="txtExtrapolQMin">
               <property name="enabled">
                <bool>false</bool>
               </property>
+              <property name="toolTip">
+               <string>The minimum extrapolated q value.</string>
+              </property>
              </widget>
             </item>
@@ -411,5 +482,5 @@
             </item>
             <item>
-             <widget class="QLineEdit" name="lineEdit_9">
+             <widget class="QLineEdit" name="txtExtrapolQMax">
               <property name="enabled">
                <bool>false</bool>
@@ -418,5 +489,5 @@
             </item>
             <item>
-             <widget class="QLabel" name="label_15">
+             <widget class="QLabel" name="lblExtrapolQUnits">
               <property name="text">
                <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ã
@@ -428,11 +499,81 @@
           </item>
           <item row="1" column="0">
-           <widget class="QGroupBox" name="groupBox_5">
+           <widget class="QGroupBox" name="groupBox_lowQ">
             <property name="title">
              <string>Low Q</string>
             </property>
             <layout class="QGridLayout" name="gridLayout_7">
-             <item row="0" column="0">
-              <widget class="QCheckBox" name="checkBox">
+             <item row="1" column="0" colspan="2">
+              <layout class="QHBoxLayout" name="horizontalLayout_3">
+               <item>
+                <widget class="QLabel" name="label_16">
+                 <property name="text">
+                  <string>Npts:</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QLineEdit" name="txtNptsLowQ">
+                 <property name="toolTip">
+                  <string>Number of Q points to consider
+while extrapolating the low-Q region</string>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item row="2" column="0">
+              <layout class="QVBoxLayout" name="verticalLayout_2">
+               <item>
+                <widget class="QRadioButton" name="rbGuinier">
+                 <property name="text">
+                  <string>Guinier</string>
+                 </property>
+                 <property name="checked">
+                  <bool>true</bool>
+                 </property>
+                 <property name="autoExclusive">
+                  <bool>false</bool>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QRadioButton" name="rbPowerLawLowQ">
+                 <property name="text">
+                  <string>Power law</string>
+                 </property>
+                 <property name="checked">
+                  <bool>false</bool>
+                 </property>
+                 <property name="autoExclusive">
+                  <bool>false</bool>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item row="3" column="0" colspan="2">
+              <layout class="QHBoxLayout" name="horizontalLayout_6">
+               <item>
+                <widget class="QLabel" name="label_17">
+                 <property name="text">
+                  <string>Power:</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QLineEdit" name="txtPowerLowQ">
+                 <property name="toolTip">
+                  <string>Exponent to apply to the Power_law function.</string>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item row="0" column="0" colspan="2">
+              <widget class="QCheckBox" name="chkLowQ">
+               <property name="toolTip">
+                <string>Check to extrapolate data at low-Q</string>
+               </property>
                <property name="text">
                 <string>Enable Low-Q extrapolation</string>
@@ -440,69 +581,48 @@
               </widget>
              </item>
-             <item row="1" column="0">
-              <layout class="QHBoxLayout" name="horizontalLayout_3">
-               <item>
-                <widget class="QLabel" name="label_16">
-                 <property name="text">
-                  <string>Npts:</string>
-                 </property>
-                </widget>
-               </item>
-               <item>
-                <widget class="QLineEdit" name="lineEdit_10"/>
+             <item row="2" column="1">
+              <layout class="QVBoxLayout" name="verticalLayout">
+               <item>
+                <widget class="QRadioButton" name="rbFitLowQ">
+                 <property name="enabled">
+                  <bool>true</bool>
+                 </property>
+                 <property name="text">
+                  <string>Fit</string>
+                 </property>
+                 <property name="checkable">
+                  <bool>true</bool>
+                 </property>
+                 <property name="checked">
+                  <bool>true</bool>
+                 </property>
+                 <property name="autoExclusive">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QRadioButton" name="rbFixLowQ">
+                 <property name="text">
+                  <string>Fix</string>
+                 </property>
+                 <property name="checkable">
+                  <bool>true</bool>
+                 </property>
+                 <property name="checked">
+                  <bool>false</bool>
+                 </property>
+                 <property name="autoExclusive">
+                  <bool>true</bool>
+                 </property>
+                </widget>
                </item>
               </layout>
              </item>
-             <item row="2" column="0">
-              <layout class="QFormLayout" name="formLayout">
-               <item row="0" column="0">
-                <widget class="QRadioButton" name="radioButton">
-                 <property name="text">
-                  <string>Guinier</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="1">
-                <widget class="QRadioButton" name="radioButton_3">
-                 <property name="text">
-                  <string>Fit</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="0">
-                <widget class="QRadioButton" name="radioButton_2">
-                 <property name="text">
-                  <string>Power law</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="1">
-                <widget class="QRadioButton" name="radioButton_4">
-                 <property name="text">
-                  <string>Fix</string>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </item>
-             <item row="3" column="0">
-              <layout class="QHBoxLayout" name="horizontalLayout_6">
-               <item>
-                <widget class="QLabel" name="label_17">
-                 <property name="text">
-                  <string>Power:</string>
-                 </property>
-                </widget>
-               </item>
-               <item>
-                <widget class="QLineEdit" name="lineEdit_11"/>
-               </item>
-              </layout>
-             </item>
             </layout>
            </widget>
           </item>
           <item row="1" column="1">
-           <widget class="QGroupBox" name="groupBox_6">
+           <widget class="QGroupBox" name="groupBox_highQ">
             <property name="title">
              <string>High Q</string>
@@ -510,5 +630,8 @@
             <layout class="QGridLayout" name="gridLayout_8">
              <item row="0" column="0">
-              <widget class="QCheckBox" name="checkBox_2">
+              <widget class="QCheckBox" name="chkHighQ">
+               <property name="toolTip">
+                <string>Check to extrapolate data at high-Q</string>
+               </property>
                <property name="text">
                 <string>Enable High-Q extrapolation</string>
@@ -526,21 +649,35 @@
                </item>
                <item>
-                <widget class="QLineEdit" name="lineEdit_12"/>
+                <widget class="QLineEdit" name="txtNptsHighQ">
+                 <property name="toolTip">
+                  <string>Number of Q points to consider
+ while extrapolating the high-Q region</string>
+                 </property>
+                </widget>
                </item>
               </layout>
              </item>
              <item row="2" column="0">
-              <layout class="QFormLayout" name="formLayout_2">
+              <layout class="QGridLayout" name="gridLayout_13">
                <item row="0" column="0">
-                <widget class="QRadioButton" name="radioButton_7">
+                <widget class="QRadioButton" name="rbFitHighQ">
                  <property name="text">
                   <string>Fit</string>
                  </property>
+                 <property name="checkable">
+                  <bool>true</bool>
+                 </property>
+                 <property name="checked">
+                  <bool>false</bool>
+                 </property>
                 </widget>
                </item>
                <item row="1" column="0">
-                <widget class="QRadioButton" name="radioButton_8">
+                <widget class="QRadioButton" name="rbFixHighQ">
                  <property name="text">
                   <string>Fix</string>
+                 </property>
+                 <property name="checked">
+                  <bool>true</bool>
                  </property>
                 </widget>
@@ -558,5 +695,9 @@
                </item>
                <item>
-                <widget class="QLineEdit" name="lineEdit_13"/>
+                <widget class="QLineEdit" name="txtPowerHighQ">
+                 <property name="toolTip">
+                  <string>Exponent to apply to the Power_law function.</string>
+                 </property>
+                </widget>
                </item>
               </layout>
@@ -570,71 +711,5 @@
       </layout>
      </widget>
-     <widget class="QWidget" name="tab">
-      <attribute name="title">
-       <string>View on model</string>
-      </attribute>
-      <widget class="QTreeView" name="treeView">
-       <property name="geometry">
-        <rect>
-         <x>5</x>
-         <y>11</y>
-         <width>431</width>
-         <height>311</height>
-        </rect>
-       </property>
-      </widget>
-     </widget>
     </widget>
-   </item>
-   <item row="1" column="0">
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>2</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="2" column="0">
-    <layout class="QHBoxLayout" name="horizontalLayout_8">
-     <item>
-      <widget class="QPushButton" name="pushButton">
-       <property name="text">
-        <string>Calculate</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <spacer name="horizontalSpacer">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-     <item>
-      <widget class="QPushButton" name="pushButton_2">
-       <property name="text">
-        <string>Status</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QPushButton" name="pushButton_3">
-       <property name="text">
-        <string>Help</string>
-       </property>
-      </widget>
-     </item>
-    </layout>
    </item>
   </layout>
Index: src/sas/qtgui/Perspectives/Invariant/UnitTesting/InvariantDetailsTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/UnitTesting/InvariantDetailsTest.py	(revision f1f3e6a66c47bce134b59fe9f166fe14eac3a61d)
+++ src/sas/qtgui/Perspectives/Invariant/UnitTesting/InvariantDetailsTest.py	(revision f1f3e6a66c47bce134b59fe9f166fe14eac3a61d)
@@ -0,0 +1,153 @@
+import sys
+import time
+import numpy
+import logging
+import unittest
+from PyQt5 import QtGui, QtWidgets
+from PyQt5 import QtCore
+from PyQt5.QtTest import QTest
+from PyQt5.QtCore import Qt
+from mock import MagicMock
+from mock import patch
+
+from twisted.internet import threads
+
+from sas.qtgui.Perspectives.Invariant.InvariantDetails import DetailsDialog
+from sas.qtgui.Perspectives.Invariant.InvariantUtils import WIDGETS
+
+from sas.qtgui.Utilities.GuiUtils import *
+
+if not QtWidgets.QApplication.instance():
+    app = QtWidgets.QApplication(sys.argv)
+
+BG_COLOR_ERR = 'background-color: rgb(244, 170, 164);'
+
+
+class InvariantDetailsTest(unittest.TestCase):
+    """Test the Invariant Perspective Window"""
+    def setUp(self):
+        """Create the Invariant Details window"""
+
+        self.widget = DetailsDialog(None)
+
+        self.widget._model = QtGui.QStandardItemModel()
+
+        self.widget._model.setItem(WIDGETS.W_INVARIANT, QtGui.QStandardItem(str(10.)))
+
+        self.widget._model.setItem(WIDGETS.W_INVARIANT_ERR, QtGui.QStandardItem(str(0.1)))
+
+        self.widget._model.setItem(WIDGETS.W_ENABLE_LOWQ, QtGui.QStandardItem('true'))
+
+        self.widget._model.setItem(WIDGETS.D_LOW_QSTAR, QtGui.QStandardItem(str(9.)))
+
+        self.widget._model.setItem(WIDGETS.D_LOW_QSTAR_ERR, QtGui.QStandardItem(str(0.03)))
+
+        # # High-Q
+        self.widget._model.setItem(WIDGETS.W_ENABLE_HIGHQ,
+                                   QtGui.QStandardItem('false'))
+        # self._model.item(WIDGETS.D_HIGH_QSTAR)
+        # self._model.item(WIDGETS.D_HIGH_QSTAR_ERR)
+
+    def tearDown(self):
+        """Destroy the Invariant Details window """
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        """Test the GUI in its default state"""
+
+        self.widget.qstar_total = None
+        self.widget.qhigh = None
+        self.widget.qlow = None
+
+        self.widget.progress_low_qstar = 0.0
+        self.widget.progress_high_qstar = 0.0
+        self.widget.progress_qstar = 100.0
+
+        self.widget.warning_msg = "No Details on calculations available...\n"
+
+        self.assertIsInstance(self.widget, QtWidgets.QDialog)
+
+        self.assertEqual(self.widget.progressBarLowQ.minimum(), 0)
+        self.assertEqual(self.widget.progressBarLowQ.maximum(), 100)
+
+        self.assertEqual(self.widget.progressBarData.minimum(), 0)
+        self.assertEqual(self.widget.progressBarData.maximum(), 100)
+
+        self.assertEqual(self.widget.progressBarHighQ.minimum(), 0)
+        self.assertEqual(self.widget.progressBarHighQ.maximum(), 100)
+
+
+        # Tooltips
+        self.assertEqual(self.widget.txtQData.toolTip(), "Invariant in the data set's Q range.")
+
+        self.assertEqual(self.widget.txtQDataErr.toolTip(), "Uncertainty on the invariant from data's range.")
+
+        self.assertEqual(self.widget.txtQLowQ.toolTip(), "Extrapolated invariant from low-Q range.")
+
+        self.assertEqual(self.widget.txtQLowQErr.toolTip(), "Uncertainty on the invariant from low-Q range.")
+
+        self.assertEqual(self.widget.txtQHighQ.toolTip(), "Extrapolated invariant from high-Q range.")
+
+        self.assertEqual(self.widget.txtQHighQErr.toolTip(), "Uncertainty on the invariant from high-Q range.")
+
+    def testOnOK(self):
+        """ Test closing dialog"""
+        okButton = self.widget.cmdOK
+        QTest.mouseClick(okButton, Qt.LeftButton)
+
+    def testShowDialog(self):
+        """ """
+        self.widget.showDialog()
+        # Low Q true
+        self.assertEqual(self.widget.qlow , 9.0)
+
+        self.assertEqual(self.widget.txtQLowQ.text(), '9.0')
+
+        self.assertEqual(self.widget.progress_low_qstar, 90.0)
+
+        self.assertEqual(self.widget.qstar_total, 10.0)
+
+        self.assertEqual(self.widget.txtQData.text(), '10.0')
+
+        self.assertEqual(self.widget.txtQDataErr.text(), '0.1')
+
+        # High Q false
+        self.assertEqual(self.widget.txtQHighQ.text(), '')
+        self.assertEqual(self.widget.txtQHighQErr.text(), '')
+        self.assertEqual(self.widget.progress_high_qstar, 0.0)  #  = 0
+        self.widget.qhigh  # = 0
+
+        # Progressbars
+        self.assertEqual(self.widget.progressBarLowQ.value(), self.widget.progress_low_qstar)
+
+        self.assertEqual(self.widget.progressBarLowQ.value(), self.widget.progress_low_qstar)
+
+        self.assertEqual(self.widget.progressBarHighQ.value(), self.widget.progress_high_qstar)
+
+    # TODO to complete
+    def testCheckValues(self):
+        """ """
+        self.widget.qstart_total = None
+        self.assertEqual(self.widget.checkValues(), "Invariant not calculated.\n")
+
+        self.widget.qstar_total = 0
+        self.assertEqual(self.widget.checkValues(), "Invariant is zero. \n " \
+                          "The calculations are likely to be unreliable!\n")
+
+        self.widget.qstar_total = 10
+        self.widget.progress_qstar = 'error'
+        self.assertEqual(self.widget.checkValues(), "Error occurred when computing invariant from data.\n Invariant Q contribution is greater than 100% .\n")
+
+        self.widget.progress_qstar = 0
+
+        self.widget.progress_low_qstar = 10
+        self.assertEqual(self.widget.checkValues(),
+                         'Extrapolated contribution at Low Q is higher than 5% of the invariant.\nThe sum of all extrapolated contributions is higher than 5% of the invariant.\n')
+
+        self.widget.progress_low_qstar = -1
+        self.assertEqual(self.widget.checkValues(), "Extrapolated contribution at Low Q < 0.\n")
+
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Perspectives/Invariant/UnitTesting/InvariantPerspectiveTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/UnitTesting/InvariantPerspectiveTest.py	(revision f1f3e6a66c47bce134b59fe9f166fe14eac3a61d)
+++ src/sas/qtgui/Perspectives/Invariant/UnitTesting/InvariantPerspectiveTest.py	(revision f1f3e6a66c47bce134b59fe9f166fe14eac3a61d)
@@ -0,0 +1,474 @@
+import sys
+import time
+import numpy
+import logging
+import unittest
+from PyQt5 import QtGui, QtWidgets
+from PyQt5 import QtCore
+from PyQt5.QtTest import QTest
+from PyQt5.QtCore import Qt
+from mock import MagicMock
+from mock import patch
+from mock import create_autospec
+
+from twisted.internet import threads
+
+from sas.qtgui.Perspectives.Invariant.InvariantPerspective import InvariantWindow
+from sas.qtgui.Perspectives.Invariant.InvariantDetails import DetailsDialog
+from sas.qtgui.Perspectives.Invariant.InvariantUtils import WIDGETS
+from sas.qtgui.Plotting.PlotterData import Data1D
+from sas.qtgui.MainWindow.GuiManager import GuiManager
+from sas.qtgui.MainWindow.DataExplorer import DataExplorerWindow
+
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+
+if not QtWidgets.QApplication.instance():
+    app = QtWidgets.QApplication(sys.argv)
+
+BG_COLOR_ERR = 'background-color: rgb(244, 170, 164);'
+
+class InvariantPerspectiveTest(unittest.TestCase):
+    """Test the Invariant Perspective Window"""
+    def setUp(self):
+        """Create the Invariant Perspective Window"""
+
+        class MainWindow(object):
+            def __init__(self):
+                self.model = QtGui.QStandardItemModel()
+
+        class dummy_manager(object):
+            def __init__(self):
+                self.filesWidget = MainWindow()
+
+            def communicator(self):
+                return GuiUtils.Communicate()
+
+            def communicate(self):
+                return GuiUtils.Communicate()
+
+        self.widget = InvariantWindow(dummy_manager())
+
+    def tearDown(self):
+        """Destroy the DataOperationUtility"""
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        """Test the GUI in its default state"""
+
+        self.assertIsInstance(self.widget, QtWidgets.QDialog)
+
+        self.assertEqual(self.widget.windowTitle(), "Invariant Perspective")
+
+        # name for displaying in the DataExplorer combo box
+        self.assertEqual(self.widget.name, "Invariant")
+
+        self.assertIsInstance(self.widget.model, QtGui.QStandardItemModel)
+
+        self.assertIsNone(self.widget._data)
+        self.assertEqual(self.widget._path, '')
+        self.assertFalse(self.widget._allow_close)
+
+        # disabled pushbuttons
+        self.assertFalse(self.widget.cmdStatus.isEnabled())
+        self.assertFalse(self.widget.cmdCalculate.isEnabled())
+
+        # disabled, read only line edits
+        self.assertFalse(self.widget.txtName.isEnabled())
+        self.assertTrue(self.widget.txtVolFract.isReadOnly())
+        self.assertTrue(self.widget.txtVolFractErr.isReadOnly())
+
+        self.assertTrue(self.widget.txtSpecSurf.isReadOnly())
+        self.assertTrue(self.widget.txtSpecSurfErr.isReadOnly())
+
+        self.assertTrue(self.widget.txtInvariantTot.isReadOnly())
+        self.assertTrue(self.widget.txtInvariantTotErr.isReadOnly())
+
+        self.assertFalse(self.widget.txtBackgd.isReadOnly())
+        self.assertFalse(self.widget.txtScale.isReadOnly())
+        self.assertFalse(self.widget.txtContrast.isReadOnly())
+        self.assertFalse(self.widget.txtPorodCst.isReadOnly())
+
+        self.assertFalse(self.widget.txtExtrapolQMin.isEnabled())
+        self.assertFalse(self.widget.txtExtrapolQMax.isEnabled())
+
+        self.assertFalse(self.widget.txtNptsLowQ.isReadOnly())
+        self.assertFalse(self.widget.txtNptsHighQ.isReadOnly())
+
+        # content of line edits
+        self.assertEqual(self.widget.txtName.text(), '')
+        self.assertEqual(self.widget.txtTotalQMin.text(), '0.0')
+        self.assertEqual(self.widget.txtTotalQMax.text(), '0.0')
+        self.assertEqual(self.widget.txtBackgd.text(), '0.0')
+        self.assertEqual(self.widget.txtScale.text(), '1.0')
+        self.assertEqual(self.widget.txtContrast.text(), '1.0')
+        self.assertEqual(self.widget.txtExtrapolQMin.text(), '1e-05')
+        self.assertEqual(self.widget.txtExtrapolQMax.text(), '10')
+        self.assertEqual(self.widget.txtPowerLowQ.text(), '4')
+        self.assertEqual(self.widget.txtPowerHighQ.text(), '4')
+
+        # unchecked checkboxes
+        self.assertFalse(self.widget.chkLowQ.isChecked())
+        self.assertFalse(self.widget.chkHighQ.isChecked())
+
+        # number of tabs
+        self.assertEqual(self.widget.tabWidget.count(), 2)
+        # default tab
+        self.assertEqual(self.widget.tabWidget.currentIndex(), 0)
+        # tab's title
+        self.assertEqual(self.widget.tabWidget.tabText(0), 'Invariant')
+        self.assertEqual(self.widget.tabWidget.tabText(1), 'Options')
+
+        # Tooltips
+        self.assertEqual(self.widget.cmdStatus.toolTip(), "Get more details of computation such as fraction from extrapolation" )
+
+        self.assertEqual(self.widget.txtInvariantTot.toolTip(), "Total invariant [Q*], including extrapolated regions.")
+
+        self.assertEqual(self.widget.txtExtrapolQMin.toolTip(), "The minimum extrapolated q value.")
+
+        self.assertEqual(self.widget.txtPowerHighQ.toolTip(),"Exponent to apply to the Power_law function.")
+
+        self.assertEqual(self.widget.txtNptsHighQ.toolTip(), "Number of Q points to consider\n while extrapolating the high-Q region")
+
+        self.assertEqual(self.widget.chkHighQ.toolTip(), "Check to extrapolate data at high-Q")
+
+        self.assertEqual(self.widget.txtNptsLowQ.toolTip(), "Number of Q points to consider\nwhile extrapolating the low-Q region")
+
+        self.assertEqual(self.widget.chkLowQ.toolTip(), "Check to extrapolate data at low-Q")
+
+        self.assertEqual(self.widget.cmdCalculate.toolTip(), "Compute invariant")
+
+        self.assertEqual(self.widget.txtPowerLowQ.toolTip(), "Exponent to apply to the Power_law function." )
+
+        # Validators
+        self.assertIsInstance(self.widget.txtNptsLowQ.validator(), QtGui.QRegExpValidator)
+        self.assertIsInstance(self.widget.txtNptsHighQ.validator(), QtGui.QRegExpValidator)
+        self.assertIsInstance(self.widget.txtPowerLowQ.validator(), QtGui.QRegExpValidator)
+        self.assertIsInstance(self.widget.txtPowerHighQ.validator(), QtGui.QRegExpValidator)
+
+        self.assertIsInstance(self.widget.txtBackgd.validator(), QtGui.QDoubleValidator)
+        self.assertIsInstance(self.widget.txtContrast.validator(), QtGui.QDoubleValidator)
+        self.assertIsInstance(self.widget.txtScale.validator(), QtGui.QDoubleValidator)
+        self.assertIsInstance(self.widget.txtPorodCst.validator(), QtGui.QDoubleValidator)
+
+        # Test autoexclusivity of radiobuttons
+        # Low Q
+        self.assertFalse(self.widget.rbGuinier.autoExclusive())
+        self.assertFalse(self.widget.rbPowerLawLowQ.autoExclusive())
+        self.assertTrue(self.widget.rbFixLowQ.autoExclusive())
+        self.assertTrue(self.widget.rbFitLowQ.autoExclusive())
+        # High Q
+        self.assertTrue(self.widget.rbFixHighQ.autoExclusive())
+        self.assertTrue(self.widget.rbFitHighQ.autoExclusive())
+
+    def testOnCalculate(self):
+        """ Test onCompute function """
+        self.widget.calculateInvariant = MagicMock()
+        self.widget.cmdCalculate.setEnabled(True)
+        QTest.mouseClick(self.widget.cmdCalculate, Qt.LeftButton)
+        self.assertTrue(self.widget.calculateInvariant.called_once())
+
+    def testCalculateInvariant(self):
+        """ """
+        threads.deferToThread = MagicMock()
+        self.widget.calculateInvariant()
+        self.assertTrue(threads.deferToThread.called)
+        self.assertEqual(threads.deferToThread.call_args_list[0][0][0].__name__, 'calculateThread')
+
+        self.assertEqual(self.widget.cmdCalculate.text(), 'Calculating...')
+        self.assertFalse(self.widget.cmdCalculate.isEnabled())
+
+    # TODO
+    def testPlotResult(self):
+        """ """
+        pass
+        # create fake input
+        # data = Data1D(x=[1, 2], y=[3, 4])
+        # GuiUtils.dataFromItem = MagicMock(return_value=data)
+        # # self.widget._manager.filesWidget.model = MagicMock()
+        # item = QtGui.QStandardItem("test")
+
+        # run function
+        # self.widget.plotResult = MagicMock(return_value=None) # (item)
+        # self.widget.plotResult(item)
+        # self.assertTrue(self.widget.plotResult.called_once())
+
+
+        # self.assertTrue(self.widget.cmdCalculate.isEnabled())
+        # self.assertEqual(self.widget.cmdCalculate.text(), 'Calculate')
+        # self.assertEqual(self.widget._data.x[0], 1)
+        # self.assertEqual(self.widget._data.x[1], 2)
+        # self.assertEqual(self.widget._data.y[0], 3)
+        # self.assertEqual(self.widget._data.y[1], 4)
+
+    def testHelp(self):
+        """ Assure help file is shown """
+        # this should not rise
+        self.widget.onHelp()
+
+    def testAllowBatch(self):
+        """ """
+        self.assertFalse(self.widget.allowBatch())
+
+    def testTitle(self):
+        """
+        Test Perspective name
+        """
+        self.assertEqual(self.widget.title(), "Invariant panel")
+
+    def testOnStatus(self):
+        """
+        Test Display of Invariant Details
+        """
+        # enable click on Calculate button
+        self.widget.cmdStatus.setEnabled(True)
+
+        invariant_details_dialog = create_autospec(DetailsDialog)
+
+        self.widget.detailsDialog = invariant_details_dialog
+
+        # click on button
+        QTest.mouseClick(self.widget.cmdStatus, Qt.LeftButton)
+
+        invariant_details_dialog.showDialog.assert_called_once_with()
+
+    def testUpdateFromModel(self):
+        """
+        update the globals based on the data in the model
+        """
+        self.widget.updateFromModel()
+        self.assertEqual(self.widget._background,
+                         float(self.widget.model.item(WIDGETS.W_BACKGROUND).text()))
+        self.assertEqual(self.widget._contrast,
+                         float(self.widget.model.item(WIDGETS.W_CONTRAST).text()))
+        self.assertEqual(self.widget._scale, float(self.widget.model.item(WIDGETS.W_SCALE).text()))
+        self.assertEqual(self.widget._low_extrapolate,
+                         str(self.widget.model.item(WIDGETS.W_ENABLE_LOWQ).text()) == 'true')
+        self.assertEqual(self.widget._low_points,
+                         float(self.widget.model.item(WIDGETS.W_NPTS_LOWQ).text()))
+
+        self.assertEqual(self.widget._low_guinier, str(self.widget.model.item(WIDGETS.W_LOWQ_GUINIER).text()) == 'true' )
+
+        self.assertEqual(self.widget._low_fit,str(self.widget.model.item(WIDGETS.W_LOWQ_FIT).text()) == 'true')
+        self.assertEqual(self.widget._low_power_value, float(self.widget.model.item(WIDGETS.W_LOWQ_POWER_VALUE).text()))
+
+        self.assertEqual(self.widget._high_extrapolate,str(self.widget.model.item(WIDGETS.W_ENABLE_HIGHQ).text()) == 'true')
+        self.assertEqual(self.widget._high_points,
+                         float(self.widget.model.item(WIDGETS.W_NPTS_HIGHQ).text()))
+        self.assertEqual(self.widget._high_fit,str(self.widget.model.item(WIDGETS.W_HIGHQ_FIT).text()) == 'true')
+
+        self.assertEqual(self.widget._high_power_value, float(self.widget.model.item(WIDGETS.W_HIGHQ_POWER_VALUE).text()))
+
+    def testEnabling(self):
+        """ """
+
+        self.widget.cmdStatus.setEnabled(False)
+
+        self.widget.enabling()
+
+        self.assertTrue(self.widget.cmdStatus.isEnabled())
+
+    def testCheckLength(self):
+        """
+        Test validator for number of points for extrapolation
+         Error if it is larger than the distribution length
+        """
+        logging.warning = MagicMock()
+        self.widget.txtNptsLowQ.setEnabled(True)
+
+        self.widget._data = Data1D(x=[1, 2], y=[1, 2])
+        self.widget.txtNptsLowQ.setText('9')
+
+        # QTest.keyClicks(self.widget.txtNptsLowQ, '9')
+        # QTest.keyClick(self.widget.txtNptsLowQ, QtCore.Qt.Key_Return)
+
+        BG_COLOR_ERR = 'background-color: rgb(244, 170, 164);'
+        # print 'style ',self.widget.txtNptsLowQ.styleSheet()
+        self.assertIn(BG_COLOR_ERR, self.widget.txtNptsLowQ.styleSheet())
+        self.assertTrue(logging.warning.called_once_with())
+        self.assertFalse(self.widget.cmdCalculate.isEnabled())
+
+    def testModelChanged(self):
+        """ """
+        self.widget.lowQToggle = MagicMock()
+        status_ini = self.widget.model.item(WIDGETS.W_ENABLE_LOWQ).text()
+        if status_ini == 'true':
+            status_fin = 'false'
+        else:
+            status_fin = 'true'
+
+        self.widget.model.setItem(WIDGETS.W_ENABLE_LOWQ, QtGui.QStandardItem(status_fin))
+
+        if status_fin:
+            self.assertTrue(self.widget._low_extrapolate)
+        else:
+            self.assertFalse(self.widget._low_extrapolate)
+
+        self.assertTrue(self.widget.lowQToggle.called_once_with())
+
+    def testUpdateFromGui(self):
+        """ """
+        self.widget.txtBackgd.setText('0.22')
+        self.assertEqual(str(self.widget.model.item(WIDGETS.W_BACKGROUND).text()), '0.22')
+
+    def testLowGuinierAndPowerToggle(self):
+        """ """
+        # enable all tested radiobuttons
+        self.widget.rbGuinier.setEnabled(True)
+        self.widget.rbPowerLawLowQ.setEnabled(True)
+        self.widget.txtNptsLowQ.setEnabled(True)
+
+        # record initial status
+        status_ini = self.widget.rbGuinier.isChecked()
+
+        # mouse click to run function
+        QTest.mouseClick(self.widget.rbGuinier, Qt.LeftButton)
+
+        # check that status changed
+        self.assertNotEqual(self.widget.rbGuinier.isChecked(), status_ini)
+
+        status_fin = self.widget.rbGuinier.isChecked()
+
+        self.assertEqual(self.widget.rbPowerLawLowQ.isChecked(), not status_fin)
+
+        self.assertEqual(self.widget.txtPowerLowQ.isEnabled(),
+                         all([not status_fin, not self.widget._low_fit]))
+
+    def testLowFitAndFixToggle(self):
+        """ """
+        status = True
+        # run function to test
+        self.widget.lowFitAndFixToggle(status)
+        self.assertEqual(self.widget._low_fit, status)
+        self.assertNotEqual(self.widget.txtPowerLowQ.isEnabled(), status)
+
+    def testHiFitAndFixToggle(self):
+        status = True
+        self.widget.hiFitAndFixToggle(status)
+        self.assertEqual(self.widget.txtPowerHighQ.isEnabled(), not status)
+
+    def testHighQToggle(self):
+        """ Test enabling / disabling for check box High Q extrapolation """
+        status_chkHighQ = self.widget.chkHighQ.isChecked()
+        self.widget.highQToggle(status_chkHighQ)
+
+        self.assertEqual(self.widget.rbFitHighQ.isEnabled(), status_chkHighQ)
+        self.assertEqual(self.widget.rbFixHighQ.isEnabled(), status_chkHighQ)
+        self.assertEqual(self.widget.txtNptsHighQ.isEnabled(), status_chkHighQ)
+        self.assertEqual(self.widget.txtPowerHighQ.isEnabled(), status_chkHighQ)
+
+        # change checked status of chkHighQ
+        self.widget.chkHighQ.setChecked(True)
+        status_chkHighQ = self.widget.chkHighQ.isChecked()
+        self.assertEqual(self.widget.rbFitHighQ.isEnabled(), status_chkHighQ)
+        self.assertEqual(self.widget.rbFixHighQ.isEnabled(), status_chkHighQ)
+        self.assertEqual(self.widget.txtNptsHighQ.isEnabled(), status_chkHighQ)
+        self.assertEqual(self.widget.txtPowerHighQ.isEnabled(),
+                         status_chkHighQ)
+
+    def testLowQToggle(self):
+        """ Test enabling / disabling for check box Low Q extrapolation """
+        status_chkLowQ = self.widget.chkLowQ.isChecked()
+
+        self.assertEqual(self.widget.rbGuinier.isEnabled(), status_chkLowQ)
+        self.assertEqual(self.widget.rbPowerLawLowQ.isEnabled(), status_chkLowQ)
+        self.assertEqual(self.widget.txtNptsLowQ.isEnabled(), status_chkLowQ)
+
+        self.assertEqual(self.widget.rbFitLowQ.isVisible(), self.widget.rbPowerLawLowQ.isChecked())
+        self.assertEqual(self.widget.rbFixLowQ.isVisible(), self.widget.rbPowerLawLowQ.isChecked())
+        self.assertEqual(self.widget.rbFitLowQ.isEnabled(), status_chkLowQ)
+        self.assertEqual(self.widget.rbFixLowQ.isEnabled(), status_chkLowQ)
+
+        self.assertEqual(self.widget.txtNptsLowQ.isEnabled(),
+                         all([status_chkLowQ, not self.widget._low_guinier, not self.widget._low_fit]))
+
+    def testSetupModel(self):
+        """ Test default settings of model"""
+        self.assertEqual(self.widget.model.item(WIDGETS.W_FILENAME).text(),
+                         self.widget._path)
+
+        self.assertEqual(self.widget.model.item(WIDGETS.W_QMIN).text(), '0.0')
+
+        self.assertEqual(self.widget.model.item(WIDGETS.W_QMAX).text(), '0.0')
+
+        self.assertEqual(self.widget.model.item(WIDGETS.W_BACKGROUND).text(),
+                         str(self.widget._background))
+
+        self.assertEqual(self.widget.model.item(WIDGETS.W_CONTRAST).text(),
+                         str(self.widget._contrast))
+
+        self.assertEqual(self.widget.model.item(WIDGETS.W_SCALE).text(),
+                         str(self.widget._scale))
+
+        self.assertIn(str(self.widget.model.item(WIDGETS.W_POROD_CST).text()),
+                      ['', str(self.widget._porod)])
+
+        self.assertEqual(
+            str(self.widget.model.item(WIDGETS.W_ENABLE_HIGHQ).text()).lower(),
+            'false')
+
+        self.assertEqual(
+            str(self.widget.model.item(WIDGETS.W_ENABLE_LOWQ).text()).lower(),
+            'false')
+
+        self.assertEqual(
+            str(self.widget.model.item(WIDGETS.W_NPTS_LOWQ).text()),
+            str(10))
+
+        self.assertEqual(self.widget.model.item(WIDGETS.W_NPTS_HIGHQ).text(),
+                         str(10))
+
+        self.assertEqual(
+            str(self.widget.model.item(WIDGETS.W_LOWQ_GUINIER).text()).lower(),
+            'true')
+
+        self.assertEqual(
+            str(self.widget.model.item(WIDGETS.W_LOWQ_FIT).text()).lower(),
+            'true')
+
+        self.assertEqual(
+            str(self.widget.model.item(WIDGETS.W_LOWQ_POWER_VALUE).text()), '4')
+
+        self.assertEqual(
+            str(self.widget.model.item(WIDGETS.W_HIGHQ_FIT).text()).lower(),
+            'true')
+
+        self.assertEqual(
+            str(self.widget.model.item(WIDGETS.W_HIGHQ_POWER_VALUE).text()),
+            '4')
+
+    # TODO
+    def testSetupMapper(self):
+        """ """
+        self.assertIsInstance(self.widget.mapper, QtWidgets.QDataWidgetMapper)
+
+        self.assertEqual(self.widget.mapper.orientation(), 2)
+
+        self.assertEqual(self.widget.mapper.model(), self.widget.model)
+
+    def testSetData(self):
+        """ """
+        self.widget.updateGuiFromFile = MagicMock()
+
+        data = Data1D(x=[1, 2], y=[1, 2])
+        GuiUtils.dataFromItem = MagicMock(return_value=data)
+        item = QtGui.QStandardItem("test")
+        self.widget.setData([item])
+
+        self.assertTrue(self.widget.updateGuiFromFile.called_once())
+
+    def TestCheckQExtrapolatedData(self):
+        """
+        Test Match status of low or high-Q extrapolated data checkbox in
+        DataExplorer with low or high-Q extrapolation checkbox in invariant
+        panel
+        """
+        # Low-Q check box ticked
+        self.widget.chkLowQ.setCheckStatus(QtCore.Qt.Checked)
+        GuiUtils.updateModelItemStatus = MagicMock()
+
+        self.assertTrue(GuiUtils.updateModelItemStatus.called_once())
+
+
+if __name__ == "__main__":
+    unittest.main()
