Index: run.py
===================================================================
--- run.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ run.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -122,4 +122,4 @@
 if __name__ == "__main__":
     prepare()
-    from sas.qtgui.MainWindow import run
+    from sas.qtgui.MainWindow.MainWindow import run
     run()
Index: c/sas/qtgui/AboutBox.py
===================================================================
--- src/sas/qtgui/AboutBox.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,65 +1,0 @@
-import functools
-from PyQt4 import QtGui
-
-import sas.sasview
-import sas.qtgui.LocalConfig as LocalConfig
-import sas.qtgui.GuiUtils as GuiUtils
-
-from UI.AboutUI import Ui_AboutUI
-
-class AboutBox(QtGui.QDialog, Ui_AboutUI):
-    def __init__(self, parent=None):
-        super(AboutBox, self).__init__(parent)
-        self.setupUi(self)
-
-        self.setWindowTitle("About")
-
-        self.addText()
-
-        self.addActions()
-
-    def addText(self):
-        """
-        Modify the labels so the text corresponds to the current version
-        """
-        version = sas.sasview.__version__
-
-        self.lblVersion.setText(str(version))
-        lbl_font = self.font()
-        lbl_font.setPointSize(24)
-        self.lblVersion.setFont(lbl_font)
-        about_text = r'<html><head/><body><p>'
-        about_text += '<p>Build ' + str(LocalConfig.__build__) +'</p>'
-        about_text += '<p>' + LocalConfig._copyright + '</p>'
-        about_text += r'<p><a href=http://www.sasview.org>http://www.sasview.org</a></p><br/>'
-        about_text += '<p>Comments? Bugs? Requests?<br/>'
-        about_text += r'<a href=mailto:help@sasview.org>Send us a ticket</a></p><br/>'
-        about_text += r'<a href=' + str(LocalConfig.__download_page__)\
-                   + 'Get the latest version</a></p><br/>'
-        self.lblAbout.setText(about_text)
-
-        # Enable link clicking on the label
-        self.lblAbout.setOpenExternalLinks(True)
-
-    def addActions(self):
-        """
-        Add actions to the logo push buttons
-        """
-        self.cmdLinkUT.clicked.connect(functools.partial(
-            GuiUtils.openLink, LocalConfig._inst_url))
-        self.cmdLinkUMD.clicked.connect(functools.partial(
-            GuiUtils.openLink, LocalConfig._umd_url))
-        self.cmdLinkNIST.clicked.connect(functools.partial(
-            GuiUtils.openLink, LocalConfig._nist_url))
-        self.cmdLinkSNS.clicked.connect(functools.partial(
-            GuiUtils.openLink, LocalConfig._sns_url))
-        self.cmdLinkISIS.clicked.connect(functools.partial(
-            GuiUtils.openLink, LocalConfig._isis_url))
-        self.cmdLinkESS.clicked.connect(functools.partial(
-            GuiUtils.openLink, LocalConfig._ess_url))
-        self.cmdLinkILL.clicked.connect(functools.partial(
-            GuiUtils.openLink, LocalConfig._ill_url))
-        self.cmdLinkANSTO.clicked.connect(functools.partial(
-            GuiUtils.openLink, LocalConfig._ansto_url))
-
-        self.cmdOK.clicked.connect(self.close)
Index: c/sas/qtgui/AddText.py
===================================================================
--- src/sas/qtgui/AddText.py	(revision 9290b1a2e57458d51b13f1acd1798b999372c7d7)
+++ 	(revision )
@@ -1,47 +1,0 @@
-from PyQt4 import QtGui
-
-import sas.sasview
-
-from sas.qtgui.UI.AddTextUI import Ui_AddText
-
-class AddText(QtGui.QDialog, Ui_AddText):
-    """ Simple GUI for a single line text query """
-    def __init__(self, parent=None):
-        super(AddText, self).__init__(parent)
-        self.setupUi(self)
-
-        self._font = QtGui.QFont()
-        self._color = "black"
-        self.btnFont.clicked.connect(self.onFontChange)
-        self.btnColor.clicked.connect(self.onColorChange)
-
-    def text(self):
-        return self.textEdit.toPlainText()
-
-    def font(self):
-        return self._font
-
-    def color(self):
-        return self._color
-
-    def onFontChange(self, event):
-        """
-        Pop up the standard Qt Font change dialog
-        """
-        self._font, ok = QtGui.QFontDialog.getFont(parent=self)
-        if ok:
-            self.textEdit.setFont(self._font)
-
-    def onColorChange(self, event):
-        """
-        Pop up the standard Qt color change dialog
-        """
-        # Pick up the chosen color
-        self._color = QtGui.QColorDialog.getColor(parent=self)
-        # Update the text control
-        palette = QtGui.QPalette()
-        palette.setColor(QtGui.QPalette.Text, self._color)
-        self.textEdit.setPalette(palette)
-
-        # Save the color as #RRGGBB
-        self._color = str(self._color.name())
Index: c/sas/qtgui/BoxSum.py
===================================================================
--- src/sas/qtgui/BoxSum.py	(revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ 	(revision )
@@ -1,42 +1,0 @@
-"""
-Allows users to modify the box slicer parameters.
-"""
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-
-# Local UI
-from sas.qtgui.UI.BoxSumUI import Ui_BoxSumUI
-
-class BoxSum(QtGui.QDialog, Ui_BoxSumUI):
-    apply_signal = QtCore.pyqtSignal(tuple, str)
-    def __init__(self, parent=None, model=None):
-        super(BoxSum, self).__init__()
-
-        self.setupUi(self)
-        assert isinstance(model, QtGui.QStandardItemModel)
-
-        self.txtBoxHeight.setValidator(QtGui.QDoubleValidator())
-        self.txtBoxWidth.setValidator(QtGui.QDoubleValidator())
-        self.txtCenterX.setValidator(QtGui.QDoubleValidator())
-        self.txtCenterY.setValidator(QtGui.QDoubleValidator())
-
-        self.model = model
-        self.mapper = QtGui.QDataWidgetMapper()
-        self.mapper.setModel(self.model)
-
-        # Map model items onto widget controls
-        self.mapper.addMapping(self.txtBoxHeight, 0)
-        self.mapper.addMapping(self.txtBoxWidth, 1)
-        self.mapper.addMapping(self.txtCenterX, 2)
-        self.mapper.addMapping(self.txtCenterY, 3)
-        self.mapper.addMapping(self.lblAvg, 4, "text")
-        self.mapper.addMapping(self.lblAvgErr, 5, "text")
-        self.mapper.addMapping(self.lblSum, 6, "text")
-        self.mapper.addMapping(self.lblSumErr, 7, "text")
-        self.mapper.addMapping(self.lblNumPoints, 8, "text")
-
-        # Populate the widgets with data from the first column
-        self.mapper.toFirst()
-
-        self.setFixedSize(self.minimumSizeHint())
-
Index: src/sas/qtgui/Calculators/DensityPanel.py
===================================================================
--- src/sas/qtgui/Calculators/DensityPanel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/DensityPanel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,156 @@
+# global
+import logging
+import functools
+from PyQt4 import QtGui, QtCore
+
+from periodictable import formula as Formula
+
+from sas.qtgui.Utilities.GuiUtils import FormulaValidator
+
+# Local UI
+from sas.qtgui.Calculators.UI.DensityPanel import Ui_DensityPanel
+
+def enum(*sequential, **named):
+    enums = dict(zip(sequential, range(len(sequential))), **named)
+    return type('Enum', (), enums)
+
+MODEL = enum(
+    'MOLECULAR_FORMULA',
+    'MOLAR_MASS',
+    'MOLAR_VOLUME',
+    'MASS_DENSITY',
+)
+
+MODES = enum(
+    'VOLUME_TO_DENSITY',
+    'DENSITY_TO_VOLUME',
+)
+
+def toMolarMass(formula):
+    AVOGADRO = 6.02214129e23
+
+    try:
+        f = Formula(str(formula))
+        return "%g" % (f.molecular_mass * AVOGADRO)
+    except:
+        return ""
+
+
+class DensityPanel(QtGui.QDialog):
+
+    def __init__(self, parent=None):
+        super(DensityPanel, self).__init__()
+
+        self.mode = None
+        self.manager = parent
+        self.setupUi()
+        self.setupModel()
+        self.setupMapper()
+
+    def setupUi(self):
+        self.ui = Ui_DensityPanel()
+        self.ui.setupUi(self)
+
+        # no reason to have this widget resizable
+        self.setFixedSize(self.minimumSizeHint())
+
+        # set validators
+        self.ui.editMolecularFormula.setValidator(FormulaValidator(self.ui.editMolecularFormula))
+
+        rx = QtCore.QRegExp("[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?")
+        self.ui.editMolarVolume.setValidator(QtGui.QRegExpValidator(rx, self.ui.editMolarVolume))
+        self.ui.editMassDensity.setValidator(QtGui.QRegExpValidator(rx, self.ui.editMassDensity))
+
+        # signals
+        self.ui.editMolarVolume.textEdited.connect(functools.partial(self.setMode, MODES.VOLUME_TO_DENSITY))
+        self.ui.editMassDensity.textEdited.connect(functools.partial(self.setMode, MODES.DENSITY_TO_VOLUME))
+
+        self.ui.buttonBox.button(QtGui.QDialogButtonBox.Reset).clicked.connect(self.modelReset)
+        self.ui.buttonBox.button(QtGui.QDialogButtonBox.Help).clicked.connect(self.displayHelp)
+
+    def setupModel(self):
+        self.model = QtGui.QStandardItemModel(self)
+        self.model.setItem(MODEL.MOLECULAR_FORMULA, QtGui.QStandardItem())
+        self.model.setItem(MODEL.MOLAR_MASS       , QtGui.QStandardItem())
+        self.model.setItem(MODEL.MOLAR_VOLUME     , QtGui.QStandardItem())
+        self.model.setItem(MODEL.MASS_DENSITY     , QtGui.QStandardItem())
+
+        self.model.dataChanged.connect(self.dataChanged)
+
+        self.modelReset()
+
+    def setupMapper(self):
+        self.mapper = QtGui.QDataWidgetMapper(self)
+        self.mapper.setModel(self.model)
+        self.mapper.setOrientation(QtCore.Qt.Vertical)
+
+        self.mapper.addMapping(self.ui.editMolecularFormula, MODEL.MOLECULAR_FORMULA)
+        self.mapper.addMapping(self.ui.editMolarMass       , MODEL.MOLAR_MASS)
+        self.mapper.addMapping(self.ui.editMolarVolume     , MODEL.MOLAR_VOLUME)
+        self.mapper.addMapping(self.ui.editMassDensity     , MODEL.MASS_DENSITY)
+
+        self.mapper.toFirst()
+
+    def dataChanged(self, top, bottom):
+        for index in xrange(top.row(), bottom.row() + 1):
+            if index == MODEL.MOLECULAR_FORMULA:
+                molarMass = toMolarMass(self.model.item(MODEL.MOLECULAR_FORMULA).text())
+                self.model.item(MODEL.MOLAR_MASS).setText(molarMass)
+
+                if self.mode == MODES.VOLUME_TO_DENSITY:
+                    self._updateDensity()
+                elif self.mode == MODES.DENSITY_TO_VOLUME:
+                    self._updateVolume()
+
+            elif index == MODEL.MOLAR_VOLUME and self.mode == MODES.VOLUME_TO_DENSITY:
+                self._updateDensity()
+
+            elif index == MODEL.MASS_DENSITY and self.mode == MODES.DENSITY_TO_VOLUME:
+                self._updateVolume()
+
+    def setMode(self, mode):
+        self.mode = mode
+
+    def _updateDensity(self):
+        try:
+            molarMass = float(toMolarMass(self.model.item(MODEL.MOLECULAR_FORMULA).text()))
+            molarVolume = float(self.model.item(MODEL.MOLAR_VOLUME).text())
+
+            molarDensity = molarMass / molarVolume
+            self.model.item(MODEL.MASS_DENSITY).setText(str(molarDensity))
+
+        except (ArithmeticError, ValueError):
+            self.model.item(MODEL.MASS_DENSITY).setText("")
+
+    def _updateVolume(self):
+        try:
+            molarMass = float(toMolarMass(self.model.item(MODEL.MOLECULAR_FORMULA).text()))
+            molarDensity = float(self.model.item(MODEL.MASS_DENSITY).text())
+
+            molarVolume = molarMass / molarDensity
+            self.model.item(MODEL.MOLAR_VOLUME).setText(str(molarVolume))
+
+        except (ArithmeticError, ValueError):
+            self.model.item(MODEL.MOLAR_VOLUME).setText("")
+
+    def modelReset(self):
+        #self.model.beginResetModel()
+        try:
+            self.setMode(None)
+            self.model.item(MODEL.MOLECULAR_FORMULA).setText("H2O")
+            self.model.item(MODEL.MOLAR_VOLUME     ).setText("")
+            self.model.item(MODEL.MASS_DENSITY     ).setText("")
+        finally:
+            pass
+            #self.model.endResetModel()
+
+    def displayHelp(self):
+        try:
+            location = self.manager.HELP_DIRECTORY_LOCATION + \
+                "/user/sasgui/perspectives/calculator/density_calculator_help.html"
+
+            self.manager._helpView.load(QtCore.QUrl(location))
+            self.manager._helpView.show()
+        except AttributeError:
+            # No manager defined - testing and standalone runs
+            pass
Index: src/sas/qtgui/Calculators/KiessigPanel.py
===================================================================
--- src/sas/qtgui/Calculators/KiessigPanel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/KiessigPanel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,62 @@
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+from UI.KiessigPanel import Ui_KiessigPanel
+
+# sas-global
+from sas.sascalc.calculator.kiessig_calculator import KiessigThicknessCalculator
+
+
+class KiessigPanel(QtGui.QDialog, Ui_KiessigPanel):
+    def __init__(self, parent=None):
+        super(KiessigPanel, self).__init__()
+        self.setupUi(self)
+
+        self.setWindowTitle("Kiessig Thickness Calculator")
+
+        self.manager = parent
+        self.thickness = KiessigThicknessCalculator()
+
+        self.deltaq_in.setText("0.05")
+
+        # signals
+        self.helpButton.clicked.connect(self.onHelp)
+        self.computeButton.clicked.connect(self.onCompute)
+        self.closeButton.clicked.connect(self.onClose)
+
+        # no reason to have this widget resizable
+        self.setFixedSize(self.minimumSizeHint())
+
+    def onHelp(self):
+        """
+        Bring up the Kiessig fringe calculator Documentation whenever
+        the HELP button is clicked.
+        Calls DocumentationWindow with the path of the location within the
+        documentation tree (after /doc/ ....".
+        """
+        try:
+            location = self.manager.HELP_DIRECTORY_LOCATION + \
+                "/user/sasgui/perspectives/calculator/kiessig_calculator_help.html"
+
+            self.manager._helpView.load(QtCore.QUrl(location))
+            self.manager._helpView.show()
+        except AttributeError:
+            # No manager defined - testing and standalone runs
+            pass
+
+    def onCompute(self):
+        """
+        Execute the computation of thickness
+        """
+        try:
+            self.thickness.set_deltaq(dq=float(self.deltaq_in.text()))
+            kiessing_result = self.thickness.compute_thickness()
+            float_as_str = "{:.3f}".format(kiessing_result)
+            self.lengthscale_out.setText(float_as_str)
+        except (ArithmeticError, ValueError):
+            self.lengthscale_out.setText("")
+
+    def onClose(self):
+        """
+        close the window containing this panel
+        """
+        self.close()
Index: src/sas/qtgui/Calculators/SldPanel.py
===================================================================
--- src/sas/qtgui/Calculators/SldPanel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/SldPanel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,224 @@
+# global
+import logging
+from PyQt4 import QtGui, QtCore
+
+from periodictable import formula as Formula
+from periodictable.xsf import xray_energy, xray_sld_from_atoms
+from periodictable.nsf import neutron_scattering
+
+from sas.qtgui.Utilities.GuiUtils import FormulaValidator
+
+# Local UI
+from sas.qtgui.Calculators.UI.SldPanel import Ui_SldPanel
+
+def enum(*sequential, **named):
+    enums = dict(zip(sequential, range(len(sequential))), **named)
+    return type('Enum', (), enums)
+
+MODEL = enum(
+    'MOLECULAR_FORMULA',
+    'MASS_DENSITY',
+    'WAVELENGTH',
+    'NEUTRON_SLD_REAL',
+    'NEUTRON_SLD_IMAG',
+    'CU_KA_SLD_REAL',
+    'CU_KA_SLD_IMAG',
+    'MO_KA_SLD_REAL',
+    'MO_KA_SLD_IMAG',
+    'NEUTRON_INC_XS',
+    'NEUTRON_ABS_XS',
+    'NEUTRON_LENGTH',
+)
+
+class SldResult(object):
+    def __init__(self, molecular_formula, mass_density, wavelength,
+        neutron_sld_real, neutron_sld_imag,
+        cu_ka_sld_real, cu_ka_sld_imag,
+        mo_ka_sld_real, mo_ka_sld_imag,
+        neutron_inc_xs, neutron_abs_xs, neutron_length):
+
+        self.molecular_formula = molecular_formula
+        self.mass_density = mass_density
+        self.wavelength = wavelength
+        self.neutron_sld_real = neutron_sld_real
+        self.neutron_sld_imag = neutron_sld_imag
+        self.cu_ka_sld_real = cu_ka_sld_real
+        self.cu_ka_sld_imag = cu_ka_sld_imag
+        self.mo_ka_sld_real = mo_ka_sld_real
+        self.mo_ka_sld_imag = mo_ka_sld_imag
+        self.neutron_inc_xs = neutron_inc_xs
+        self.neutron_abs_xs = neutron_abs_xs
+        self.neutron_length = neutron_length
+
+def sldAlgorithm(molecular_formula, mass_density, wavelength):
+
+    sld_formula = Formula(molecular_formula, density=mass_density)
+
+    def calculate_sld(formula):
+        if len(formula.atoms) != 1:
+            raise NotImplementedError()
+        energy = xray_energy(formula.atoms.keys()[0].K_alpha)
+        return xray_sld_from_atoms(
+            sld_formula.atoms,
+            density=mass_density,
+            energy=energy)
+
+    cu_real, cu_imag = calculate_sld(Formula("Cu"))
+    mo_real, mo_imag = calculate_sld(Formula("Mo"))
+
+    (sld_real, sld_imag, _), (_, neutron_abs_xs, neutron_inc_xs), neutron_length = \
+        neutron_scattering(
+            compound=molecular_formula,
+            density=mass_density,
+            wavelength=wavelength)
+
+    SCALE = 1e-6
+
+    # neutron sld
+    neutron_sld_real = SCALE * sld_real
+    neutron_sld_imag = SCALE * abs(sld_imag)
+
+    # Cu sld
+    cu_ka_sld_real = SCALE * cu_real
+    cu_ka_sld_imag = SCALE * abs(cu_imag)
+
+    # Mo sld
+    mo_ka_sld_real = SCALE * mo_real
+    mo_ka_sld_imag = SCALE * abs(mo_imag)
+
+    return SldResult(
+        molecular_formula, mass_density, wavelength,
+        neutron_sld_real, neutron_sld_imag,
+        cu_ka_sld_real, cu_ka_sld_imag,
+        mo_ka_sld_real, mo_ka_sld_imag,
+        neutron_inc_xs, neutron_abs_xs, neutron_length)
+
+
+class SldPanel(QtGui.QDialog):
+
+    def __init__(self, parent=None):
+        super(SldPanel, self).__init__()
+
+        self.manager = parent
+
+        self.setupUi()
+        self.setupModel()
+        self.setupMapper()
+
+    def _getOutputs(self):
+        return {
+            MODEL.NEUTRON_SLD_REAL: self.ui.editNeutronSldReal,
+            MODEL.NEUTRON_SLD_IMAG: self.ui.editNeutronSldImag,
+            MODEL.CU_KA_SLD_REAL: self.ui.editCuKaSldReal,
+            MODEL.CU_KA_SLD_IMAG: self.ui.editCuKaSldImag,
+            MODEL.MO_KA_SLD_REAL: self.ui.editMoKaSldReal,
+            MODEL.MO_KA_SLD_IMAG: self.ui.editMoKaSldImag,
+            MODEL.NEUTRON_INC_XS: self.ui.editNeutronIncXs,
+            MODEL.NEUTRON_ABS_XS: self.ui.editNeutronAbsXs,
+            MODEL.NEUTRON_LENGTH: self.ui.editNeutronLength
+        }
+
+    def setupUi(self):
+        self.ui = Ui_SldPanel()
+        self.ui.setupUi(self)
+
+        # set validators
+        self.ui.editMolecularFormula.setValidator(FormulaValidator(self.ui.editMolecularFormula))
+
+        rx = QtCore.QRegExp("[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?")
+        self.ui.editMassDensity.setValidator(QtGui.QRegExpValidator(rx, self.ui.editMassDensity))
+        self.ui.editWavelength.setValidator(QtGui.QRegExpValidator(rx, self.ui.editWavelength))
+
+        # signals
+        self.ui.buttonBox.button(QtGui.QDialogButtonBox.Reset).clicked.connect(self.modelReset)
+        self.ui.buttonBox.button(QtGui.QDialogButtonBox.Help).clicked.connect(self.displayHelp)
+
+    def setupModel(self):
+        self.model = QtGui.QStandardItemModel(self)
+        self.model.setItem(MODEL.MOLECULAR_FORMULA, QtGui.QStandardItem())
+        self.model.setItem(MODEL.MASS_DENSITY     , QtGui.QStandardItem())
+        self.model.setItem(MODEL.WAVELENGTH       , QtGui.QStandardItem())
+
+        for key in self._getOutputs().keys():
+            self.model.setItem(key, QtGui.QStandardItem())
+
+        QtCore.QObject.connect(
+            self.model,
+            QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
+            self.dataChanged)
+
+        self.modelReset()
+
+    def setupMapper(self):
+        self.mapper = QtGui.QDataWidgetMapper(self)
+        self.mapper.setModel(self.model)
+        self.mapper.setOrientation(QtCore.Qt.Vertical)
+
+        self.mapper.addMapping(self.ui.editMolecularFormula, MODEL.MOLECULAR_FORMULA)
+        self.mapper.addMapping(self.ui.editMassDensity     , MODEL.MASS_DENSITY)
+        self.mapper.addMapping(self.ui.editWavelength      , MODEL.WAVELENGTH)
+
+        for key, edit in self._getOutputs().iteritems():
+            self.mapper.addMapping(edit, key)
+
+        self.mapper.toFirst()
+
+    def dataChanged(self, top, bottom):
+        update = False
+        for index in xrange(top.row(), bottom.row() + 1):
+            if (index == MODEL.MOLECULAR_FORMULA) or (index == MODEL.MASS_DENSITY) or (index == MODEL.WAVELENGTH):
+                update = True
+
+        # calcualtion
+        if update:
+            formula = self.model.item(MODEL.MOLECULAR_FORMULA).text()
+            density = self.model.item(MODEL.MASS_DENSITY).text()
+            wavelength = self.model.item(MODEL.WAVELENGTH).text()
+            if len(formula) > 0 and len(density) > 0 and len(wavelength) > 0:
+                try:
+                    results = sldAlgorithm(str(formula), float(density), float(wavelength))
+
+                    def format(value):
+                        return ("%-5.3g" % value).strip()
+
+                    self.model.item(MODEL.NEUTRON_SLD_REAL).setText(format(results.neutron_sld_real))
+                    self.model.item(MODEL.NEUTRON_SLD_IMAG).setText(format(results.neutron_sld_imag))
+
+                    self.model.item(MODEL.CU_KA_SLD_REAL).setText(format(results.cu_ka_sld_real))
+                    self.model.item(MODEL.CU_KA_SLD_IMAG).setText(format(results.cu_ka_sld_imag))
+
+                    self.model.item(MODEL.MO_KA_SLD_REAL).setText(format(results.mo_ka_sld_real))
+                    self.model.item(MODEL.MO_KA_SLD_IMAG).setText(format(results.mo_ka_sld_imag))
+
+                    self.model.item(MODEL.NEUTRON_INC_XS).setText(format(results.neutron_inc_xs))
+                    self.model.item(MODEL.NEUTRON_ABS_XS).setText(format(results.neutron_abs_xs))
+                    self.model.item(MODEL.NEUTRON_LENGTH).setText(format(results.neutron_length))
+
+                    return
+            
+                except Exception as e:
+                    pass
+
+            for key in self._getOutputs().keys():
+                self.model.item(key).setText("")
+
+    def modelReset(self):
+        #self.model.beginResetModel()
+        try:
+            self.model.item(MODEL.MOLECULAR_FORMULA).setText("H2O")
+            self.model.item(MODEL.MASS_DENSITY     ).setText("1")
+            self.model.item(MODEL.WAVELENGTH       ).setText("6")
+        finally:
+            pass
+            #self.model.endResetModel()
+
+    def displayHelp(self):
+        try:
+            location = self.manager.HELP_DIRECTORY_LOCATION + \
+                "/user/sasgui/perspectives/calculator/sld_calculator_help.html"
+            self.manager._helpView.load(QtCore.QUrl(location))
+            self.manager._helpView.show()
+        except AttributeError:
+            # No manager defined - testing and standalone runs
+            pass
+
Index: src/sas/qtgui/Calculators/SlitSizeCalculator.py
===================================================================
--- src/sas/qtgui/Calculators/SlitSizeCalculator.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/SlitSizeCalculator.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,133 @@
+"""
+Slit Size Calculator Panel
+"""
+import os
+import sys
+
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+from UI.SlitSizeCalculator import Ui_SlitSizeCalculator
+from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.calculator.slit_length_calculator import SlitlengthCalculator
+
+
+class SlitSizeCalculator(QtGui.QDialog, Ui_SlitSizeCalculator):
+    """
+    Provides the slit length calculator GUI.
+    """
+    def __init__(self, parent=None):
+        super(SlitSizeCalculator, self).__init__()
+        self.setupUi(self)
+
+        self.setWindowTitle("Slit Size Calculator")
+        self._parent = parent
+
+        self.thickness = SlitlengthCalculator()
+
+        # signals
+        self.helpButton.clicked.connect(self.onHelp)
+        self.browseButton.clicked.connect(self.onBrowse)
+        self.closeButton.clicked.connect(self.onClose)
+
+        # no reason to have this widget resizable
+        self.setFixedSize(self.minimumSizeHint())
+
+
+    def onHelp(self):
+        """
+        Bring up the Slit Size Calculator calculator Documentation whenever
+        the HELP button is clicked.
+        Calls DocumentationWindow with the path of the location within the
+        documentation tree (after /doc/ ....".
+        """
+        try:
+            location = self._parent.HELP_DIRECTORY_LOCATION + \
+                "/user/sasgui/perspectives/calculator/slit_calculator_help.html"
+
+            self._parent._helpView.load(QtCore.QUrl(location))
+            self._parent._helpView.show()
+        except AttributeError:
+            # No manager defined - testing and standalone runs
+            pass
+
+    def onBrowse(self):
+        """
+        Browse the file and calculate slit lenght upon loading
+        """
+        path_str = self.chooseFile()
+        if not path_str:
+            return
+        loader = Loader()
+        data = loader.load(path_str)
+
+        self.data_file.setText(os.path.basename(path_str))
+        self.calculateSlitSize(data)
+
+    def chooseFile(self):
+        """
+        Shows the Open file dialog and returns the chosen path(s)
+        """
+
+        # Location is automatically saved - no need to keep track of the last dir
+        # But only with Qt built-in dialog (non-platform native)
+        path = QtGui.QFileDialog.getOpenFileName(self, "Choose a file", "",
+                                                 "SAXSess 1D data (*.txt *.TXT *.dat *.DAT)", None,
+                                                 QtGui.QFileDialog.DontUseNativeDialog)
+
+        if path is None:
+            return
+
+        if isinstance(path, QtCore.QString):
+            path = str(path)
+
+        return path
+
+    def onClose(self):
+        """
+        close the window containing this panel
+        """
+        self.close()
+
+    def clearResults(self):
+        """
+        Clear the content of output LineEdits
+        """
+        self.slit_length_out.setText("ERROR!")
+        self.unit_out.clear()
+
+    def calculateSlitSize(self, data=None):
+        """
+        Computes slit lenght from given 1D data
+        """
+
+        if data is None:
+            self.clearResults()
+            msg = "ERROR: Data hasn't been loaded correctly"
+            raise RuntimeError, msg
+
+        if data.__class__.__name__ == 'Data2D':
+            self.clearResults()
+            msg = "Slit Length cannot be computed for 2D Data"
+            raise RuntimeError, msg
+
+        #compute the slit size
+        try:
+            xdata = data.x
+            ydata = data.y
+            if xdata == [] or xdata is None or ydata == [] or ydata is None:
+                msg = "The current data is empty please check x and y"
+                raise ValueError, msg
+            slit_length_calculator = SlitlengthCalculator()
+            slit_length_calculator.set_data(x=xdata, y=ydata)
+            slit_length = slit_length_calculator.calculate_slit_length()
+        except:
+            self.clearResults()
+            msg = "Slit Size Calculator: %s" % (sys.exc_value)
+            raise RuntimeError, msg
+
+        slit_length_str = "{:.5f}".format(slit_length)
+        self.slit_length_out.setText(slit_length_str)
+
+        #Display unit, which most likely needs to be 1/Ang but needs to be confirmed
+        self.unit_out.setText("[Unknown]")
+
Index: src/sas/qtgui/Calculators/UI/DensityPanel.ui
===================================================================
--- src/sas/qtgui/Calculators/UI/DensityPanel.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/UI/DensityPanel.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DensityPanel</class>
+ <widget class="QDialog" name="DensityPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>290</width>
+    <height>178</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Density/Volume Calculator</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label_1">
+       <property name="text">
+        <string>Molecular Formula</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="editMolecularFormula"/>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>e.g. H2O</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Molar Mass</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLineEdit" name="editMolarMass">
+       <property name="styleSheet">
+        <string notr="true"/>
+       </property>
+       <property name="readOnly">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="2">
+      <widget class="QLabel" name="label_4">
+       <property name="text">
+        <string>g/mol</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="0" colspan="3">
+      <widget class="QFrame" name="frame">
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>5</height>
+        </size>
+       </property>
+       <property name="frameShape">
+        <enum>QFrame::HLine</enum>
+       </property>
+       <property name="frameShadow">
+        <enum>QFrame::Raised</enum>
+       </property>
+       <property name="lineWidth">
+        <number>1</number>
+       </property>
+       <property name="midLineWidth">
+        <number>0</number>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="0">
+      <widget class="QLabel" name="label_5">
+       <property name="text">
+        <string>Molar Volume</string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1">
+      <widget class="QLineEdit" name="editMolarVolume"/>
+     </item>
+     <item row="3" column="2">
+      <widget class="QLabel" name="label_6">
+       <property name="text">
+        <string>cmÂ³/mol</string>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="0">
+      <widget class="QLabel" name="label_7">
+       <property name="text">
+        <string>Mass Density</string>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="1">
+      <widget class="QLineEdit" name="editMassDensity"/>
+     </item>
+     <item row="4" column="2">
+      <widget class="QLabel" name="label_8">
+       <property name="text">
+        <string>g/cmÂ³</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="0">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Expanding</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="0">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::Reset</set>
+     </property>
+     <property name="centerButtons">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>editMolecularFormula</tabstop>
+  <tabstop>editMolarMass</tabstop>
+  <tabstop>editMolarVolume</tabstop>
+  <tabstop>editMassDensity</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>DensityPanel</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>DensityPanel</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Calculators/UI/KiessigPanel.ui
===================================================================
--- src/sas/qtgui/Calculators/UI/KiessigPanel.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/UI/KiessigPanel.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>KiessigPanel</class>
+ <widget class="QDialog" name="KiessigPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>354</width>
+    <height>193</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <property name="toolTip">
+   <string/>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_3">
+   <item row="0" column="0" colspan="3">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Input</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="0">
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <widget class="QLabel" name="label">
+          <property name="text">
+           <string>Kiessing Fringe Width (Delta Q)</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="deltaq_in"/>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_2">
+          <property name="text">
+           <string>1/Ã
+</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="1" column="0" colspan="3">
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="title">
+      <string>Output</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="0">
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <item>
+         <widget class="QLabel" name="label_3">
+          <property name="text">
+           <string>Thickness (or Diameter)               </string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="lengthscale_out">
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_4">
+          <property name="text">
+           <string>   Ã
+</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="2" column="2">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="3" column="1">
+    <widget class="QPushButton" name="closeButton">
+     <property name="toolTip">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Close this window.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="text">
+      <string>Close</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="2">
+    <widget class="QPushButton" name="helpButton">
+     <property name="toolTip">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Help using the Kiessing fringe calculator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="text">
+      <string>Help</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0">
+    <widget class="QPushButton" name="computeButton">
+     <property name="toolTip">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Compute the thickness or diameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="text">
+      <string>Compute</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
Index: src/sas/qtgui/Calculators/UI/SldPanel.ui
===================================================================
--- src/sas/qtgui/Calculators/UI/SldPanel.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/UI/SldPanel.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,380 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SldPanel</class>
+ <widget class="QDialog" name="SldPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>447</width>
+    <height>403</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>SLD Calculator</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0">
+    <widget class="QGroupBox" name="groupBoxInput">
+     <property name="title">
+      <string>Input</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayoutInput">
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_8">
+        <property name="text">
+         <string>Mass Density</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2">
+       <widget class="QLabel" name="label_16">
+        <property name="text">
+         <string>g/cmÂ³</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <widget class="QLabel" name="label_10">
+        <property name="text">
+         <string>e.g. H2O</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLineEdit" name="editMolecularFormula"/>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLineEdit" name="editMassDensity"/>
+      </item>
+      <item row="2" column="1">
+       <widget class="QLineEdit" name="editWavelength">
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <property name="readOnly">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QLabel" name="label_12">
+        <property name="text">
+         <string>Ã
+</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_9">
+        <property name="text">
+         <string>Molecular Formula</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label_11">
+        <property name="text">
+         <string>Wavelength</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QGroupBox" name="groupBoxOutput">
+     <property name="title">
+      <string>Output</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayoutOutput">
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_17">
+        <property name="text">
+         <string>Neutron SLD</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLineEdit" name="editNeutronSldReal">
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <widget class="QLabel" name="label_18">
+        <property name="text">
+         <string>-i</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3">
+       <widget class="QLineEdit" name="editNeutronSldImag">
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="4">
+       <widget class="QLabel" name="label_5">
+        <property name="text">
+         <string>1/Ã
+Â²</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_19">
+        <property name="text">
+         <string>Cu Ka SLD</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLineEdit" name="editCuKaSldReal">
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2">
+       <widget class="QLabel" name="label_20">
+        <property name="text">
+         <string>-i</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="3">
+       <widget class="QLineEdit" name="editCuKaSldImag">
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="4">
+       <widget class="QLabel" name="label_6">
+        <property name="text">
+         <string>1/Ã
+Â²</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Mo Ka SLD</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QLineEdit" name="editMoKaSldReal">
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>-i</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="3">
+       <widget class="QLineEdit" name="editMoKaSldImag">
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="4">
+       <widget class="QLabel" name="label_7">
+        <property name="text">
+         <string>1/Ã
+Â²</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0" colspan="5">
+       <widget class="QFrame" name="frame">
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>5</height>
+         </size>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::HLine</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Raised</enum>
+        </property>
+        <property name="lineWidth">
+         <number>1</number>
+        </property>
+        <property name="midLineWidth">
+         <number>0</number>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="0">
+       <widget class="QLabel" name="label_21">
+        <property name="text">
+         <string>Neutron Inc. Xs</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="1">
+       <widget class="QLineEdit" name="editNeutronIncXs">
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="2" colspan="2">
+       <widget class="QLabel" name="label_22">
+        <property name="text">
+         <string>1/cm</string>
+        </property>
+       </widget>
+      </item>
+      <item row="5" column="0">
+       <widget class="QLabel" name="label_23">
+        <property name="text">
+         <string>Neutron Abs. Xs</string>
+        </property>
+       </widget>
+      </item>
+      <item row="5" column="1">
+       <widget class="QLineEdit" name="editNeutronAbsXs">
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="5" column="2" colspan="2">
+       <widget class="QLabel" name="label_24">
+        <property name="text">
+         <string>1/cm</string>
+        </property>
+       </widget>
+      </item>
+      <item row="6" column="0">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Neutron 1/e length</string>
+        </property>
+       </widget>
+      </item>
+      <item row="6" column="1">
+       <widget class="QLineEdit" name="editNeutronLength">
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="6" column="2" colspan="2">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>cm</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="3" column="0">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::Reset</set>
+     </property>
+     <property name="centerButtons">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>editMolecularFormula</tabstop>
+  <tabstop>editMassDensity</tabstop>
+  <tabstop>editWavelength</tabstop>
+  <tabstop>editNeutronSldReal</tabstop>
+  <tabstop>editNeutronSldImag</tabstop>
+  <tabstop>editCuKaSldReal</tabstop>
+  <tabstop>editCuKaSldImag</tabstop>
+  <tabstop>editMoKaSldReal</tabstop>
+  <tabstop>editMoKaSldImag</tabstop>
+  <tabstop>editNeutronIncXs</tabstop>
+  <tabstop>editNeutronAbsXs</tabstop>
+  <tabstop>editNeutronLength</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>SldPanel</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>SldPanel</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Calculators/UI/SlitSizeCalculator.ui
===================================================================
--- src/sas/qtgui/Calculators/UI/SlitSizeCalculator.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/UI/SlitSizeCalculator.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SlitSizeCalculator</class>
+ <widget class="QDialog" name="SlitSizeCalculator">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>496</width>
+    <height>253</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <property name="toolTip">
+   <string/>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_3">
+   <item row="0" column="0">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Input</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="0">
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <widget class="QLabel" name="label">
+          <property name="text">
+           <string>Data</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="data_file">
+          <property name="minimumSize">
+           <size>
+            <width>200</width>
+            <height>21</height>
+           </size>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="1" column="0" colspan="3">
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="title">
+      <string>Output</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="0">
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <item>
+         <widget class="QLabel" name="label_3">
+          <property name="text">
+           <string>Slit Size (FWHM/2):</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="slit_length_out">
+          <property name="minimumSize">
+           <size>
+            <width>110</width>
+            <height>21</height>
+           </size>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item row="0" column="1">
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <item>
+         <widget class="QLabel" name="label_2">
+          <property name="text">
+           <string>Unit:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="unit_out">
+          <property name="minimumSize">
+           <size>
+            <width>100</width>
+            <height>21</height>
+           </size>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="0" column="2">
+    <widget class="QPushButton" name="browseButton">
+     <property name="toolTip">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Compute the thickness or diameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="text">
+      <string>Browse</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="2">
+    <widget class="QPushButton" name="helpButton">
+     <property name="toolTip">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Help using the Kiessing fringe calculator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="text">
+      <string>Help</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <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 row="4" column="1">
+    <widget class="QPushButton" name="closeButton">
+     <property name="toolTip">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Close this window.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="text">
+      <string>Close</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <spacer name="horizontalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>40</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
Index: src/sas/qtgui/Calculators/UnitTesting/DensityCalculatorTest.py
===================================================================
--- src/sas/qtgui/Calculators/UnitTesting/DensityCalculatorTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/UnitTesting/DensityCalculatorTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,121 @@
+import sys
+import unittest
+import webbrowser
+
+from PyQt4 import QtGui
+from PyQt4.QtTest import QTest
+from PyQt4 import QtCore
+from mock import MagicMock
+
+####### TEMP
+import sas.qtgui.path_prepare
+#######
+
+# Local
+from sas.qtgui.Calculators.DensityPanel import DensityPanel
+from sas.qtgui.Calculators.DensityPanel import toMolarMass
+from sas.qtgui.Utilities.GuiUtils import FormulaValidator
+
+import sas.qtgui.Utilities.LocalConfig
+
+app = QtGui.QApplication(sys.argv)
+
+class ToMolarMassTest(unittest.TestCase):
+    """ Test the auxiliary conversion method"""
+    def testGoodEasy(self):
+        self.assertEqual(toMolarMass("H2"), "2.01588")
+
+    def testGoodComplex(self):
+        self.assertEqual(toMolarMass("H24O12C4C6N2Pu"), "608.304")
+
+    def testGoodComplex2(self):
+        self.assertEqual(toMolarMass("(H2O)0.5(D2O)0.5"), "19.0214")
+
+    def testBadInputInt(self):
+        self.assertEqual(toMolarMass(1), "")
+
+    def testBadInputStr(self):
+        self.assertEqual(toMolarMass("Im a bad string"), "")
+
+class DensityCalculatorTest(unittest.TestCase):
+    '''Test the DensityCalculator'''
+    def setUp(self):
+        '''Create the DensityCalculator'''
+        self.widget = DensityPanel(None)
+
+    def tearDown(self):
+        '''Destroy the DensityCalculator'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtGui.QWidget)
+        self.assertEqual(self.widget.windowTitle(), "Density/Volume Calculator")
+        self.assertIsInstance(self.widget.ui.editMolecularFormula.validator(), FormulaValidator)
+        self.assertEqual(self.widget.ui.editMolecularFormula.styleSheet(), '')
+        self.assertEqual(self.widget.model.columnCount(), 1)
+        self.assertEqual(self.widget.model.rowCount(), 4)
+        self.assertEqual(self.widget.sizePolicy().Policy(), QtGui.QSizePolicy.Fixed)
+
+    def testSimpleEntry(self):
+        ''' Default compound calculations '''
+        self.widget.ui.editMolarVolume.insert("1.0")
+
+        self.widget.show()
+        # Send tab x3
+        key = QtCore.Qt.Key_Tab
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.qWait(100)
+
+        # Assure the mass density field is set
+        self.assertEqual(self.widget.ui.editMassDensity.text(), '18.0153')
+
+        # Change mass density
+        self.widget.ui.editMassDensity.insert("16.0")
+        # Send shift-tab to update the molar volume field
+        key =  QtCore.Qt.Key_Tab
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.ShiftModifier)
+        QTest.qWait(100)
+
+        # Assure the molar volume field got updated
+        self.assertEqual(self.widget.ui.editMolarVolume.text(), '1.12595625')
+
+    def testComplexEntryAndReset(self):
+        ''' User entered compound calculations and subsequent reset'''
+
+        self.widget.ui.editMolecularFormula.clear()
+        self.widget.ui.editMolecularFormula.insert("KMnO4")
+        self.widget.ui.editMolarVolume.insert("2.0")
+
+        self.widget.show()
+        # Send tab x3
+        key = QtCore.Qt.Key_Tab
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.qWait(100)
+
+        # Assure the mass density field is set
+        self.assertEqual(self.widget.ui.editMassDensity.text(), '79.017')
+
+        # Reset the widget
+        self.widget.modelReset()
+
+        self.assertEqual(self.widget.ui.editMolecularFormula.text(), "H2O")
+        self.assertEqual(self.widget.ui.editMolarMass.text(), "18.0153")
+        self.assertEqual(self.widget.ui.editMolarVolume.text(), "")
+        self.assertEqual(self.widget.ui.editMassDensity.text(), "")
+
+        #self.widget.exec_()
+
+    def testHelp(self):
+        """ Assure help file is shown """
+
+        # this should not rise
+        self.widget.displayHelp()
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Calculators/UnitTesting/KiessigCalculatorTest.py
===================================================================
--- src/sas/qtgui/Calculators/UnitTesting/KiessigCalculatorTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/UnitTesting/KiessigCalculatorTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,83 @@
+import sys
+import unittest
+from PyQt4 import QtGui
+from PyQt4.QtTest import QTest
+from PyQt4.QtCore import Qt
+
+# TEMP
+import sas.qtgui.path_prepare
+
+
+from sas.qtgui.Calculators.KiessigPanel import KiessigPanel
+
+app = QtGui.QApplication(sys.argv)
+
+
+class KiessigCalculatorTest(unittest.TestCase):
+    """Test the KiessigCalculator"""
+    def setUp(self):
+        """Create the KiessigCalculator"""
+        self.widget = KiessigPanel(None)
+
+    def tearDown(self):
+        """Destroy the KiessigCalculator"""
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        """Test the GUI in its default state"""
+        self.assertIsInstance(self.widget, QtGui.QWidget)
+        self.assertEqual(self.widget.windowTitle(), "Kiessig Thickness Calculator")
+        self.assertEqual(self.widget.sizePolicy().Policy(), QtGui.QSizePolicy.Fixed)
+
+    def testHelp(self):
+        """ Assure help file is shown """
+
+        # this should not rise
+        self.widget.onHelp()
+
+    def testComplexEntryNumbers(self):
+        """ User entered compound calculations and subsequent reset"""
+
+        self.widget.deltaq_in.clear()
+        self.widget.deltaq_in.insert('0.05')
+        #
+        # Push Compute with the left mouse button
+        computeButton = self.widget.computeButton
+        QTest.mouseClick(computeButton, Qt.LeftButton)
+        self.assertEqual(self.widget.lengthscale_out.text(), '125.664')
+
+    def testComplexEntryNumbers2(self):
+        """ User entered compound calculations and subsequent reset"""
+
+        self.widget.deltaq_in.clear()
+        self.widget.deltaq_in.insert('1.0')
+        #
+        # Push Compute with the left mouse button
+        computeButton = self.widget.computeButton
+        QTest.mouseClick(computeButton, Qt.LeftButton)
+        self.assertEqual(self.widget.lengthscale_out.text(), '6.283')
+
+    def testComplexEntryNumbers3(self):
+        """ User entered compound calculations and subsequent reset"""
+
+        self.widget.deltaq_in.clear()
+        self.widget.deltaq_in.insert('2.0')
+        #
+        # Push Compute with the left mouse button
+        computeButton = self.widget.computeButton
+        QTest.mouseClick(computeButton, Qt.LeftButton)
+        self.assertEqual(self.widget.lengthscale_out.text(), '3.142')
+
+    def testComplexEntryLetters(self):
+        """ User entered compound calculations and subsequent reset"""
+
+        self.widget.deltaq_in.insert("xyz")
+
+        # Push Compute with the left mouse button
+        computeButton = self.widget.computeButton
+        QTest.mouseClick(computeButton, Qt.LeftButton)
+        self.assertEqual(self.widget.lengthscale_out.text(), '')
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Calculators/UnitTesting/SLDCalculatorTest.py
===================================================================
--- src/sas/qtgui/Calculators/UnitTesting/SLDCalculatorTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/UnitTesting/SLDCalculatorTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,145 @@
+import sys
+import unittest
+import webbrowser
+
+from PyQt4 import QtGui
+from PyQt4.QtTest import QTest
+from PyQt4 import QtCore
+from mock import MagicMock
+
+####### TEMP
+import sas.qtgui.path_prepare
+#######
+
+# Local
+from sas.qtgui.Calculators.SldPanel import SldResult
+from sas.qtgui.Calculators.SldPanel import SldPanel
+from sas.qtgui.Calculators.SldPanel import sldAlgorithm
+from sas.qtgui.Utilities.GuiUtils import FormulaValidator
+
+import sas.qtgui.Utilities.LocalConfig
+
+app = QtGui.QApplication(sys.argv)
+
+class SldResultTest(unittest.TestCase):
+    """ Test the simple container class"""
+    def testObjectSize(self):
+        results = SldResult(0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                            0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
+        self.assertEqual(sys.getsizeof(results), 56)
+
+
+class SldAlgorithmTest(unittest.TestCase):
+    """ Test the periodictable wrapper """
+    def testSldAlgorithm1(self):
+        molecular_formula = "H2O"
+        mass_density = 1.0
+        wavelength = 6.0
+        
+        results = sldAlgorithm( molecular_formula,
+                                mass_density,
+                                wavelength)
+        self.assertIsInstance(results, SldResult)
+        self.assertAlmostEqual(results.neutron_length, 0.175463, 5)
+        self.assertAlmostEqual(results.neutron_inc_xs, 5.365857, 5)
+        self.assertAlmostEqual(results.neutron_abs_xs, 0.074224, 5)
+
+    def testSldAlgorithm2(self):
+        molecular_formula = "C29O[18]5+7NH[2]3"
+        mass_density = 3.0
+        wavelength = 666.0
+        
+        results = sldAlgorithm( molecular_formula,
+                                mass_density,
+                                wavelength)
+        self.assertIsInstance(results, SldResult)
+        self.assertAlmostEqual(results.neutron_length,   0.059402, 5)
+        self.assertAlmostEqual(results.neutron_inc_xs,   0.145427, 5)
+        self.assertAlmostEqual(results.neutron_abs_xs,  15.512215, 5)
+        self.assertAlmostEqual(results.neutron_sld_real, 1.3352833e-05, 5)
+        self.assertAlmostEqual(results.neutron_sld_imag, 1.1645807e-10, 5)
+
+
+class SLDCalculatorTest(unittest.TestCase):
+    '''Test the SLDCalculator'''
+    def setUp(self):
+        '''Create the SLDCalculator'''
+        self.widget = SldPanel(None)
+
+    def tearDown(self):
+        '''Destroy the DensityCalculator'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtGui.QWidget)
+        self.assertEqual(self.widget.windowTitle(), "SLD Calculator")
+        self.assertIsInstance(self.widget.ui.editMolecularFormula.validator(), FormulaValidator)
+        self.assertEqual(self.widget.ui.editMolecularFormula.styleSheet(), '')
+        self.assertEqual(self.widget.model.columnCount(), 1)
+        self.assertEqual(self.widget.model.rowCount(), 12)
+        self.assertEqual(self.widget.sizePolicy().Policy(), QtGui.QSizePolicy.Fixed)
+
+    def testSimpleEntry(self):
+        ''' Default compound calculations '''
+
+        self.widget.show()
+
+        self.widget.ui.editMassDensity.clear()
+        self.widget.ui.editMassDensity.insert("1.0")
+        # Send tab x3
+        key = QtCore.Qt.Key_Tab
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QtGui.qApp.processEvents()
+        QTest.qWait(100)
+
+        # Assure the output fields are set
+        self.assertEqual(self.widget.ui.editNeutronIncXs.text(), '5.37')
+
+        # Change mass density
+        self.widget.ui.editWavelength.clear()
+        self.widget.ui.editWavelength.setText("666.0")
+
+        # Send shift-tab to update the molar volume field
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QtGui.qApp.processEvents()
+        QTest.qWait(100)
+
+        # Assure the molar volume field got updated
+        self.assertEqual(self.widget.ui.editNeutronAbsXs.text(), '8.24')
+
+    def testComplexEntryAndReset(self):
+        ''' User entered compound calculations and subsequent reset'''
+
+        self.widget.ui.editMolecularFormula.clear()
+        self.widget.ui.editMolecularFormula.insert("CaCO[18]3+6H2O")
+        self.widget.ui.editMassDensity.insert("5.0")
+
+        self.widget.show()
+        # Send tab x2
+        key = QtCore.Qt.Key_Tab
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
+        QTest.qWait(100)
+
+        # Assure the mass density field is set
+        self.assertEqual(self.widget.ui.editNeutronIncXs.text(), '40.6')
+
+        # Reset the widget
+        self.widget.modelReset()
+
+        self.assertEqual(self.widget.ui.editMolecularFormula.text(), "H2O")
+        self.assertEqual(self.widget.ui.editMassDensity.text(), "1")
+        self.assertEqual(self.widget.ui.editWavelength.text(), "6")
+
+    def testHelp(self):
+        """ Assure help file is shown """
+
+        # this should not rise
+        self.widget.displayHelp()
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Calculators/UnitTesting/SlitSizeCalculatorTest.py
===================================================================
--- src/sas/qtgui/Calculators/UnitTesting/SlitSizeCalculatorTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Calculators/UnitTesting/SlitSizeCalculatorTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,103 @@
+import sys
+import unittest
+from PyQt4 import QtGui
+from PyQt4.QtTest import QTest
+from PyQt4.QtCore import Qt
+from mock import MagicMock
+
+# set up import paths
+import sas.qtgui.path_prepare
+
+from sas.qtgui.Calculators.SlitSizeCalculator import SlitSizeCalculator
+from sas.sascalc.dataloader.loader import Loader
+
+app = QtGui.QApplication(sys.argv)
+
+
+class SlitSizeCalculatorTest(unittest.TestCase):
+    """Test the SlitSizeCalculator"""
+    def setUp(self):
+        """Create the SlitSizeCalculator"""
+        self.widget = SlitSizeCalculator(None)
+
+    def tearDown(self):
+        """Destroy the SlitSizeCalculator"""
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        """Test the GUI in its default state"""
+        self.assertIsInstance(self.widget, QtGui.QWidget)
+        self.assertEqual(self.widget.windowTitle(), "Slit Size Calculator")
+        self.assertEqual(self.widget.sizePolicy().Policy(), QtGui.QSizePolicy.Fixed)
+
+    def testHelp(self):
+        """ Assure help file is shown """
+
+        # this should not rise
+        self.widget.onHelp()
+
+    def testBrowseButton(self):
+        browseButton = self.widget.browseButton
+
+        filename = "beam_profile.DAT"
+
+        # Return no files.
+        QtGui.QFileDialog.getOpenFileName = MagicMock(return_value=None)
+
+        # Click on the Browse button
+        QTest.mouseClick(browseButton, Qt.LeftButton)
+
+        # Test the getOpenFileName() dialog called once
+        self.assertTrue(QtGui.QFileDialog.getOpenFileName.called)
+        QtGui.QFileDialog.getOpenFileName.assert_called_once()
+
+        # Now, return a single file
+        QtGui.QFileDialog.getOpenFileName = MagicMock(return_value=filename)
+
+        # Click on the Load button
+        QTest.mouseClick(browseButton, Qt.LeftButton)
+        QtGui.qApp.processEvents()
+
+        # Test the getOpenFileName() dialog called once
+        self.assertTrue(QtGui.QFileDialog.getOpenFileName.called)
+        QtGui.QFileDialog.getOpenFileName.assert_called_once()
+
+
+    def testCalculateSlitSize(self):
+        """ Test slit size calculated value """
+
+        filename = "beam_profile.DAT"
+        loader = Loader()
+        data = loader.load(filename)
+
+        self.widget.calculateSlitSize(data)
+        # The value "5.5858" was obtained by manual calculation.
+        # It turns out our slit length is FWHM/2
+        self.assertAlmostEqual(float(self.widget.slit_length_out.text()), 5.5858/2, 3)
+
+    def testWrongInput(self):
+        """ Test on wrong input data """
+
+        filename = "Dec07031.ASC"
+        loader = Loader()
+        data = loader.load(filename)
+        self.assertRaisesRegexp(RuntimeError,
+                                "Slit Length cannot be computed for 2D Data",
+                                self.widget.calculateSlitSize, data)
+
+        filename = "empty_file.txt"
+        loader = Loader()
+        data = loader.load(filename)
+        self.assertRaisesRegexp(RuntimeError,
+                                "ERROR: Data hasn't been loaded correctly",
+                                self.widget.calculateSlitSize, data)
+
+        data = None
+        self.assertRaisesRegexp(RuntimeError,
+                                "ERROR: Data hasn't been loaded correctly",
+                                self.widget.calculateSlitSize, data)
+
+
+if __name__ == "__main__":
+    unittest.main()
Index: c/sas/qtgui/ColorMap.py
===================================================================
--- src/sas/qtgui/ColorMap.py	(revision 965fbd854b36d33e3c78f5ffed0a6040af2ad43e)
+++ 	(revision )
@@ -1,267 +1,0 @@
-"""
-Allows users to change the range of the current graph
-"""
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-import path_prepare
-
-import matplotlib as mpl
-from matplotlib import pylab
-import numpy
-
-from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
-from sas.sasgui.guiframe.dataFitting import Data2D
-from sas.qtgui.GuiUtils import formatNumber
-from rangeSlider import RangeSlider
-
-DEFAULT_MAP = 'jet'
-
-# Local UI
-from sas.qtgui.UI.ColorMapUI import Ui_ColorMapUI
-
-class ColorMap(QtGui.QDialog, Ui_ColorMapUI):
-    apply_signal = QtCore.pyqtSignal(tuple, str)
-    def __init__(self, parent=None, cmap=None, vmin=0.0, vmax=100.0, data=None):
-        super(ColorMap, self).__init__()
-
-        self.setupUi(self)
-        assert(isinstance(data, Data2D))
-
-        self.data = data
-        self._cmap_orig = self._cmap = cmap if cmap is not None else DEFAULT_MAP
-        self.all_maps = [m for m in pylab.cm.datad]
-        self.maps = sorted(m for m in self.all_maps if not m.endswith("_r"))
-        self.rmaps = sorted(set(self.all_maps) - set(self.maps))
-
-        self.vmin = self.vmin_orig = vmin
-        self.vmax = self.vmax_orig = vmax
-
-        # Initialize detector labels
-        self.initDetectorData()
-
-        # Initialize the combo box
-        self.initMapCombobox()
-
-        self.initRangeSlider()
-
-        # Add the color map component
-        self.initColorMap()
-
-        # Initialize validators on amplitude textboxes
-        validator_min = QtGui.QDoubleValidator(self.txtMinAmplitude)
-        validator_min.setNotation(0)
-        self.txtMinAmplitude.setValidator(validator_min)
-        validator_max = QtGui.QDoubleValidator(self.txtMaxAmplitude)
-        validator_max.setNotation(0)
-        self.txtMaxAmplitude.setValidator(validator_max)
-
-        # Set the initial amplitudes
-        self.txtMinAmplitude.setText(formatNumber(self.vmin))
-        self.txtMaxAmplitude.setText(formatNumber(self.vmax))
-
-        # Enforce constant size on the widget
-        self.setFixedSize(self.minimumSizeHint())
-
-        # Handle combobox changes
-        self.cbColorMap.currentIndexChanged.connect(self.onMapIndexChange)
-
-        # Handle checkbox changes
-        self.chkReverse.stateChanged.connect(self.onColorMapReversed)
-
-        # Handle the Reset button click
-        self.buttonBox.button(QtGui.QDialogButtonBox.Reset).clicked.connect(self.onReset)
-
-        # Handle the Apply button click
-        self.buttonBox.button(QtGui.QDialogButtonBox.Apply).clicked.connect(self.onApply)
-
-        # Handle the amplitude setup
-        self.txtMinAmplitude.editingFinished.connect(self.onAmplitudeChange)
-        self.txtMaxAmplitude.editingFinished.connect(self.onAmplitudeChange)
-
-    def cmap(self):
-        """
-        Getter for the color map
-        """
-        return self._cmap
-
-    def norm(self):
-        """
-        Getter for the color map norm
-        """
-        return (self._norm.vmin, self._norm.vmax)
-
-    def onReset(self):
-        """
-        Respond to the Reset button click
-        """
-        # Go back to original settings
-        self._cmap = self._cmap_orig
-        self.vmin = self.vmin_orig
-        self.vmax = self.vmax_orig
-        self._norm = mpl.colors.Normalize(vmin=self.vmin, vmax=self.vmax)
-        self.txtMinAmplitude.setText(formatNumber(self.vmin))
-        self.txtMaxAmplitude.setText(formatNumber(self.vmax))
-        self.initMapCombobox()
-        self.slider.setMinimum(self.vmin)
-        self.slider.setMaximum(self.vmax)
-        self.slider.setLowValue(self.vmin)
-        self.slider.setHighValue(self.vmax)
-        # Redraw the widget
-        self.redrawColorBar()
-        self.canvas.draw()
-
-    def onApply(self):
-        """
-        Respond to the Apply button click.
-        Send a signal to the plotter with vmin/vmax/cmap for chart update
-        """
-        self.apply_signal.emit(self.norm(), self.cmap())
-
-    def initDetectorData(self):
-        """
-        Fill out the Detector labels
-        """
-        xnpts = len(self.data.x_bins)
-        ynpts = len(self.data.y_bins)
-        self.lblWidth.setText(formatNumber(xnpts))
-        self.lblHeight.setText(formatNumber(ynpts))
-        xmax = max(self.data.xmin, self.data.xmax)
-        ymax = max(self.data.ymin, self.data.ymax)
-        qmax = numpy.sqrt(numpy.power(xmax, 2) + numpy.power(ymax, 2))
-        self.lblQmax.setText(formatNumber(qmax))
-        self.lblStopRadius.setText(formatNumber(self.data.xmin))
-
-    def initMapCombobox(self):
-        """
-        Fill out the combo box with all available color maps
-        """
-        if self._cmap in self.rmaps:
-            maps = self.rmaps
-            # Assure correct state of the checkbox
-            self.chkReverse.setChecked(True)
-        else:
-            maps = self.maps
-            # Assure correct state of the checkbox
-            self.chkReverse.setChecked(False)
-
-        self.cbColorMap.addItems(maps)
-        # Set the default/passed map
-        self.cbColorMap.setCurrentIndex(self.cbColorMap.findText(self._cmap))
-
-    def initRangeSlider(self):
-        """
-        Create and display the double slider for data range mapping.
-        """
-        self.slider = RangeSlider()
-        self.slider.setMinimum(self.vmin)
-        self.slider.setMaximum(self.vmax)
-        self.slider.setLowValue(self.vmin)
-        self.slider.setHighValue(self.vmax)
-        self.slider.setOrientation(QtCore.Qt.Horizontal)
-
-        self.slider_label = QtGui.QLabel()
-        self.slider_label.setText("Drag the sliders to adjust color range.")
-
-        def set_vmin(value):
-            self.vmin = value
-            self.txtMinAmplitude.setText(str(value))
-            self.updateMap()
-        def set_vmax(value):
-            self.vmax = value
-            self.txtMaxAmplitude.setText(str(value))
-            self.updateMap()
-
-        self.slider.lowValueChanged.connect(set_vmin)
-        self.slider.highValueChanged.connect(set_vmin)
-
-    def updateMap(self):
-        self._norm = mpl.colors.Normalize(vmin=self.vmin, vmax=self.vmax)
-        self.redrawColorBar()
-        self.canvas.draw()
-
-    def initColorMap(self):
-        """
-        Prepare and display the color map
-        """
-        self.fig = mpl.figure.Figure(figsize=(4, 1))
-        self.ax1 = self.fig.add_axes([0.05, 0.65, 0.9, 0.15])
-
-        self._norm = mpl.colors.Normalize(vmin=self.vmin, vmax=self.vmax)
-        self.redrawColorBar()
-        self.canvas = FigureCanvas(self.fig)
-
-        layout = QtGui.QVBoxLayout()
-        layout.addWidget(self.slider_label)
-        layout.addWidget(self.slider)
-        layout.addWidget(self.canvas)
-
-        self.widget.setLayout(layout)
-
-    def onMapIndexChange(self, index):
-        """
-        Respond to the color map change event
-        """
-        new_map = str(self.cbColorMap.itemText(index))
-        self._cmap = new_map
-        self.redrawColorBar()
-        self.canvas.draw()
-
-    def redrawColorBar(self):
-        """
-        Call ColorbarBase with current values, effectively redrawing the widget
-        """
-        self.cb = mpl.colorbar.ColorbarBase(self.ax1, cmap=self._cmap,
-                                            norm=self._norm,
-                                            orientation='horizontal')
-        self.cb.set_label('Color map range')
-
-    def onColorMapReversed(self, isChecked):
-        """
-        Respond to ticking/unticking the color map reverse checkbox
-        """
-        current_map = str(self.cbColorMap.currentText())
-        if isChecked:
-            # Add "_r" to map name for the reversed version
-            new_map = current_map + "_r"
-            maps = self.rmaps
-            # Assure the reversed map exists.
-            if new_map not in maps:
-                new_map = maps[0]
-        else:
-            new_map = current_map[:-2] # "_r" = last two chars
-            maps = self.maps
-            # Base map for the reversed map should ALWAYS exist,
-            # but let's be paranoid here
-            if new_map not in maps:
-                new_map = maps[0]
-
-        self._cmap = new_map
-        # Clear the content of the combobox.
-        # Needs signal blocking, or else onMapIndexChange() spoils it all
-        self.cbColorMap.blockSignals(True)
-        self.cbColorMap.clear()
-        # Add the new set of maps
-        self.cbColorMap.addItems(maps)
-        # Remove the signal block before the proper index set
-        self.cbColorMap.blockSignals(False)
-        self.cbColorMap.setCurrentIndex(self.cbColorMap.findText(new_map))
-
-    def onAmplitudeChange(self):
-        """
-        Respond to editing the amplitude fields
-        """
-        min_amp = self.vmin
-        max_amp = self.vmax
-
-        try:
-            min_amp = float(self.txtMinAmplitude.text())
-        except ValueError:
-            pass
-        try:
-            max_amp = float(self.txtMaxAmplitude.text())
-        except ValueError:
-            pass
-
-        self._norm = mpl.colors.Normalize(vmin=min_amp, vmax=max_amp)
-        self.redrawColorBar()
-        self.canvas.draw()
Index: c/sas/qtgui/DataExplorer.py
===================================================================
--- src/sas/qtgui/DataExplorer.py	(revision 1970780bb41fa72bf4fc9e750008667278c2f7b8)
+++ 	(revision )
@@ -1,1011 +1,0 @@
-# global
-import sys
-import os
-import time
-import logging
-
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-from PyQt4 import QtWebKit
-from PyQt4.Qt import QMutex
-
-from twisted.internet import threads
-
-# SAS
-from sas.sascalc.dataloader.loader import Loader
-from sas.sasgui.guiframe.data_manager import DataManager
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.dataFitting import Data2D
-
-import sas.qtgui.GuiUtils as GuiUtils
-import sas.qtgui.PlotHelper as PlotHelper
-from sas.qtgui.Plotter import Plotter
-from sas.qtgui.Plotter2D import Plotter2D
-from sas.qtgui.DroppableDataLoadWidget import DroppableDataLoadWidget
-from sas.qtgui.MaskEditor import MaskEditor
-
-import Perspectives
-
-class DataExplorerWindow(DroppableDataLoadWidget):
-    # The controller which is responsible for managing signal slots connections
-    # for the gui and providing an interface to the data model.
-
-    def __init__(self, parent=None, guimanager=None, manager=None):
-        super(DataExplorerWindow, self).__init__(parent, guimanager)
-
-        # Main model for keeping loaded data
-        self.model = QtGui.QStandardItemModel(self)
-
-        # Secondary model for keeping frozen data sets
-        self.theory_model = QtGui.QStandardItemModel(self)
-
-        # GuiManager is the actual parent, but we needed to also pass the QMainWindow
-        # in order to set the widget parentage properly.
-        self.parent = guimanager
-        self.loader = Loader()
-        self.manager = manager if manager is not None else DataManager()
-        self.txt_widget = QtGui.QTextEdit(None)
-
-        # Be careful with twisted threads.
-        self.mutex = QMutex()
-
-        # Active plots
-        self.active_plots = {}
-
-        # Connect the buttons
-        self.cmdLoad.clicked.connect(self.loadFile)
-        self.cmdDeleteData.clicked.connect(self.deleteFile)
-        self.cmdDeleteTheory.clicked.connect(self.deleteTheory)
-        self.cmdFreeze.clicked.connect(self.freezeTheory)
-        self.cmdSendTo.clicked.connect(self.sendData)
-        self.cmdNew.clicked.connect(self.newPlot)
-        self.cmdNew_2.clicked.connect(self.newPlot)
-        self.cmdAppend.clicked.connect(self.appendPlot)
-        self.cmdHelp.clicked.connect(self.displayHelp)
-        self.cmdHelp_2.clicked.connect(self.displayHelp)
-
-        # Display HTML content
-        self._helpView = QtWebKit.QWebView()
-
-        # Fill in the perspectives combo
-        self.initPerspectives()
-
-        # Custom context menu
-        self.treeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
-        self.treeView.customContextMenuRequested.connect(self.onCustomContextMenu)
-        self.contextMenu()
-
-        # Same menus for the theory view
-        self.freezeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
-        self.freezeView.customContextMenuRequested.connect(self.onCustomContextMenu)
-
-        # Connect the comboboxes
-        self.cbSelect.currentIndexChanged.connect(self.selectData)
-
-        #self.closeEvent.connect(self.closeEvent)
-        self.currentChanged.connect(self.onTabSwitch)
-        self.communicator = self.parent.communicator()
-        self.communicator.fileReadSignal.connect(self.loadFromURL)
-        self.communicator.activeGraphsSignal.connect(self.updateGraphCombo)
-        self.communicator.activeGraphName.connect(self.updatePlotName)
-        self.communicator.plotUpdateSignal.connect(self.updatePlot)
-        self.cbgraph.editTextChanged.connect(self.enableGraphCombo)
-        self.cbgraph.currentIndexChanged.connect(self.enableGraphCombo)
-
-        # Proxy model for showing a subset of Data1D/Data2D content
-        self.data_proxy = QtGui.QSortFilterProxyModel(self)
-        self.data_proxy.setSourceModel(self.model)
-
-        # Don't show "empty" rows with data objects
-        self.data_proxy.setFilterRegExp(r"[^()]")
-
-        # The Data viewer is QTreeView showing the proxy model
-        self.treeView.setModel(self.data_proxy)
-
-        # Proxy model for showing a subset of Theory content
-        self.theory_proxy = QtGui.QSortFilterProxyModel(self)
-        self.theory_proxy.setSourceModel(self.theory_model)
-
-        # Don't show "empty" rows with data objects
-        self.theory_proxy.setFilterRegExp(r"[^()]")
-
-        # Theory model view
-        self.freezeView.setModel(self.theory_proxy)
-
-        self.enableGraphCombo(None)
-
-        # Current view on model
-        self.current_view = self.treeView
-
-    def closeEvent(self, event):
-        """
-        Overwrite the close event - no close!
-        """
-        event.ignore()
-
-    def onTabSwitch(self, index):
-        """ Callback for tab switching signal """
-        if index == 0:
-            self.current_view = self.treeView
-        else:
-            self.current_view = self.freezeView
-
-    def displayHelp(self):
-        """
-        Show the "Loading data" section of help
-        """
-        tree_location = self.parent.HELP_DIRECTORY_LOCATION +\
-            "/user/sasgui/guiframe/data_explorer_help.html"
-        self._helpView.load(QtCore.QUrl(tree_location))
-        self._helpView.show()
-
-    def enableGraphCombo(self, combo_text):
-        """
-        Enables/disables "Assign Plot" elements
-        """
-        self.cbgraph.setEnabled(len(PlotHelper.currentPlots()) > 0)
-        self.cmdAppend.setEnabled(len(PlotHelper.currentPlots()) > 0)
-
-    def initPerspectives(self):
-        """
-        Populate the Perspective combobox and define callbacks
-        """
-        available_perspectives = sorted([p for p in Perspectives.PERSPECTIVES.keys()])
-        if available_perspectives:
-            self.cbFitting.clear()
-            self.cbFitting.addItems(available_perspectives)
-        self.cbFitting.currentIndexChanged.connect(self.updatePerspectiveCombo)
-        # Set the index so we see the default (Fitting)
-        self.updatePerspectiveCombo(0)
-
-    def _perspective(self):
-        """
-        Returns the current perspective
-        """
-        return self.parent.perspective()
-
-    def loadFromURL(self, url):
-        """
-        Threaded file load
-        """
-        load_thread = threads.deferToThread(self.readData, url)
-        load_thread.addCallback(self.loadComplete)
-
-    def loadFile(self, event=None):
-        """
-        Called when the "Load" button pressed.
-        Opens the Qt "Open File..." dialog
-        """
-        path_str = self.chooseFiles()
-        if not path_str:
-            return
-        self.loadFromURL(path_str)
-
-    def loadFolder(self, event=None):
-        """
-        Called when the "File/Load Folder" menu item chosen.
-        Opens the Qt "Open Folder..." dialog
-        """
-        folder = QtGui.QFileDialog.getExistingDirectory(self, "Choose a directory", "",
-              QtGui.QFileDialog.ShowDirsOnly | QtGui.QFileDialog.DontUseNativeDialog)
-        if folder is None:
-            return
-
-        folder = str(folder)
-
-        if not os.path.isdir(folder):
-            return
-
-        # get content of dir into a list
-        path_str = [os.path.join(os.path.abspath(folder), filename)
-                    for filename in os.listdir(folder)]
-
-        self.loadFromURL(path_str)
-
-    def loadProject(self):
-        """
-        Called when the "Open Project" menu item chosen.
-        """
-        kwargs = {
-            'parent'    : self,
-            'caption'   : 'Open Project',
-            'filter'    : 'Project (*.json);;All files (*.*)',
-            'options'   : QtGui.QFileDialog.DontUseNativeDialog
-        }
-        filename = str(QtGui.QFileDialog.getOpenFileName(**kwargs))
-        if filename:
-            load_thread = threads.deferToThread(self.readProject, filename)
-            load_thread.addCallback(self.readProjectComplete)
-
-    def readProject(self, filename):
-        self.communicator.statusBarUpdateSignal.emit("Loading Project... %s" % os.path.basename(filename))
-        try:
-            manager = DataManager()
-            with open(filename, 'r') as infile:
-                manager.load_from_readable(infile)
-
-            self.communicator.statusBarUpdateSignal.emit("Loaded Project: %s" % os.path.basename(filename))
-            return manager
-
-        except:
-            self.communicator.statusBarUpdateSignal.emit("Failed: %s" % os.path.basename(filename))
-            raise
-
-    def readProjectComplete(self, manager):
-        self.model.clear()
-
-        self.manager.assign(manager)
-        for id, item in self.manager.get_all_data().iteritems():
-            self.updateModel(item.data, item.path)
-
-        self.model.reset()
-
-    def saveProject(self):
-        """
-        Called when the "Save Project" menu item chosen.
-        """
-        kwargs = {
-            'parent'    : self,
-            'caption'   : 'Save Project',
-            'filter'    : 'Project (*.json)',
-            'options'   : QtGui.QFileDialog.DontUseNativeDialog
-        }
-        filename = str(QtGui.QFileDialog.getSaveFileName(**kwargs))
-        if filename:
-            self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename))
-            with open(filename, 'w') as outfile:
-                self.manager.save_to_writable(outfile)
-
-    def deleteFile(self, event):
-        """
-        Delete selected rows from the model
-        """
-        # Assure this is indeed wanted
-        delete_msg = "This operation will delete the checked data sets and all the dependents." +\
-                     "\nDo you want to continue?"
-        reply = QtGui.QMessageBox.question(self,
-                                           'Warning',
-                                           delete_msg,
-                                           QtGui.QMessageBox.Yes,
-                                           QtGui.QMessageBox.No)
-
-        if reply == QtGui.QMessageBox.No:
-            return
-
-        # Figure out which rows are checked
-        ind = -1
-        # Use 'while' so the row count is forced at every iteration
-        while ind < self.model.rowCount():
-            ind += 1
-            item = self.model.item(ind)
-            if item and item.isCheckable() and item.checkState() == QtCore.Qt.Checked:
-                # Delete these rows from the model
-                self.model.removeRow(ind)
-                # Decrement index since we just deleted it
-                ind -= 1
-
-        # pass temporarily kept as a breakpoint anchor
-        pass
-
-    def deleteTheory(self, event):
-        """
-        Delete selected rows from the theory model
-        """
-        # Assure this is indeed wanted
-        delete_msg = "This operation will delete the checked data sets and all the dependents." +\
-                     "\nDo you want to continue?"
-        reply = QtGui.QMessageBox.question(self,
-                                           'Warning',
-                                           delete_msg,
-                                           QtGui.QMessageBox.Yes,
-                                           QtGui.QMessageBox.No)
-
-        if reply == QtGui.QMessageBox.No:
-            return
-
-        # Figure out which rows are checked
-        ind = -1
-        # Use 'while' so the row count is forced at every iteration
-        while ind < self.theory_model.rowCount():
-            ind += 1
-            item = self.theory_model.item(ind)
-            if item and item.isCheckable() and item.checkState() == QtCore.Qt.Checked:
-                # Delete these rows from the model
-                self.theory_model.removeRow(ind)
-                # Decrement index since we just deleted it
-                ind -= 1
-
-        # pass temporarily kept as a breakpoint anchor
-        pass
-
-    def sendData(self, event):
-        """
-        Send selected item data to the current perspective and set the relevant notifiers
-        """
-        # Set the signal handlers
-        self.communicator.updateModelFromPerspectiveSignal.connect(self.updateModelFromPerspective)
-
-        def isItemReady(index):
-            item = self.model.item(index)
-            return item.isCheckable() and item.checkState() == QtCore.Qt.Checked
-
-        # Figure out which rows are checked
-        selected_items = [self.model.item(index)
-                          for index in xrange(self.model.rowCount())
-                          if isItemReady(index)]
-
-        if len(selected_items) < 1:
-            return
-
-        # Which perspective has been selected?
-        if len(selected_items) > 1 and not self._perspective().allowBatch():
-            msg = self._perspective().title() + " does not allow multiple data."
-            msgbox = QtGui.QMessageBox()
-            msgbox.setIcon(QtGui.QMessageBox.Critical)
-            msgbox.setText(msg)
-            msgbox.setStandardButtons(QtGui.QMessageBox.Ok)
-            retval = msgbox.exec_()
-            return
-
-        # Notify the GuiManager about the send request
-        self._perspective().setData(data_item=selected_items)
-
-    def freezeTheory(self, event):
-        """
-        Freeze selected theory rows.
-
-        "Freezing" means taking the plottable data from the Theory item
-        and copying it to a separate top-level item in Data.
-        """
-        # Figure out which rows are checked
-        # Use 'while' so the row count is forced at every iteration
-        outer_index = -1
-        theories_copied = 0
-        while outer_index < self.theory_model.rowCount():
-            outer_index += 1
-            outer_item = self.theory_model.item(outer_index)
-            if not outer_item:
-                continue
-            if outer_item.isCheckable() and \
-                   outer_item.checkState() == QtCore.Qt.Checked:
-                theories_copied += 1
-                new_item = self.recursivelyCloneItem(outer_item)
-                # Append a "unique" descriptor to the name
-                time_bit = str(time.time())[7:-1].replace('.', '')
-                new_name = new_item.text() + '_@' + time_bit
-                new_item.setText(new_name)
-                self.model.appendRow(new_item)
-            self.model.reset()
-
-        freeze_msg = ""
-        if theories_copied == 0:
-            return
-        elif theories_copied == 1:
-            freeze_msg = "1 theory copied from the Theory tab as a data set"
-        elif theories_copied > 1:
-            freeze_msg = "%i theories copied from the Theory tab as data sets" % theories_copied
-        else:
-            freeze_msg = "Unexpected number of theories copied: %i" % theories_copied
-            raise AttributeError, freeze_msg
-        self.communicator.statusBarUpdateSignal.emit(freeze_msg)
-        # Actively switch tabs
-        self.setCurrentIndex(1)
-
-    def recursivelyCloneItem(self, item):
-        """
-        Clone QStandardItem() object
-        """
-        new_item = item.clone()
-        # clone doesn't do deepcopy :(
-        for child_index in xrange(item.rowCount()):
-            child_item = self.recursivelyCloneItem(item.child(child_index))
-            new_item.setChild(child_index, child_item)
-        return new_item
-
-    def updatePlotName(self, name_tuple):
-        """
-        Modify the name of the current plot
-        """
-        old_name, current_name = name_tuple
-        ind = self.cbgraph.findText(old_name)
-        self.cbgraph.setCurrentIndex(ind)
-        self.cbgraph.setItemText(ind, current_name)
-
-    def updateGraphCombo(self, graph_list):
-        """
-        Modify Graph combo box on graph add/delete
-        """
-        orig_text = self.cbgraph.currentText()
-        self.cbgraph.clear()
-        #graph_titles= [str(graph) for graph in graph_list]
-
-        #self.cbgraph.insertItems(0, graph_titles)
-        self.cbgraph.insertItems(0, graph_list)
-        ind = self.cbgraph.findText(orig_text)
-        if ind > 0:
-            self.cbgraph.setCurrentIndex(ind)
-
-    def updatePerspectiveCombo(self, index):
-        """
-        Notify the gui manager about the new perspective chosen.
-        """
-        self.communicator.perspectiveChangedSignal.emit(self.cbFitting.currentText())
-        self.chkBatch.setEnabled(self.parent.perspective().allowBatch())
-
-    def newPlot(self):
-        """
-        Create a new matplotlib chart from selected data
-        """
-        # Check which tab is currently active
-        if self.current_view == self.treeView:
-            plots = GuiUtils.plotsFromCheckedItems(self.model)
-        else:
-            plots = GuiUtils.plotsFromCheckedItems(self.theory_model)
-
-        # Call show on requested plots
-        # All same-type charts in one plot
-        new_plot = Plotter(self)
-
-        def addDataPlot2D(plot_set, item):
-            plot2D = Plotter2D(self)
-            plot2D.item = item
-            plot2D.plot(plot_set)
-            self.plotAdd(plot2D)
-            #============================================
-            ## Attach silx
-            #from silx.gui import qt
-            #from silx.gui.plot import StackView
-            #sv = StackView()
-            #sv.setColormap("jet", autoscale=True)
-            #sv.setStack(plot_set.data.reshape(1,100,100))
-            ##sv.setLabels(["x: -10 to 10 (200 samples)",
-            ##              "y: -10 to 5 (150 samples)"])
-            #sv.show()
-            #============================================
-
-        for item, plot_set in plots:
-            if isinstance(plot_set, Data1D):
-                new_plot.plot(plot_set)
-            elif isinstance(plot_set, Data2D):
-                addDataPlot2D(plot_set, item)
-            else:
-                msg = "Incorrect data type passed to Plotting"
-                raise AttributeError, msg
-
-        if plots and \
-            hasattr(new_plot, 'data') and \
-            isinstance(new_plot.data, Data1D):
-                self.plotAdd(new_plot)
-
-    def plotAdd(self, new_plot):
-        """
-        Helper method for plot bookkeeping
-        """
-        # Update the global plot counter
-        title = str(PlotHelper.idOfPlot(new_plot))
-        new_plot.setWindowTitle(title)
-
-        # Add the plot to the workspace
-        self.parent.workspace().addWindow(new_plot)
-
-        # Show the plot
-        new_plot.show()
-
-        # Update the active chart list
-        self.active_plots[new_plot.data.id] = new_plot
-
-    def appendPlot(self):
-        """
-        Add data set(s) to the existing matplotlib chart
-        """
-        # new plot data
-        new_plots = GuiUtils.plotsFromCheckedItems(self.model)
-
-        # old plot data
-        plot_id = str(self.cbgraph.currentText())
-
-        assert plot_id in PlotHelper.currentPlots(), "No such plot: %s"%(plot_id)
-
-        old_plot = PlotHelper.plotById(plot_id)
-
-        # Add new data to the old plot, if data type is the same.
-        for _, plot_set in new_plots:
-            if type(plot_set) is type(old_plot._data):
-                old_plot.data = plot_set
-                old_plot.plot()
-
-    def updatePlot(self, new_data):
-        """
-        Modify existing plot for immediate response
-        """
-        data = new_data[0]
-        assert type(data).__name__ in ['Data1D', 'Data2D']
-
-        id = data.id
-        if data.id in self.active_plots.keys():
-            self.active_plots[id].replacePlot(id, data)
-
-    def chooseFiles(self):
-        """
-        Shows the Open file dialog and returns the chosen path(s)
-        """
-        # List of known extensions
-        wlist = self.getWlist()
-
-        # Location is automatically saved - no need to keep track of the last dir
-        # But only with Qt built-in dialog (non-platform native)
-        paths = QtGui.QFileDialog.getOpenFileNames(self, "Choose a file", "",
-                wlist, None, QtGui.QFileDialog.DontUseNativeDialog)
-        if paths is None:
-            return
-
-        if isinstance(paths, QtCore.QStringList):
-            paths = [str(f) for f in paths]
-
-        if not isinstance(paths, list):
-            paths = [paths]
-
-        return paths
-
-    def readData(self, path):
-        """
-        verbatim copy-paste from
-           sasgui.guiframe.local_perspectives.data_loader.data_loader.py
-        slightly modified for clarity
-        """
-        message = ""
-        log_msg = ''
-        output = {}
-        any_error = False
-        data_error = False
-        error_message = ""
-        number_of_files = len(path)
-        self.communicator.progressBarUpdateSignal.emit(0.0)
-
-        for index, p_file in enumerate(path):
-            basename = os.path.basename(p_file)
-            _, extension = os.path.splitext(basename)
-            if extension.lower() in GuiUtils.EXTENSIONS:
-                any_error = True
-                log_msg = "Data Loader cannot "
-                log_msg += "load: %s\n" % str(p_file)
-                log_msg += """Please try to open that file from "open project" """
-                log_msg += """or "open analysis" menu\n"""
-                error_message = log_msg + "\n"
-                logging.info(log_msg)
-                continue
-
-            try:
-                message = "Loading Data... " + str(basename) + "\n"
-
-                # change this to signal notification in GuiManager
-                self.communicator.statusBarUpdateSignal.emit(message)
-
-                output_objects = self.loader.load(p_file)
-
-                # Some loaders return a list and some just a single Data1D object.
-                # Standardize.
-                if not isinstance(output_objects, list):
-                    output_objects = [output_objects]
-
-                for item in output_objects:
-                    # cast sascalc.dataloader.data_info.Data1D into
-                    # sasgui.guiframe.dataFitting.Data1D
-                    # TODO : Fix it
-                    new_data = self.manager.create_gui_data(item, p_file)
-                    output[new_data.id] = new_data
-
-                    # Model update should be protected
-                    self.mutex.lock()
-                    self.updateModel(new_data, p_file)
-                    self.model.reset()
-                    QtGui.qApp.processEvents()
-                    self.mutex.unlock()
-
-                    if hasattr(item, 'errors'):
-                        for error_data in item.errors:
-                            data_error = True
-                            message += "\tError: {0}\n".format(error_data)
-                    else:
-
-                        logging.error("Loader returned an invalid object:\n %s" % str(item))
-                        data_error = True
-
-            except Exception as ex:
-                logging.error(sys.exc_value)
-
-                any_error = True
-            if any_error or error_message != "":
-                if error_message == "":
-                    error = "Error: " + str(sys.exc_info()[1]) + "\n"
-                    error += "while loading Data: \n%s\n" % str(basename)
-                    error_message += "The data file you selected could not be loaded.\n"
-                    error_message += "Make sure the content of your file"
-                    error_message += " is properly formatted.\n\n"
-                    error_message += "When contacting the SasView team, mention the"
-                    error_message += " following:\n%s" % str(error)
-                elif data_error:
-                    base_message = "Errors occurred while loading "
-                    base_message += "{0}\n".format(basename)
-                    base_message += "The data file loaded but with errors.\n"
-                    error_message = base_message + error_message
-                else:
-                    error_message += "%s\n" % str(p_file)
-
-            current_percentage = int(100.0* index/number_of_files)
-            self.communicator.progressBarUpdateSignal.emit(current_percentage)
-
-        if any_error or error_message:
-            logging.error(error_message)
-            status_bar_message = "Errors occurred while loading %s" % format(basename)
-            self.communicator.statusBarUpdateSignal.emit(status_bar_message)
-
-        else:
-            message = "Loading Data Complete! "
-        message += log_msg
-        # Notify the progress bar that the updates are over.
-        self.communicator.progressBarUpdateSignal.emit(-1)
-        self.communicator.statusBarUpdateSignal.emit(message)
-
-        return output, message
-
-    def getWlist(self):
-        """
-        Wildcards of files we know the format of.
-        """
-        # Display the Qt Load File module
-        cards = self.loader.get_wildcards()
-
-        # get rid of the wx remnant in wildcards
-        # TODO: modify sasview loader get_wildcards method, after merge,
-        # so this kludge can be avoided
-        new_cards = []
-        for item in cards:
-            new_cards.append(item[:item.find("|")])
-        wlist = ';;'.join(new_cards)
-
-        return wlist
-
-    def selectData(self, index):
-        """
-        Callback method for modifying the TreeView on Selection Options change
-        """
-        if not isinstance(index, int):
-            msg = "Incorrect type passed to DataExplorer.selectData()"
-            raise AttributeError, msg
-
-        # Respond appropriately
-        if index == 0:
-            # Select All
-            for index in range(self.model.rowCount()):
-                item = self.model.item(index)
-                if item.isCheckable() and item.checkState() == QtCore.Qt.Unchecked:
-                    item.setCheckState(QtCore.Qt.Checked)
-        elif index == 1:
-            # De-select All
-            for index in range(self.model.rowCount()):
-                item = self.model.item(index)
-                if item.isCheckable() and item.checkState() == QtCore.Qt.Checked:
-                    item.setCheckState(QtCore.Qt.Unchecked)
-
-        elif index == 2:
-            # Select All 1-D
-            for index in range(self.model.rowCount()):
-                item = self.model.item(index)
-                item.setCheckState(QtCore.Qt.Unchecked)
-
-                try:
-                    is1D = isinstance(GuiUtils.dataFromItem(item), Data1D)
-                except AttributeError:
-                    msg = "Bad structure of the data model."
-                    raise RuntimeError, msg
-
-                if is1D:
-                    item.setCheckState(QtCore.Qt.Checked)
-
-        elif index == 3:
-            # Unselect All 1-D
-            for index in range(self.model.rowCount()):
-                item = self.model.item(index)
-
-                try:
-                    is1D = isinstance(GuiUtils.dataFromItem(item), Data1D)
-                except AttributeError:
-                    msg = "Bad structure of the data model."
-                    raise RuntimeError, msg
-
-                if item.isCheckable() and item.checkState() == QtCore.Qt.Checked and is1D:
-                    item.setCheckState(QtCore.Qt.Unchecked)
-
-        elif index == 4:
-            # Select All 2-D
-            for index in range(self.model.rowCount()):
-                item = self.model.item(index)
-                item.setCheckState(QtCore.Qt.Unchecked)
-                try:
-                    is2D = isinstance(GuiUtils.dataFromItem(item), Data2D)
-                except AttributeError:
-                    msg = "Bad structure of the data model."
-                    raise RuntimeError, msg
-
-                if is2D:
-                    item.setCheckState(QtCore.Qt.Checked)
-
-        elif index == 5:
-            # Unselect All 2-D
-            for index in range(self.model.rowCount()):
-                item = self.model.item(index)
-
-                try:
-                    is2D = isinstance(GuiUtils.dataFromItem(item), Data2D)
-                except AttributeError:
-                    msg = "Bad structure of the data model."
-                    raise RuntimeError, msg
-
-                if item.isCheckable() and item.checkState() == QtCore.Qt.Checked and is2D:
-                    item.setCheckState(QtCore.Qt.Unchecked)
-
-        else:
-            msg = "Incorrect value in the Selection Option"
-            # Change this to a proper logging action
-            raise Exception, msg
-
-    def contextMenu(self):
-        """
-        Define actions and layout of the right click context menu
-        """
-        # Create a custom menu based on actions defined in the UI file
-        self.context_menu = QtGui.QMenu(self)
-        self.context_menu.addAction(self.actionDataInfo)
-        self.context_menu.addAction(self.actionSaveAs)
-        self.context_menu.addAction(self.actionQuickPlot)
-        self.context_menu.addSeparator()
-        self.context_menu.addAction(self.actionQuick3DPlot)
-        self.context_menu.addAction(self.actionEditMask)
-
-        # Define the callbacks
-        self.actionDataInfo.triggered.connect(self.showDataInfo)
-        self.actionSaveAs.triggered.connect(self.saveDataAs)
-        self.actionQuickPlot.triggered.connect(self.quickDataPlot)
-        self.actionQuick3DPlot.triggered.connect(self.quickData3DPlot)
-        self.actionEditMask.triggered.connect(self.showEditDataMask)
-
-    def onCustomContextMenu(self, position):
-        """
-        Show the right-click context menu in the data treeview
-        """
-        index = self.current_view.indexAt(position)
-        proxy = self.current_view.model()
-        model = proxy.sourceModel()
-
-        if index.isValid():
-            model_item = model.itemFromIndex(proxy.mapToSource(index))
-            # Find the mapped index
-            orig_index = model_item.isCheckable()
-            if orig_index:
-                # Check the data to enable/disable actions
-                is_2D = isinstance(GuiUtils.dataFromItem(model_item), Data2D)
-                self.actionQuick3DPlot.setEnabled(is_2D)
-                self.actionEditMask.setEnabled(is_2D)
-                # Fire up the menu
-                self.context_menu.exec_(self.current_view.mapToGlobal(position))
-
-    def showDataInfo(self):
-        """
-        Show a simple read-only text edit with data information.
-        """
-        index = self.current_view.selectedIndexes()[0]
-        proxy = self.current_view.model()
-        model = proxy.sourceModel()
-        model_item = model.itemFromIndex(proxy.mapToSource(index))
-
-        data = GuiUtils.dataFromItem(model_item)
-        if isinstance(data, Data1D):
-            text_to_show = GuiUtils.retrieveData1d(data)
-            # Hardcoded sizes to enable full width rendering with default font
-            self.txt_widget.resize(420,600)
-        else:
-            text_to_show = GuiUtils.retrieveData2d(data)
-            # Hardcoded sizes to enable full width rendering with default font
-            self.txt_widget.resize(700,600)
-
-        self.txt_widget.setReadOnly(True)
-        self.txt_widget.setWindowFlags(QtCore.Qt.Window)
-        self.txt_widget.setWindowIcon(QtGui.QIcon(":/res/ball.ico"))
-        self.txt_widget.setWindowTitle("Data Info: %s" % data.filename)
-        self.txt_widget.insertPlainText(text_to_show)
-
-        self.txt_widget.show()
-        # Move the slider all the way up, if present
-        vertical_scroll_bar = self.txt_widget.verticalScrollBar()
-        vertical_scroll_bar.triggerAction(QtGui.QScrollBar.SliderToMinimum)
-
-    def saveDataAs(self):
-        """
-        Save the data points as either txt or xml
-        """
-        index = self.current_view.selectedIndexes()[0]
-        proxy = self.current_view.model()
-        model = proxy.sourceModel()
-        model_item = model.itemFromIndex(proxy.mapToSource(index))
-
-        data = GuiUtils.dataFromItem(model_item)
-        if isinstance(data, Data1D):
-            GuiUtils.saveData1D(data)
-        else:
-            GuiUtils.saveData2D(data)
-
-    def quickDataPlot(self):
-        """
-        Frozen plot - display an image of the plot
-        """
-        index = self.current_view.selectedIndexes()[0]
-        proxy = self.current_view.model()
-        model = proxy.sourceModel()
-        model_item = model.itemFromIndex(proxy.mapToSource(index))
-
-        data = GuiUtils.dataFromItem(model_item)
-
-        method_name = 'Plotter'
-        if isinstance(data, Data2D):
-            method_name='Plotter2D'
-
-        new_plot = globals()[method_name](self, quickplot=True)
-        new_plot.data = data
-        #new_plot.plot(marker='o')
-        new_plot.plot()
-
-        # Update the global plot counter
-        title = "Plot " + data.name
-        new_plot.setWindowTitle(title)
-
-        # Show the plot
-        new_plot.show()
-
-    def quickData3DPlot(self):
-        """
-        Slowish 3D plot
-        """
-        index = self.current_view.selectedIndexes()[0]
-        proxy = self.current_view.model()
-        model = proxy.sourceModel()
-        model_item = model.itemFromIndex(proxy.mapToSource(index))
-
-        data = GuiUtils.dataFromItem(model_item)
-
-        new_plot = Plotter2D(self, quickplot=True, dimension=3)
-        new_plot.data = data
-        new_plot.plot()
-
-        # Update the global plot counter
-        title = "Plot " + data.name
-        new_plot.setWindowTitle(title)
-
-        # Show the plot
-        new_plot.show()
-
-    def showEditDataMask(self):
-        """
-        Mask Editor for 2D plots
-        """
-        index = self.current_view.selectedIndexes()[0]
-        proxy = self.current_view.model()
-        model = proxy.sourceModel()
-        model_item = model.itemFromIndex(proxy.mapToSource(index))
-
-        data = GuiUtils.dataFromItem(model_item)
-
-        mask_editor = MaskEditor(self, data)
-        # Modal dialog here.
-        mask_editor.exec_()
-
-    def loadComplete(self, output):
-        """
-        Post message to status bar and update the data manager
-        """
-        assert isinstance(output, tuple)
-
-        # Reset the model so the view gets updated.
-        self.model.reset()
-        self.communicator.progressBarUpdateSignal.emit(-1)
-
-        output_data = output[0]
-        message = output[1]
-        # Notify the manager of the new data available
-        self.communicator.statusBarUpdateSignal.emit(message)
-        self.communicator.fileDataReceivedSignal.emit(output_data)
-        self.manager.add_data(data_list=output_data)
-
-    def updateModel(self, data, p_file):
-        """
-        Add data and Info fields to the model item
-        """
-        # Structure of the model
-        # checkbox + basename
-        #     |-------> Data.D object
-        #     |-------> Info
-        #                 |----> Title:
-        #                 |----> Run:
-        #                 |----> Type:
-        #                 |----> Path:
-        #                 |----> Process
-        #                          |-----> process[0].name
-        #     |-------> THEORIES
-
-        # Top-level item: checkbox with label
-        checkbox_item = QtGui.QStandardItem(True)
-        checkbox_item.setCheckable(True)
-        checkbox_item.setCheckState(QtCore.Qt.Checked)
-        checkbox_item.setText(os.path.basename(p_file))
-
-        # Add the actual Data1D/Data2D object
-        object_item = QtGui.QStandardItem()
-        object_item.setData(QtCore.QVariant(data))
-
-        checkbox_item.setChild(0, object_item)
-
-        # Add rows for display in the view
-        info_item = GuiUtils.infoFromData(data)
-
-        # Set info_item as the first child
-        checkbox_item.setChild(1, info_item)
-
-        # Caption for the theories
-        checkbox_item.setChild(2, QtGui.QStandardItem("THEORIES"))
-
-        # New row in the model
-        self.model.appendRow(checkbox_item)
-
-
-    def updateModelFromPerspective(self, model_item):
-        """
-        Receive an update model item from a perspective
-        Make sure it is valid and if so, replace it in the model
-        """
-        # Assert the correct type
-        if not isinstance(model_item, QtGui.QStandardItem):
-            msg = "Wrong data type returned from calculations."
-            raise AttributeError, msg
-
-        # TODO: Assert other properties
-
-        # Reset the view
-        self.model.reset()
-        # Pass acting as a debugger anchor
-        pass
-
-    def updateTheoryFromPerspective(self, model_item):
-        """
-        Receive an update theory item from a perspective
-        Make sure it is valid and if so, replace/add in the model
-        """
-        # Assert the correct type
-        if not isinstance(model_item, QtGui.QStandardItem):
-            msg = "Wrong data type returned from calculations."
-            raise AttributeError, msg
-
-        # Check if there are any other items for this tab
-        # If so, delete them
-        # TODO: fix this to resemble GuiUtils.updateModelItemWithPlot
-        # 
-        current_tab_name = model_item.text()[:2]
-        for current_index in xrange(self.theory_model.rowCount()):
-            if current_tab_name in self.theory_model.item(current_index).text():
-                self.theory_model.removeRow(current_index)
-                break
-
-        # Reset the view
-        self.model.reset()
-
-        # Reset the view
-        self.theory_model.appendRow(model_item)
-
-        # Pass acting as a debugger anchor
-        pass
-
-
-if __name__ == "__main__":
-    app = QtGui.QApplication([])
-    dlg = DataExplorerWindow()
-    dlg.show()
-    sys.exit(app.exec_())
Index: c/sas/qtgui/DensityPanel.py
===================================================================
--- src/sas/qtgui/DensityPanel.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,156 +1,0 @@
-# global
-import logging
-import functools
-from PyQt4 import QtGui, QtCore
-
-from periodictable import formula as Formula
-
-from sas.qtgui.GuiUtils import FormulaValidator
-
-# Local UI
-from sas.qtgui.UI.DensityPanel import Ui_DensityPanel
-
-def enum(*sequential, **named):
-    enums = dict(zip(sequential, range(len(sequential))), **named)
-    return type('Enum', (), enums)
-
-MODEL = enum(
-    'MOLECULAR_FORMULA',
-    'MOLAR_MASS',
-    'MOLAR_VOLUME',
-    'MASS_DENSITY',
-)
-
-MODES = enum(
-    'VOLUME_TO_DENSITY',
-    'DENSITY_TO_VOLUME',
-)
-
-def toMolarMass(formula):
-    AVOGADRO = 6.02214129e23
-
-    try:
-        f = Formula(str(formula))
-        return "%g" % (f.molecular_mass * AVOGADRO)
-    except:
-        return ""
-
-
-class DensityPanel(QtGui.QDialog):
-
-    def __init__(self, parent=None):
-        super(DensityPanel, self).__init__()
-
-        self.mode = None
-        self.manager = parent
-        self.setupUi()
-        self.setupModel()
-        self.setupMapper()
-
-    def setupUi(self):
-        self.ui = Ui_DensityPanel()
-        self.ui.setupUi(self)
-
-        # no reason to have this widget resizable
-        self.setFixedSize(self.minimumSizeHint())
-
-        # set validators
-        self.ui.editMolecularFormula.setValidator(FormulaValidator(self.ui.editMolecularFormula))
-
-        rx = QtCore.QRegExp("[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?")
-        self.ui.editMolarVolume.setValidator(QtGui.QRegExpValidator(rx, self.ui.editMolarVolume))
-        self.ui.editMassDensity.setValidator(QtGui.QRegExpValidator(rx, self.ui.editMassDensity))
-
-        # signals
-        self.ui.editMolarVolume.textEdited.connect(functools.partial(self.setMode, MODES.VOLUME_TO_DENSITY))
-        self.ui.editMassDensity.textEdited.connect(functools.partial(self.setMode, MODES.DENSITY_TO_VOLUME))
-
-        self.ui.buttonBox.button(QtGui.QDialogButtonBox.Reset).clicked.connect(self.modelReset)
-        self.ui.buttonBox.button(QtGui.QDialogButtonBox.Help).clicked.connect(self.displayHelp)
-
-    def setupModel(self):
-        self.model = QtGui.QStandardItemModel(self)
-        self.model.setItem(MODEL.MOLECULAR_FORMULA, QtGui.QStandardItem())
-        self.model.setItem(MODEL.MOLAR_MASS       , QtGui.QStandardItem())
-        self.model.setItem(MODEL.MOLAR_VOLUME     , QtGui.QStandardItem())
-        self.model.setItem(MODEL.MASS_DENSITY     , QtGui.QStandardItem())
-
-        self.model.dataChanged.connect(self.dataChanged)
-
-        self.modelReset()
-
-    def setupMapper(self):
-        self.mapper = QtGui.QDataWidgetMapper(self)
-        self.mapper.setModel(self.model)
-        self.mapper.setOrientation(QtCore.Qt.Vertical)
-
-        self.mapper.addMapping(self.ui.editMolecularFormula, MODEL.MOLECULAR_FORMULA)
-        self.mapper.addMapping(self.ui.editMolarMass       , MODEL.MOLAR_MASS)
-        self.mapper.addMapping(self.ui.editMolarVolume     , MODEL.MOLAR_VOLUME)
-        self.mapper.addMapping(self.ui.editMassDensity     , MODEL.MASS_DENSITY)
-
-        self.mapper.toFirst()
-
-    def dataChanged(self, top, bottom):
-        for index in xrange(top.row(), bottom.row() + 1):
-            if index == MODEL.MOLECULAR_FORMULA:
-                molarMass = toMolarMass(self.model.item(MODEL.MOLECULAR_FORMULA).text())
-                self.model.item(MODEL.MOLAR_MASS).setText(molarMass)
-
-                if self.mode == MODES.VOLUME_TO_DENSITY:
-                    self._updateDensity()
-                elif self.mode == MODES.DENSITY_TO_VOLUME:
-                    self._updateVolume()
-
-            elif index == MODEL.MOLAR_VOLUME and self.mode == MODES.VOLUME_TO_DENSITY:
-                self._updateDensity()
-
-            elif index == MODEL.MASS_DENSITY and self.mode == MODES.DENSITY_TO_VOLUME:
-                self._updateVolume()
-
-    def setMode(self, mode):
-        self.mode = mode
-
-    def _updateDensity(self):
-        try:
-            molarMass = float(toMolarMass(self.model.item(MODEL.MOLECULAR_FORMULA).text()))
-            molarVolume = float(self.model.item(MODEL.MOLAR_VOLUME).text())
-
-            molarDensity = molarMass / molarVolume
-            self.model.item(MODEL.MASS_DENSITY).setText(str(molarDensity))
-
-        except (ArithmeticError, ValueError):
-            self.model.item(MODEL.MASS_DENSITY).setText("")
-
-    def _updateVolume(self):
-        try:
-            molarMass = float(toMolarMass(self.model.item(MODEL.MOLECULAR_FORMULA).text()))
-            molarDensity = float(self.model.item(MODEL.MASS_DENSITY).text())
-
-            molarVolume = molarMass / molarDensity
-            self.model.item(MODEL.MOLAR_VOLUME).setText(str(molarVolume))
-
-        except (ArithmeticError, ValueError):
-            self.model.item(MODEL.MOLAR_VOLUME).setText("")
-
-    def modelReset(self):
-        #self.model.beginResetModel()
-        try:
-            self.setMode(None)
-            self.model.item(MODEL.MOLECULAR_FORMULA).setText("H2O")
-            self.model.item(MODEL.MOLAR_VOLUME     ).setText("")
-            self.model.item(MODEL.MASS_DENSITY     ).setText("")
-        finally:
-            pass
-            #self.model.endResetModel()
-
-    def displayHelp(self):
-        try:
-            location = self.manager.HELP_DIRECTORY_LOCATION + \
-                "/user/sasgui/perspectives/calculator/density_calculator_help.html"
-
-            self.manager._helpView.load(QtCore.QUrl(location))
-            self.manager._helpView.show()
-        except AttributeError:
-            # No manager defined - testing and standalone runs
-            pass
Index: c/sas/qtgui/DroppableDataLoadWidget.py
===================================================================
--- src/sas/qtgui/DroppableDataLoadWidget.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,67 +1,0 @@
-# global
-from PyQt4 import QtGui, QtCore
-
-# UI
-from sas.qtgui.UI.DataExplorerUI import Ui_DataLoadWidget
-
-class DroppableDataLoadWidget(QtGui.QTabWidget, Ui_DataLoadWidget):
-    """
-    Overwrite drag and drop methods in the base class
-    so users can drop files directly onto the Data Explorer
-    """
-    def __init__(self, parent=None, guimanager=None):
-        super(DroppableDataLoadWidget, self).__init__(parent)
-        self.setupUi(self)
-
-        # Enable file drag-drop on treeView
-        self.setAcceptDrops(True)
-        self.communicator = guimanager.communicator()
-        flags = QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowSystemMenuHint
-        self.setWindowFlags(flags)
-
-    def dragIsOK(self, event):
-        """
-        Return True if the event contain URLs
-        """
-        # Analyze mime data
-        return bool(event.mimeData().hasUrls() and self.currentIndex() == 0)
-
-    def dragEnterEvent(self, event):
-        """
-        Called automatically on a drag into the treeview
-        """
-        if self.dragIsOK(event):
-            event.setDropAction(QtCore.Qt.CopyAction)
-            event.accept()
-        else:
-            event.ignore()
-
-    def dragMoveEvent(self, event):
-        """
-        Called automatically when a drag is
-        moved inside the treeview
-        """
-        if self.dragIsOK(event):
-            event.accept()
-        else:
-            event.ignore()
-
-    def dropEvent(self, event):
-        """
-        Called automatically when a drop
-        is added to the treeview.
-        """
-        if self.dragIsOK(event):
-            filenames=[]
-            for url in event.mimeData().urls():
-                filenames.append(str(url.toLocalFile()))
-            self.communicator.fileReadSignal.emit(filenames)
-            event.accept()
-        else:
-            event.ignore()
-
-    def closeEvent(self, event):
-        """
-        Overwrite the close event - no close!
-        """
-        event.ignore()
Index: src/sas/qtgui/GUITests.py
===================================================================
--- src/sas/qtgui/GUITests.py	(revision 7248d75d0e91daa6e6c6163bb53fa76c1c8898e3)
+++ src/sas/qtgui/GUITests.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -1,30 +1,39 @@
 import unittest
 
-from UnitTesting import AboutBoxTest
-from UnitTesting import AddTextTest
-from UnitTesting import DataExplorerTest
-from UnitTesting import WelcomePanelTest
-from UnitTesting import DroppableDataLoadWidgetTest
-from UnitTesting import GuiManagerTest
-from UnitTesting import GuiUtilsTest
-from UnitTesting import MainWindowTest
+# Main Window
+from MainWindow.UnitTesting import AboutBoxTest
+from MainWindow.UnitTesting import DataExplorerTest
+from MainWindow.UnitTesting import WelcomePanelTest
+from MainWindow.UnitTesting import DroppableDataLoadWidgetTest
+from MainWindow.UnitTesting import GuiManagerTest
+from MainWindow.UnitTesting import MainWindowTest
+
+# Plotting
+from Plotting.UnitTesting import AddTextTest
+from Plotting.UnitTesting import PlotHelperTest
+from Plotting.UnitTesting import PlotterBaseTest
+from Plotting.UnitTesting import PlotterTest
+from Plotting.UnitTesting import Plotter2DTest
+from Plotting.UnitTesting import ScalePropertiesTest
+from Plotting.UnitTesting import WindowTitleTest
+from Plotting.UnitTesting import SetGraphRangeTest
+from Plotting.UnitTesting import LinearFitTest
+from Plotting.UnitTesting import PlotPropertiesTest
+from Plotting.UnitTesting import PlotUtilitiesTest
+from Plotting.UnitTesting import ColorMapTest
+from Plotting.UnitTesting import BoxSumTest
+from Plotting.UnitTesting import SlicerModelTest
+from Plotting.UnitTesting import SlicerParametersTest
+
+# Calculators
+from Calculators.UnitTesting import KiessigCalculatorTest
+from Calculators.UnitTesting import DensityCalculatorTest
+
+# Utilities
+from Utilities.UnitTesting import GuiUtilsTest
+from Utilities.UnitTesting import SasviewLoggerTest
+
+# Unit Testing
 from UnitTesting import TestUtilsTest
-from UnitTesting import PlotHelperTest
-from UnitTesting import PlotterBaseTest
-from UnitTesting import PlotterTest
-from UnitTesting import Plotter2DTest
-from UnitTesting import SasviewLoggerTest
-from UnitTesting import ScalePropertiesTest
-from UnitTesting import KiessigCalculatorTest
-from UnitTesting import DensityCalculatorTest
-from UnitTesting import WindowTitleTest
-from UnitTesting import SetGraphRangeTest
-from UnitTesting import LinearFitTest
-from UnitTesting import PlotPropertiesTest
-from UnitTesting import PlotUtilitiesTest
-from UnitTesting import ColorMapTest
-from UnitTesting import BoxSumTest
-from UnitTesting import SlicerModelTest
-from UnitTesting import SlicerParametersTest
 
 # Perspectives
@@ -38,22 +47,12 @@
 def suite():
     suites = (
-        unittest.makeSuite(AboutBoxTest.AboutBoxTest,          'test'),
+        # Plotting
+        unittest.makeSuite(PlotHelperTest.PlotHelperTest,       'test'),
+        unittest.makeSuite(PlotterTest.PlotterTest,          'test'),
+        unittest.makeSuite(WindowTitleTest.WindowTitleTest, 'test'),
+        unittest.makeSuite(PlotterBaseTest.PlotterBaseTest,     'test'),
+        unittest.makeSuite(Plotter2DTest.Plotter2DTest,        'test'),
         unittest.makeSuite(AddTextTest.AddTextTest,          'test'),
-        unittest.makeSuite(DataExplorerTest.DataExplorerTest,  'test'),
-        unittest.makeSuite(WelcomePanelTest.WelcomePanelTest,  'test'),
-        unittest.makeSuite(DroppableDataLoadWidgetTest.DroppableDataLoadWidgetTest, 'test'),
-        unittest.makeSuite(GuiManagerTest.GuiManagerTest,      'test'),
-        unittest.makeSuite(GuiUtilsTest.GuiUtilsTest,          'test'),
-        unittest.makeSuite(MainWindowTest.MainWindowTest,      'test'),
-        unittest.makeSuite(TestUtilsTest.TestUtilsTest,        'test'),
-        unittest.makeSuite(PlotHelperTest.PlotHelperTest,       'test'),
-        unittest.makeSuite(PlotterBaseTest.PlotterBaseTest,     'test'),
-        unittest.makeSuite(PlotterTest.PlotterTest,          'test'),
-        unittest.makeSuite(Plotter2DTest.Plotter2DTest,        'test'),
-        unittest.makeSuite(SasviewLoggerTest.SasviewLoggerTest,    'test'),
         unittest.makeSuite(ScalePropertiesTest.ScalePropertiesTest,  'test'),
-        unittest.makeSuite(KiessigCalculatorTest.KiessigCalculatorTest, 'test'),
-        unittest.makeSuite(DensityCalculatorTest.DensityCalculatorTest, 'test'),
-        unittest.makeSuite(WindowTitleTest.WindowTitleTest, 'test'),
         unittest.makeSuite(SetGraphRangeTest.SetGraphRangeTest, 'test'),
         unittest.makeSuite(LinearFitTest.LinearFitTest, 'test'),
@@ -64,4 +63,23 @@
         unittest.makeSuite(SlicerModelTest.SlicerModelTest, 'test'),
         unittest.makeSuite(SlicerParametersTest.SlicerParametersTest, 'test'),
+
+        # Main window
+        unittest.makeSuite(AboutBoxTest.AboutBoxTest,          'test'),
+        unittest.makeSuite(DataExplorerTest.DataExplorerTest,  'test'),
+        unittest.makeSuite(WelcomePanelTest.WelcomePanelTest,  'test'),
+        unittest.makeSuite(DroppableDataLoadWidgetTest.DroppableDataLoadWidgetTest, 'test'),
+        unittest.makeSuite(GuiManagerTest.GuiManagerTest,      'test'),
+        unittest.makeSuite(GuiUtilsTest.GuiUtilsTest,          'test'),
+        unittest.makeSuite(MainWindowTest.MainWindowTest,      'test'),
+
+        # Utilities
+        unittest.makeSuite(TestUtilsTest.TestUtilsTest,        'test'),
+        unittest.makeSuite(SasviewLoggerTest.SasviewLoggerTest,    'test'),
+
+        # Calculators
+        unittest.makeSuite(KiessigCalculatorTest.KiessigCalculatorTest, 'test'),
+        unittest.makeSuite(DensityCalculatorTest.DensityCalculatorTest, 'test'),
+
+        # Perspectives
         unittest.makeSuite(FittingPerspectiveTest.FittingPerspectiveTest, 'test'),
         unittest.makeSuite(FittingWidgetTest.FittingWidgetTest, 'test'),
Index: c/sas/qtgui/GuiManager.py
===================================================================
--- src/sas/qtgui/GuiManager.py	(revision 6c8fb2ce67ed94f8fd44ef74eff5f71b3cd6b6f6)
+++ 	(revision )
@@ -1,739 +1,0 @@
-import sys
-import os
-import subprocess
-import logging
-import json
-import webbrowser
-
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-from PyQt4 import QtWebKit
-
-from twisted.internet import reactor
-# General SAS imports
-
-from sas.sasgui.guiframe.data_manager import DataManager
-from sas.sasgui.guiframe.proxy import Connection
-from sas.qtgui.SasviewLogger import XStream
-import sas.qtgui.LocalConfig as LocalConfig
-import sas.qtgui.GuiUtils as GuiUtils
-from sas.qtgui.UI.AcknowledgementsUI import Ui_Acknowledgements
-from sas.qtgui.AboutBox import AboutBox
-from sas.qtgui.IPythonWidget import IPythonWidget
-from sas.qtgui.WelcomePanel import WelcomePanel
-
-from sas.qtgui.SldPanel import SldPanel
-from sas.qtgui.DensityPanel import DensityPanel
-from sas.qtgui.KiessigPanel import KiessigPanel
-from sas.qtgui.SlitSizeCalculator import SlitSizeCalculator
-
-# Perspectives
-import Perspectives
-from sas.qtgui.Perspectives.Fitting.FittingPerspective import FittingWindow
-from sas.qtgui.DataExplorer import DataExplorerWindow
-
-class Acknowledgements(QtGui.QDialog, Ui_Acknowledgements):
-    def __init__(self, parent=None):
-        QtGui.QDialog.__init__(self, parent)
-        self.setupUi(self)
-
-class GuiManager(object):
-    """
-    Main SasView window functionality
-    """
-    ## TODO: CHANGE FOR SHIPPED PATH IN RELEASE
-    HELP_DIRECTORY_LOCATION = "docs/sphinx-docs/build/html"
-
-    def __init__(self, parent=None):
-        """
-        Initialize the manager as a child of MainWindow.
-        """
-        self._workspace = parent
-        self._parent = parent
-
-        # Reactor - singleton
-        self.setReactor(reactor)
-
-        # Add signal callbacks
-        self.addCallbacks()
-
-        # Create the data manager
-        # TODO: pull out all required methods from DataManager and reimplement
-        self._data_manager = DataManager()
-
-        # Create action triggers
-        self.addTriggers()
-
-        # Populate menus with dynamic data
-        #
-        # Analysis/Perspectives - potentially
-        # Window/current windows
-        #
-        # Widgets
-        #
-        # Current displayed perspective
-        self._current_perspective = None
-
-        # Invoke the initial perspective
-        self.perspectiveChanged("Fitting")
-
-        self.addWidgets()
-
-        # Fork off logging messages to the Log Window
-        XStream.stdout().messageWritten.connect(self.listWidget.insertPlainText)
-        XStream.stderr().messageWritten.connect(self.listWidget.insertPlainText)
-
-        # Log the start of the session
-        logging.info(" --- SasView session started ---")
-        # Log the python version
-        logging.info("Python: %s" % sys.version)
-
-        # Set up the status bar
-        self.statusBarSetup()
-
-        # Show the Welcome panel
-        self.welcomePanel = WelcomePanel()
-        self._workspace.workspace.addWindow(self.welcomePanel)
-
-        # Current help file
-        self._helpView = QtWebKit.QWebView()
-        # Needs URL like path, so no path.join() here
-        self._helpLocation = self.HELP_DIRECTORY_LOCATION + "/index.html"
-
-        # Current tutorial location
-        self._tutorialLocation = os.path.abspath(os.path.join(self.HELP_DIRECTORY_LOCATION,
-                                              "_downloads",
-                                              "Tutorial.pdf"))
-    def addWidgets(self):
-        """
-        Populate the main window with widgets
-
-        TODO: overwrite close() on Log and DR widgets so they can be hidden/shown
-        on request
-        """
-        # Add FileDialog widget as docked
-        self.filesWidget = DataExplorerWindow(self._parent, self, manager=self._data_manager)
-
-        self.dockedFilesWidget = QtGui.QDockWidget("Data Explorer", self._workspace)
-        self.dockedFilesWidget.setWidget(self.filesWidget)
-
-        # Disable maximize/minimize and close buttons
-        self.dockedFilesWidget.setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures)
-        self._workspace.addDockWidget(QtCore.Qt.LeftDockWidgetArea,
-                                      self.dockedFilesWidget)
-
-        # Add the console window as another docked widget
-        self.logDockWidget = QtGui.QDockWidget("Log Explorer", self._workspace)
-        self.logDockWidget.setObjectName("LogDockWidget")
-        self.listWidget = QtGui.QTextBrowser()
-        self.logDockWidget.setWidget(self.listWidget)
-        self._workspace.addDockWidget(QtCore.Qt.BottomDockWidgetArea,
-                                      self.logDockWidget)
-
-        # Add other, minor widgets
-        self.ackWidget = Acknowledgements()
-        self.aboutWidget = AboutBox()
-
-        # Add calculators - floating for usability
-        self.SLDCalculator = SldPanel(self)
-        self.DVCalculator = DensityPanel(self)
-        #self.KIESSIGCalculator = DensityPanel(self)#KiessigPanel(self)
-        self.KIESSIGCalculator = KiessigPanel(self)
-        self.SlitSizeCalculator = SlitSizeCalculator(self)
-
-    def statusBarSetup(self):
-        """
-        Define the status bar.
-        | <message label> .... | Progress Bar |
-
-        Progress bar invisible until explicitly shown
-        """
-        self.progress = QtGui.QProgressBar()
-        self._workspace.statusbar.setSizeGripEnabled(False)
-
-        self.statusLabel = QtGui.QLabel()
-        self.statusLabel.setText("Welcome to SasView")
-        self._workspace.statusbar.addPermanentWidget(self.statusLabel, 1)
-        self._workspace.statusbar.addPermanentWidget(self.progress, stretch=0)
-        self.progress.setRange(0, 100)
-        self.progress.setValue(0)
-        self.progress.setTextVisible(True)
-        self.progress.setVisible(False)
-
-    def fileRead(self, data):
-        """
-        Callback for fileDataReceivedSignal
-        """
-        pass
-
-    def workspace(self):
-        """
-        Accessor for the main window workspace
-        """
-        return self._workspace.workspace
-
-    def perspectiveChanged(self, perspective_name):
-        """
-        Respond to change of the perspective signal
-        """
-        # Close the previous perspective
-        if self._current_perspective:
-            self._current_perspective.setClosable()
-            self._current_perspective.close()
-        # Default perspective
-        self._current_perspective = Perspectives.PERSPECTIVES[str(perspective_name)](parent=self)
-
-        self._workspace.workspace.addWindow(self._current_perspective)
-        # Resize to the workspace height
-        workspace_height = self._workspace.workspace.sizeHint().height()
-        perspective_size = self._current_perspective.sizeHint()
-        if workspace_height < perspective_size.height:
-            perspective_width = perspective_size.width()
-            self._current_perspective.resize(perspective_width, workspace_height-10)
-        self._current_perspective.show()
-
-    def updatePerspective(self, data):
-        """
-        Update perspective with data sent.
-        """
-        assert isinstance(data, list)
-        if self._current_perspective is not None:
-            self._current_perspective.setData(data.values())
-        else:
-            msg = "No perspective is currently active."
-            logging.info(msg)
-
-    def communicator(self):
-        """ Accessor for the communicator """
-        return self.communicate
-
-    def reactor(self):
-        """ Accessor for the reactor """
-        return self._reactor
-
-    def setReactor(self, reactor):
-        """ Reactor setter """
-        self._reactor = reactor
-
-    def perspective(self):
-        """ Accessor for the perspective """
-        return self._current_perspective
-
-    def updateProgressBar(self, value):
-        """
-        Update progress bar with the required value (0-100)
-        """
-        assert -1 <= value <= 100
-        if value == -1:
-            self.progress.setVisible(False)
-            return
-        if not self.progress.isVisible():
-            self.progress.setTextVisible(True)
-            self.progress.setVisible(True)
-
-        self.progress.setValue(value)
-
-    def updateStatusBar(self, text):
-        """
-        Set the status bar text
-        """
-        self.statusLabel.setText(text)
-
-    def createGuiData(self, item, p_file=None):
-        """
-        Access the Data1D -> plottable Data1D conversion
-        """
-        return self._data_manager.create_gui_data(item, p_file)
-
-    def setData(self, data):
-        """
-        Sends data to current perspective
-        """
-        if self._current_perspective is not None:
-            self._current_perspective.setData(data.values())
-        else:
-            msg = "Guiframe does not have a current perspective"
-            logging.info(msg)
-
-    def quitApplication(self):
-        """
-        Close the reactor and exit nicely.
-        """
-        # Display confirmation messagebox
-        quit_msg = "Are you sure you want to exit the application?"
-        reply = QtGui.QMessageBox.question(
-            self._parent,
-            'Information',
-            quit_msg,
-            QtGui.QMessageBox.Yes,
-            QtGui.QMessageBox.No)
-
-        # Exit if yes
-        if reply == QtGui.QMessageBox.Yes:
-            reactor.callFromThread(reactor.stop)
-            return True
-
-        return False
-
-    def checkUpdate(self):
-        """
-        Check with the deployment server whether a new version
-        of the application is available.
-        A thread is started for the connecting with the server. The thread calls
-        a call-back method when the current version number has been obtained.
-        """
-        version_info = {"version": "0.0.0"}
-        c = Connection(LocalConfig.__update_URL__, LocalConfig.UPDATE_TIMEOUT)
-        response = c.connect()
-        if response is None:
-            return
-        try:
-            content = response.read().strip()
-            logging.info("Connected to www.sasview.org. Latest version: %s"
-                            % (content))
-            version_info = json.loads(content)
-            self.processVersion(version_info)
-        except ValueError, ex:
-            logging.info("Failed to connect to www.sasview.org:", ex)
-
-    def processVersion(self, version_info):
-        """
-        Call-back method for the process of checking for updates.
-        This methods is called by a VersionThread object once the current
-        version number has been obtained. If the check is being done in the
-        background, the user will not be notified unless there's an update.
-
-        :param version: version string
-        """
-        try:
-            version = version_info["version"]
-            if version == "0.0.0":
-                msg = "Could not connect to the application server."
-                msg += " Please try again later."
-                self.communicate.statusBarUpdateSignal.emit(msg)
-
-            elif cmp(version, LocalConfig.__version__) > 0:
-                msg = "Version %s is available! " % str(version)
-                if "download_url" in version_info:
-                    webbrowser.open(version_info["download_url"])
-                else:
-                    webbrowser.open(LocalConfig.__download_page__)
-                self.communicate.statusBarUpdateSignal.emit(msg)
-            else:
-                msg = "You have the latest version"
-                msg += " of %s" % str(LocalConfig.__appname__)
-                self.communicate.statusBarUpdateSignal.emit(msg)
-        except:
-            msg = "guiframe: could not get latest application"
-            msg += " version number\n  %s" % sys.exc_value
-            logging.error(msg)
-            msg = "Could not connect to the application server."
-            msg += " Please try again later."
-            self.communicate.statusBarUpdateSignal.emit(msg)
-
-    def addCallbacks(self):
-        """
-        Method defining all signal connections for the gui manager
-        """
-        self.communicate = GuiUtils.Communicate()
-        self.communicate.fileDataReceivedSignal.connect(self.fileRead)
-        self.communicate.statusBarUpdateSignal.connect(self.updateStatusBar)
-        self.communicate.updatePerspectiveWithDataSignal.connect(self.updatePerspective)
-        self.communicate.progressBarUpdateSignal.connect(self.updateProgressBar)
-        self.communicate.perspectiveChangedSignal.connect(self.perspectiveChanged)
-        self.communicate.updateTheoryFromPerspectiveSignal.connect(self.updateTheoryFromPerspective)
-
-    def addTriggers(self):
-        """
-        Trigger definitions for all menu/toolbar actions.
-        """
-        # File
-        self._workspace.actionLoadData.triggered.connect(self.actionLoadData)
-        self._workspace.actionLoad_Data_Folder.triggered.connect(self.actionLoad_Data_Folder)
-        self._workspace.actionOpen_Project.triggered.connect(self.actionOpen_Project)
-        self._workspace.actionOpen_Analysis.triggered.connect(self.actionOpen_Analysis)
-        self._workspace.actionSave.triggered.connect(self.actionSave)
-        self._workspace.actionSave_Analysis.triggered.connect(self.actionSave_Analysis)
-        self._workspace.actionQuit.triggered.connect(self.actionQuit)
-        # Edit
-        self._workspace.actionUndo.triggered.connect(self.actionUndo)
-        self._workspace.actionRedo.triggered.connect(self.actionRedo)
-        self._workspace.actionCopy.triggered.connect(self.actionCopy)
-        self._workspace.actionPaste.triggered.connect(self.actionPaste)
-        self._workspace.actionReport.triggered.connect(self.actionReport)
-        self._workspace.actionReset.triggered.connect(self.actionReset)
-        self._workspace.actionExcel.triggered.connect(self.actionExcel)
-        self._workspace.actionLatex.triggered.connect(self.actionLatex)
-
-        # View
-        self._workspace.actionShow_Grid_Window.triggered.connect(self.actionShow_Grid_Window)
-        self._workspace.actionHide_Toolbar.triggered.connect(self.actionHide_Toolbar)
-        self._workspace.actionStartup_Settings.triggered.connect(self.actionStartup_Settings)
-        self._workspace.actionCategry_Manager.triggered.connect(self.actionCategry_Manager)
-        # Tools
-        self._workspace.actionData_Operation.triggered.connect(self.actionData_Operation)
-        self._workspace.actionSLD_Calculator.triggered.connect(self.actionSLD_Calculator)
-        self._workspace.actionDensity_Volume_Calculator.triggered.connect(self.actionDensity_Volume_Calculator)
-        self._workspace.actionKeissig_Calculator.triggered.connect(self.actionKiessig_Calculator)
-        #self._workspace.actionKIESSING_Calculator.triggered.connect(self.actionKIESSING_Calculator)
-        self._workspace.actionSlit_Size_Calculator.triggered.connect(self.actionSlit_Size_Calculator)
-        self._workspace.actionSAS_Resolution_Estimator.triggered.connect(self.actionSAS_Resolution_Estimator)
-        self._workspace.actionGeneric_Scattering_Calculator.triggered.connect(self.actionGeneric_Scattering_Calculator)
-        self._workspace.actionPython_Shell_Editor.triggered.connect(self.actionPython_Shell_Editor)
-        self._workspace.actionImage_Viewer.triggered.connect(self.actionImage_Viewer)
-        # Fitting
-        self._workspace.actionNew_Fit_Page.triggered.connect(self.actionNew_Fit_Page)
-        self._workspace.actionConstrained_Fit.triggered.connect(self.actionConstrained_Fit)
-        self._workspace.actionCombine_Batch_Fit.triggered.connect(self.actionCombine_Batch_Fit)
-        self._workspace.actionFit_Options.triggered.connect(self.actionFit_Options)
-        self._workspace.actionFit_Results.triggered.connect(self.actionFit_Results)
-        self._workspace.actionChain_Fitting.triggered.connect(self.actionChain_Fitting)
-        self._workspace.actionEdit_Custom_Model.triggered.connect(self.actionEdit_Custom_Model)
-        # Window
-        self._workspace.actionCascade.triggered.connect(self.actionCascade)
-        self._workspace.actionTile.triggered.connect(self.actionTile)
-        self._workspace.actionArrange_Icons.triggered.connect(self.actionArrange_Icons)
-        self._workspace.actionNext.triggered.connect(self.actionNext)
-        self._workspace.actionPrevious.triggered.connect(self.actionPrevious)
-        # Analysis
-        self._workspace.actionFitting.triggered.connect(self.actionFitting)
-        self._workspace.actionInversion.triggered.connect(self.actionInversion)
-        self._workspace.actionInvariant.triggered.connect(self.actionInvariant)
-        # Help
-        self._workspace.actionDocumentation.triggered.connect(self.actionDocumentation)
-        self._workspace.actionTutorial.triggered.connect(self.actionTutorial)
-        self._workspace.actionAcknowledge.triggered.connect(self.actionAcknowledge)
-        self._workspace.actionAbout.triggered.connect(self.actionAbout)
-        self._workspace.actionCheck_for_update.triggered.connect(self.actionCheck_for_update)
-
-    #============ FILE =================
-    def actionLoadData(self):
-        """
-        Menu File/Load Data File(s)
-        """
-        self.filesWidget.loadFile()
-
-    def actionLoad_Data_Folder(self):
-        """
-        Menu File/Load Data Folder
-        """
-        self.filesWidget.loadFolder()
-
-    def actionOpen_Project(self):
-        """
-        Menu Open Project
-        """
-        self.filesWidget.loadProject()
-
-    def actionOpen_Analysis(self):
-        """
-        """
-        print("actionOpen_Analysis TRIGGERED")
-        pass
-
-    def actionSave(self):
-        """
-        Menu Save Project
-        """
-        self.filesWidget.saveProject()
-
-    def actionSave_Analysis(self):
-        """
-        """
-        print("actionSave_Analysis TRIGGERED")
-
-        pass
-
-    def actionQuit(self):
-        """
-        Close the reactor, exit the application.
-        """
-        self.quitApplication()
-
-    #============ EDIT =================
-    def actionUndo(self):
-        """
-        """
-        print("actionUndo TRIGGERED")
-        pass
-
-    def actionRedo(self):
-        """
-        """
-        print("actionRedo TRIGGERED")
-        pass
-
-    def actionCopy(self):
-        """
-        """
-        print("actionCopy TRIGGERED")
-        pass
-
-    def actionPaste(self):
-        """
-        """
-        print("actionPaste TRIGGERED")
-        pass
-
-    def actionReport(self):
-        """
-        """
-        print("actionReport TRIGGERED")
-        pass
-
-    def actionReset(self):
-        """
-        """
-        logging.warning(" *** actionOpen_Analysis logging *******")
-        print("actionReset print TRIGGERED")
-        sys.stderr.write("STDERR - TRIGGERED")
-        pass
-
-    def actionExcel(self):
-        """
-        """
-        print("actionExcel TRIGGERED")
-        pass
-
-    def actionLatex(self):
-        """
-        """
-        print("actionLatex TRIGGERED")
-        pass
-
-    #============ VIEW =================
-    def actionShow_Grid_Window(self):
-        """
-        """
-        print("actionShow_Grid_Window TRIGGERED")
-        pass
-
-    def actionHide_Toolbar(self):
-        """
-        Toggle toolbar vsibility
-        """
-        if self._workspace.toolBar.isVisible():
-            self._workspace.actionHide_Toolbar.setText("Show Toolbar")
-            self._workspace.toolBar.setVisible(False)
-        else:
-            self._workspace.actionHide_Toolbar.setText("Hide Toolbar")
-            self._workspace.toolBar.setVisible(True)
-        pass
-
-    def actionStartup_Settings(self):
-        """
-        """
-        print("actionStartup_Settings TRIGGERED")
-        pass
-
-    def actionCategry_Manager(self):
-        """
-        """
-        print("actionCategry_Manager TRIGGERED")
-        pass
-
-    #============ TOOLS =================
-    def actionData_Operation(self):
-        """
-        """
-        print("actionData_Operation TRIGGERED")
-        pass
-
-    def actionSLD_Calculator(self):
-        """
-        """
-        self.SLDCalculator.show()
-
-    def actionDensity_Volume_Calculator(self):
-        """
-        """
-        self.DVCalculator.show()
-
-    def actionKiessig_Calculator(self):
-        """
-        """
-        #self.DVCalculator.show()
-        self.KIESSIGCalculator.show()
-
-    def actionSlit_Size_Calculator(self):
-        """
-        """
-        self.SlitSizeCalculator.show()
-
-    def actionSAS_Resolution_Estimator(self):
-        """
-        """
-        print("actionSAS_Resolution_Estimator TRIGGERED")
-        pass
-
-    def actionGeneric_Scattering_Calculator(self):
-        """
-        """
-        print("actionGeneric_Scattering_Calculator TRIGGERED")
-        pass
-
-    def actionPython_Shell_Editor(self):
-        """
-        Display the Jupyter console as a docked widget.
-        """
-        terminal = IPythonWidget()
-
-        # Add the console window as another docked widget
-        self.ipDockWidget = QtGui.QDockWidget("IPython", self._workspace)
-        self.ipDockWidget.setObjectName("IPythonDockWidget")
-        self.ipDockWidget.setWidget(terminal)
-        self._workspace.addDockWidget(QtCore.Qt.RightDockWidgetArea,
-                                      self.ipDockWidget)
-
-    def actionImage_Viewer(self):
-        """
-        """
-        print("actionImage_Viewer TRIGGERED")
-        pass
-
-    #============ FITTING =================
-    def actionNew_Fit_Page(self):
-        """
-        Add a new, empty Fit page in the fitting perspective.
-        """
-        # Make sure the perspective is correct
-        per = self.perspective()
-        if not isinstance(per, FittingWindow):
-            return
-        per.addFit(None)
-
-    def actionConstrained_Fit(self):
-        """
-        """
-        print("actionConstrained_Fit TRIGGERED")
-        pass
-
-    def actionCombine_Batch_Fit(self):
-        """
-        """
-        print("actionCombine_Batch_Fit TRIGGERED")
-        pass
-
-    def actionFit_Options(self):
-        """
-        """
-        print("actionFit_Options TRIGGERED")
-        pass
-
-    def actionFit_Results(self):
-        """
-        """
-        print("actionFit_Results TRIGGERED")
-        pass
-
-    def actionChain_Fitting(self):
-        """
-        """
-        print("actionChain_Fitting TRIGGERED")
-        pass
-
-    def actionEdit_Custom_Model(self):
-        """
-        """
-        print("actionEdit_Custom_Model TRIGGERED")
-        pass
-
-    #============ ANALYSIS =================
-    def actionFitting(self):
-        """
-        """
-        print("actionFitting TRIGGERED")
-        pass
-
-    def actionInversion(self):
-        """
-        """
-        print("actionInversion TRIGGERED")
-        pass
-
-    def actionInvariant(self):
-        """
-        """
-        print("actionInvariant TRIGGERED")
-        pass
-
-    #============ WINDOW =================
-    def actionCascade(self):
-        """
-        Arranges all the child windows in a cascade pattern.
-        """
-        self._workspace.workspace.cascade()
-
-    def actionTile(self):
-        """
-        Tile workspace windows
-        """
-        self._workspace.workspace.tile()
-
-    def actionArrange_Icons(self):
-        """
-        Arranges all iconified windows at the bottom of the workspace
-        """
-        self._workspace.workspace.arrangeIcons()
-
-    def actionNext(self):
-        """
-        Gives the input focus to the next window in the list of child windows.
-        """
-        self._workspace.workspace.activateNextWindow()
-
-    def actionPrevious(self):
-        """
-        Gives the input focus to the previous window in the list of child windows.
-        """
-        self._workspace.workspace.activatePreviousWindow()
-
-    #============ HELP =================
-    def actionDocumentation(self):
-        """
-        Display the documentation
-
-        TODO: use QNetworkAccessManager to assure _helpLocation is valid
-        """
-        self._helpView.load(QtCore.QUrl(self._helpLocation))
-        self._helpView.show()
-
-    def actionTutorial(self):
-        """
-        Open the tutorial PDF file with default PDF renderer
-        """
-        # Not terribly safe here. Shell injection warning.
-        # isfile() helps but this probably needs a better solution.
-        if os.path.isfile(self._tutorialLocation):
-            result = subprocess.Popen([self._tutorialLocation], shell=True)
-
-    def actionAcknowledge(self):
-        """
-        Open the Acknowledgements widget
-        """
-        self.ackWidget.show()
-
-    def actionAbout(self):
-        """
-        Open the About box
-        """
-        # Update the about box with current version and stuff
-
-        # TODO: proper sizing
-        self.aboutWidget.show()
-
-    def actionCheck_for_update(self):
-        """
-        Menu Help/Check for Update
-        """
-        self.checkUpdate()
-
-    def updateTheoryFromPerspective(self, index):
-        """
-        Catch the theory update signal from a perspective
-        Send the request to the DataExplorer for updating the theory model.
-        """
-        self.filesWidget.updateTheoryFromPerspective(index)
-
-
-
Index: c/sas/qtgui/GuiUtils.py
===================================================================
--- src/sas/qtgui/GuiUtils.py	(revision 7d077d102dde02b0f95f856a18145c67b9e47ddd)
+++ 	(revision )
@@ -1,747 +1,0 @@
-"""
-Global defaults and various utility functions usable by the general GUI
-"""
-
-import os
-import sys
-import imp
-import warnings
-import webbrowser
-import urlparse
-
-warnings.simplefilter("ignore")
-import logging
-
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-
-# Translate event handlers
-#from sas.sasgui.guiframe.events import EVT_CATEGORY
-#from sas.sasgui.guiframe.events import EVT_STATUS
-#from sas.sasgui.guiframe.events import EVT_APPEND_BOOKMARK
-#from sas.sasgui.guiframe.events import EVT_PANEL_ON_FOCUS
-#from sas.sasgui.guiframe.events import EVT_NEW_LOAD_DATA
-#from sas.sasgui.guiframe.events import EVT_NEW_COLOR
-#from sas.sasgui.guiframe.events import StatusEvent
-#from sas.sasgui.guiframe.events import NewPlotEvent
-
-from periodictable import formula as Formula
-
-from sas.sasgui.plottools import transform
-from sas.sasgui.plottools.convert_units import convert_unit
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.dataFitting import Data2D
-from sas.sascalc.dataloader.loader import Loader
-
-
-def get_app_dir():
-    """
-        The application directory is the one where the default custom_config.py
-        file resides.
-
-        :returns: app_path - the path to the applicatin directory
-    """
-    # First, try the directory of the executable we are running
-    app_path = sys.path[0]
-    if os.path.isfile(app_path):
-        app_path = os.path.dirname(app_path)
-    if os.path.isfile(os.path.join(app_path, "custom_config.py")):
-        app_path = os.path.abspath(app_path)
-        #logging.info("Using application path: %s", app_path)
-        return app_path
-
-    # Next, try the current working directory
-    if os.path.isfile(os.path.join(os.getcwd(), "custom_config.py")):
-        #logging.info("Using application path: %s", os.getcwd())
-        return os.path.abspath(os.getcwd())
-
-    # Finally, try the directory of the sasview module
-    # TODO: gui_manager will have to know about sasview until we
-    # clean all these module variables and put them into a config class
-    # that can be passed by sasview.py.
-    #logging.info(sys.executable)
-    #logging.info(str(sys.argv))
-    from sas import sasview as sasview
-    app_path = os.path.dirname(sasview.__file__)
-    #logging.info("Using application path: %s", app_path)
-    return app_path
-
-def get_user_directory():
-    """
-        Returns the user's home directory
-    """
-    userdir = os.path.join(os.path.expanduser("~"), ".sasview")
-    if not os.path.isdir(userdir):
-        os.makedirs(userdir)
-    return userdir
-
-def _find_local_config(confg_file, path):
-    """
-        Find configuration file for the current application
-    """
-    config_module = None
-    fObj = None
-    try:
-        fObj, path_config, descr = imp.find_module(confg_file, [path])
-        config_module = imp.load_module(confg_file, fObj, path_config, descr)
-    except ImportError:
-        pass
-        #logging.error("Error loading %s/%s: %s" % (path, confg_file, sys.exc_value))
-    finally:
-        if fObj is not None:
-            fObj.close()
-    #logging.info("GuiManager loaded %s/%s" % (path, confg_file))
-    return config_module
-
-# Get APP folder
-PATH_APP = get_app_dir()
-DATAPATH = PATH_APP
-
-# GUI always starts from the App folder
-#os.chdir(PATH_APP)
-# Read in the local config, which can either be with the main
-# application or in the installation directory
-config = _find_local_config('local_config', PATH_APP)
-
-if config is None:
-    config = _find_local_config('local_config', os.getcwd())
-    if config is None:
-        # Didn't find local config, load the default
-        import sas.sasgui.guiframe.config as config
-        #logging.info("using default local_config")
-    else:
-        pass
-        #logging.info("found local_config in %s", os.getcwd())
-else:
-    pass
-    #logging.info("found local_config in %s", PATH_APP)
-
-
-from sas.sasgui.guiframe.customdir  import SetupCustom
-c_conf_dir = SetupCustom().setup_dir(PATH_APP)
-custom_config = _find_local_config('custom_config', c_conf_dir)
-if custom_config is None:
-    custom_config = _find_local_config('custom_config', os.getcwd())
-    if custom_config is None:
-        msgConfig = "Custom_config file was not imported"
-        #logging.info(msgConfig)
-    else:
-        pass
-        #logging.info("using custom_config in %s", os.getcwd())
-else:
-    pass
-    #logging.info("using custom_config from %s", c_conf_dir)
-
-#read some constants from config
-APPLICATION_STATE_EXTENSION = config.APPLICATION_STATE_EXTENSION
-APPLICATION_NAME = config.__appname__
-SPLASH_SCREEN_PATH = config.SPLASH_SCREEN_PATH
-WELCOME_PANEL_ON = config.WELCOME_PANEL_ON
-SPLASH_SCREEN_WIDTH = config.SPLASH_SCREEN_WIDTH
-SPLASH_SCREEN_HEIGHT = config.SPLASH_SCREEN_HEIGHT
-SS_MAX_DISPLAY_TIME = config.SS_MAX_DISPLAY_TIME
-if not WELCOME_PANEL_ON:
-    WELCOME_PANEL_SHOW = False
-else:
-    WELCOME_PANEL_SHOW = True
-try:
-    DATALOADER_SHOW = custom_config.DATALOADER_SHOW
-    TOOLBAR_SHOW = custom_config.TOOLBAR_SHOW
-    FIXED_PANEL = custom_config.FIXED_PANEL
-    if WELCOME_PANEL_ON:
-        WELCOME_PANEL_SHOW = custom_config.WELCOME_PANEL_SHOW
-    PLOPANEL_WIDTH = custom_config.PLOPANEL_WIDTH
-    DATAPANEL_WIDTH = custom_config.DATAPANEL_WIDTH
-    GUIFRAME_WIDTH = custom_config.GUIFRAME_WIDTH
-    GUIFRAME_HEIGHT = custom_config.GUIFRAME_HEIGHT
-    CONTROL_WIDTH = custom_config.CONTROL_WIDTH
-    CONTROL_HEIGHT = custom_config.CONTROL_HEIGHT
-    DEFAULT_PERSPECTIVE = custom_config.DEFAULT_PERSPECTIVE
-    CLEANUP_PLOT = custom_config.CLEANUP_PLOT
-    # custom open_path
-    open_folder = custom_config.DEFAULT_OPEN_FOLDER
-    if open_folder != None and os.path.isdir(open_folder):
-        DEFAULT_OPEN_FOLDER = os.path.abspath(open_folder)
-    else:
-        DEFAULT_OPEN_FOLDER = PATH_APP
-except AttributeError:
-    DATALOADER_SHOW = True
-    TOOLBAR_SHOW = True
-    FIXED_PANEL = True
-    WELCOME_PANEL_SHOW = False
-    PLOPANEL_WIDTH = config.PLOPANEL_WIDTH
-    DATAPANEL_WIDTH = config.DATAPANEL_WIDTH
-    GUIFRAME_WIDTH = config.GUIFRAME_WIDTH
-    GUIFRAME_HEIGHT = config.GUIFRAME_HEIGHT
-    CONTROL_WIDTH = -1
-    CONTROL_HEIGHT = -1
-    DEFAULT_PERSPECTIVE = None
-    CLEANUP_PLOT = False
-    DEFAULT_OPEN_FOLDER = PATH_APP
-
-DEFAULT_STYLE = config.DEFAULT_STYLE
-
-PLUGIN_STATE_EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS
-OPEN_SAVE_MENU = config.OPEN_SAVE_PROJECT_MENU
-VIEW_MENU = config.VIEW_MENU
-EDIT_MENU = config.EDIT_MENU
-extension_list = []
-if APPLICATION_STATE_EXTENSION is not None:
-    extension_list.append(APPLICATION_STATE_EXTENSION)
-EXTENSIONS = PLUGIN_STATE_EXTENSIONS + extension_list
-try:
-    PLUGINS_WLIST = '|'.join(config.PLUGINS_WLIST)
-except AttributeError:
-    PLUGINS_WLIST = ''
-APPLICATION_WLIST = config.APPLICATION_WLIST
-IS_WIN = True
-IS_LINUX = False
-CLOSE_SHOW = True
-TIME_FACTOR = 2
-NOT_SO_GRAPH_LIST = ["BoxSum"]
-
-class Communicate(QtCore.QObject):
-    """
-    Utility class for tracking of the Qt signals
-    """
-    # File got successfully read
-    fileReadSignal = QtCore.pyqtSignal(list)
-
-    # Open File returns "list" of paths
-    fileDataReceivedSignal = QtCore.pyqtSignal(dict)
-
-    # Update Main window status bar with "str"
-    # Old "StatusEvent"
-    statusBarUpdateSignal = QtCore.pyqtSignal(str)
-
-    # Send data to the current perspective
-    updatePerspectiveWithDataSignal = QtCore.pyqtSignal(list)
-
-    # New data in current perspective
-    updateModelFromPerspectiveSignal = QtCore.pyqtSignal(QtGui.QStandardItem)
-
-    # New theory data in current perspective
-    updateTheoryFromPerspectiveSignal = QtCore.pyqtSignal(QtGui.QStandardItem)
-
-    # New plot requested from the GUI manager
-    # Old "NewPlotEvent"
-    plotRequestedSignal = QtCore.pyqtSignal(str)
-
-    # Plot update requested from a perspective
-    plotUpdateSignal = QtCore.pyqtSignal(list)
-
-    # Progress bar update value
-    progressBarUpdateSignal = QtCore.pyqtSignal(int)
-
-    # Workspace charts added/removed
-    activeGraphsSignal = QtCore.pyqtSignal(list)
-
-    # Current workspace chart's name changed
-    activeGraphName = QtCore.pyqtSignal(tuple)
-
-    # Current perspective changed
-    perspectiveChangedSignal = QtCore.pyqtSignal(str)
-
-
-def updateModelItemWithPlot(item, update_data, name=""):
-    """
-    Adds a checkboxed row named "name" to QStandardItem
-    Adds QVariant 'update_data' to that row.
-    """
-    assert isinstance(item, QtGui.QStandardItem)
-    assert isinstance(update_data, QtCore.QVariant)
-    py_update_data = update_data.toPyObject()
-
-    # Check if data with the same ID is already present
-    for index in range(item.rowCount()):
-        plot_item = item.child(index)
-        if plot_item.isCheckable():
-            plot_data = plot_item.child(0).data().toPyObject()
-            if plot_data.id is not None and plot_data.id == py_update_data.id:
-                # replace data section in item
-                plot_item.child(0).setData(update_data)
-                plot_item.setText(name)
-                # Force redisplay
-                return
-
-    # Create the new item
-    checkbox_item = createModelItemWithPlot(update_data, name)
-
-    # Append the new row to the main item
-    item.appendRow(checkbox_item)
-
-def createModelItemWithPlot(update_data, name=""):
-    """
-    Creates a checkboxed QStandardItem named "name"
-    Adds QVariant 'update_data' to that row.
-    """
-    assert isinstance(update_data, QtCore.QVariant)
-    py_update_data = update_data.toPyObject()
-
-    checkbox_item = QtGui.QStandardItem()
-    checkbox_item.setCheckable(True)
-    checkbox_item.setCheckState(QtCore.Qt.Checked)
-    checkbox_item.setText(name)
-
-    # Add "Info" item
-    if isinstance(py_update_data, (Data1D, Data2D)):
-        # If Data1/2D added - extract Info from it
-        info_item = infoFromData(py_update_data)
-    else:
-        # otherwise just add a naked item
-        info_item = QtGui.QStandardItem("Info")
-
-    # Add the actual Data1D/Data2D object
-    object_item = QtGui.QStandardItem()
-    object_item.setData(update_data)
-
-    # Set the data object as the first child
-    checkbox_item.setChild(0, object_item)
-
-    # Set info_item as the second child
-    checkbox_item.setChild(1, info_item)
-
-    # And return the newly created item
-    return checkbox_item
-
-def updateModelItem(item, update_data, name=""):
-    """
-    Adds a simple named child to QStandardItem
-    """
-    assert isinstance(item, QtGui.QStandardItem)
-    assert isinstance(update_data, list)
-
-    # Add the actual Data1D/Data2D object
-    object_item = QtGui.QStandardItem()
-    object_item.setText(name)
-    object_item.setData(QtCore.QVariant(update_data))
-
-    # Append the new row to the main item
-    item.appendRow(object_item)
-
-
-def plotsFromCheckedItems(model_item):
-    """
-    Returns the list of plots for items in the model which are checked
-    """
-    assert isinstance(model_item, QtGui.QStandardItemModel)
-
-    plot_data = []
-    # Iterate over model looking for items with checkboxes
-    for index in range(model_item.rowCount()):
-        item = model_item.item(index)
-        if item.isCheckable() and item.checkState() == QtCore.Qt.Checked:
-            # TODO: assure item type is correct (either data1/2D or Plotter)
-            plot_data.append((item, item.child(0).data().toPyObject()))
-        # Going 1 level deeper only
-        for index_2 in range(item.rowCount()):
-            item_2 = item.child(index_2)
-            if item_2 and item_2.isCheckable() and item_2.checkState() == QtCore.Qt.Checked:
-                # TODO: assure item type is correct (either data1/2D or Plotter)
-                plot_data.append((item_2, item_2.child(0).data().toPyObject()))
-
-    return plot_data
-
-def infoFromData(data):
-    """
-    Given Data1D/Data2D object, extract relevant Info elements
-    and add them to a model item
-    """
-    assert isinstance(data, (Data1D, Data2D))
-
-    info_item = QtGui.QStandardItem("Info")
-
-    title_item = QtGui.QStandardItem("Title: " + data.title)
-    info_item.appendRow(title_item)
-    run_item = QtGui.QStandardItem("Run: " + str(data.run))
-    info_item.appendRow(run_item)
-    type_item = QtGui.QStandardItem("Type: " + str(data.__class__.__name__))
-    info_item.appendRow(type_item)
-
-    if data.path:
-        path_item = QtGui.QStandardItem("Path: " + data.path)
-        info_item.appendRow(path_item)
-
-    if data.instrument:
-        instr_item = QtGui.QStandardItem("Instrument: " + data.instrument)
-        info_item.appendRow(instr_item)
-
-    process_item = QtGui.QStandardItem("Process")
-    if isinstance(data.process, list) and data.process:
-        for process in data.process:
-            process_date = process.date
-            process_date_item = QtGui.QStandardItem("Date: " + process_date)
-            process_item.appendRow(process_date_item)
-
-            process_descr = process.description
-            process_descr_item = QtGui.QStandardItem("Description: " + process_descr)
-            process_item.appendRow(process_descr_item)
-
-            process_name = process.name
-            process_name_item = QtGui.QStandardItem("Name: " + process_name)
-            process_item.appendRow(process_name_item)
-
-    info_item.appendRow(process_item)
-
-    return info_item
-
-def openLink(url):
-    """
-    Open a URL in an external browser.
-    Check the URL first, though.
-    """
-    parsed_url = urlparse.urlparse(url)
-    if parsed_url.scheme:
-        webbrowser.open(url)
-    else:
-        msg = "Attempt at opening an invalid URL"
-        raise AttributeError, msg
-
-def retrieveData1d(data):
-    """
-    Retrieve 1D data from file and construct its text
-    representation
-    """
-    if not isinstance(data, Data1D):
-        msg = "Incorrect type passed to retrieveData1d"
-        raise AttributeError, msg
-    try:
-        xmin = min(data.x)
-        ymin = min(data.y)
-    except:
-        msg = "Unable to find min/max of \n data named %s" % \
-                    data.filename
-        #logging.error(msg)
-        raise ValueError, msg
-
-    text = data.__str__()
-    text += 'Data Min Max:\n'
-    text += 'X_min = %s:  X_max = %s\n' % (xmin, max(data.x))
-    text += 'Y_min = %s:  Y_max = %s\n' % (ymin, max(data.y))
-    if data.dy != None:
-        text += 'dY_min = %s:  dY_max = %s\n' % (min(data.dy), max(data.dy))
-    text += '\nData Points:\n'
-    x_st = "X"
-    for index in range(len(data.x)):
-        if data.dy != None and len(data.dy) > index:
-            dy_val = data.dy[index]
-        else:
-            dy_val = 0.0
-        if data.dx != None and len(data.dx) > index:
-            dx_val = data.dx[index]
-        else:
-            dx_val = 0.0
-        if data.dxl != None and len(data.dxl) > index:
-            if index == 0:
-                x_st = "Xl"
-            dx_val = data.dxl[index]
-        elif data.dxw != None and len(data.dxw) > index:
-            if index == 0:
-                x_st = "Xw"
-            dx_val = data.dxw[index]
-
-        if index == 0:
-            text += "<index> \t<X> \t<Y> \t<dY> \t<d%s>\n" % x_st
-        text += "%s \t%s \t%s \t%s \t%s\n" % (index,
-                                                data.x[index],
-                                                data.y[index],
-                                                dy_val,
-                                                dx_val)
-    return text
-
-def retrieveData2d(data):
-    """
-    Retrieve 2D data from file and construct its text
-    representation
-    """
-    if not isinstance(data, Data2D):
-        msg = "Incorrect type passed to retrieveData2d"
-        raise AttributeError, msg
-
-    text = data.__str__()
-    text += 'Data Min Max:\n'
-    text += 'I_min = %s\n' % min(data.data)
-    text += 'I_max = %s\n\n' % max(data.data)
-    text += 'Data (First 2501) Points:\n'
-    text += 'Data columns include err(I).\n'
-    text += 'ASCII data starts here.\n'
-    text += "<index> \t<Qx> \t<Qy> \t<I> \t<dI> \t<dQparal> \t<dQperp>\n"
-    di_val = 0.0
-    dx_val = 0.0
-    dy_val = 0.0
-    len_data = len(data.qx_data)
-    for index in xrange(0, len_data):
-        x_val = data.qx_data[index]
-        y_val = data.qy_data[index]
-        i_val = data.data[index]
-        if data.err_data != None:
-            di_val = data.err_data[index]
-        if data.dqx_data != None:
-            dx_val = data.dqx_data[index]
-        if data.dqy_data != None:
-            dy_val = data.dqy_data[index]
-
-        text += "%s \t%s \t%s \t%s \t%s \t%s \t%s\n" % (index,
-                                                        x_val,
-                                                        y_val,
-                                                        i_val,
-                                                        di_val,
-                                                        dx_val,
-                                                        dy_val)
-        # Takes too long time for typical data2d: Break here
-        if index >= 2500:
-            text += ".............\n"
-            break
-
-    return text
-
-def onTXTSave(data, path):
-    """
-    Save file as formatted txt
-    """
-    with open(path,'w') as out:
-        has_errors = True
-        if data.dy == None or data.dy == []:
-            has_errors = False
-        # Sanity check
-        if has_errors:
-            try:
-                if len(data.y) != len(data.dy):
-                    has_errors = False
-            except:
-                has_errors = False
-        if has_errors:
-            if data.dx != None and data.dx != []:
-                out.write("<X>   <Y>   <dY>   <dX>\n")
-            else:
-                out.write("<X>   <Y>   <dY>\n")
-        else:
-            out.write("<X>   <Y>\n")
-
-        for i in range(len(data.x)):
-            if has_errors:
-                if data.dx != None and data.dx != []:
-                    if  data.dx[i] != None:
-                        out.write("%g  %g  %g  %g\n" % (data.x[i],
-                                                        data.y[i],
-                                                        data.dy[i],
-                                                        data.dx[i]))
-                    else:
-                        out.write("%g  %g  %g\n" % (data.x[i],
-                                                    data.y[i],
-                                                    data.dy[i]))
-                else:
-                    out.write("%g  %g  %g\n" % (data.x[i],
-                                                data.y[i],
-                                                data.dy[i]))
-            else:
-                out.write("%g  %g\n" % (data.x[i],
-                                        data.y[i]))
-
-def saveData1D(data):
-    """
-    Save 1D data points
-    """
-    default_name = os.path.basename(data.filename)
-    default_name, extension = os.path.splitext(default_name)
-    default_name += "_out" + extension
-
-    wildcard = "Text files (*.txt);;"\
-                "CanSAS 1D files(*.xml)"
-    kwargs = {
-        'caption'   : 'Save As',
-        'directory' : default_name,
-        'filter'    : wildcard,
-        'parent'    : None,
-    }
-    # Query user for filename.
-    filename = QtGui.QFileDialog.getSaveFileName(**kwargs)
-
-    # User cancelled.
-    if not filename:
-        return
-
-    filename = str(filename)
-
-    #Instantiate a loader
-    loader = Loader()
-    if os.path.splitext(filename)[1].lower() == ".txt":
-        onTXTSave(data, filename)
-    if os.path.splitext(filename)[1].lower() == ".xml":
-        loader.save(filename, data, ".xml")
-
-def saveData2D(data):
-    """
-    Save data2d dialog
-    """
-    default_name = os.path.basename(data.filename)
-    default_name, _ = os.path.splitext(default_name)
-    ext_format = ".dat"
-    default_name += "_out" + ext_format
-
-    wildcard = "IGOR/DAT 2D file in Q_map (*.dat)"
-    kwargs = {
-        'caption'   : 'Save As',
-        'directory' : default_name,
-        'filter'    : wildcard,
-        'parent'    : None,
-    }
-    # Query user for filename.
-    filename = QtGui.QFileDialog.getSaveFileName(**kwargs)
-
-    # User cancelled.
-    if not filename:
-        return
-    filename = str(filename)
-    #Instantiate a loader
-    loader = Loader()
-
-    if os.path.splitext(filename)[1].lower() == ext_format:
-        loader.save(filename, data, ext_format)
-
-class FormulaValidator(QtGui.QValidator):
-    def __init__(self, parent=None):
-        super(FormulaValidator, self).__init__(parent)
-  
-    def validate(self, input, pos):
-        try:
-            Formula(str(input))
-            self._setStyleSheet("")
-            return QtGui.QValidator.Acceptable, pos
-
-        except Exception as e:
-            self._setStyleSheet("background-color:pink;")
-            return QtGui.QValidator.Intermediate, pos
-
-    def _setStyleSheet(self, value):
-        try:
-            if self.parent():
-                self.parent().setStyleSheet(value)
-        except:
-            pass
-
-def xyTransform(data, xLabel="", yLabel=""):
-    """
-    Transforms x and y in View and set the scale
-    """
-    # Changing the scale might be incompatible with
-    # currently displayed data (for instance, going
-    # from ln to log when all plotted values have
-    # negative natural logs).
-    # Go linear and only change the scale at the end.
-    xscale = 'linear'
-    yscale = 'linear'
-    # Local data is either 1D or 2D
-    if data.id == 'fit':
-        return
-
-    # control axis labels from the panel itself
-    yname, yunits = data.get_yaxis()
-    xname, xunits = data.get_xaxis()
-
-    # Goes through all possible scales
-    # self.x_label is already wrapped with Latex "$", so using the argument
-
-    # X
-    if xLabel == "x":
-        data.transformX(transform.toX, transform.errToX)
-        xLabel = "%s(%s)" % (xname, xunits)
-    if xLabel == "x^(2)":
-        data.transformX(transform.toX2, transform.errToX2)
-        xunits = convert_unit(2, xunits)
-        xLabel = "%s^{2}(%s)" % (xname, xunits)
-    if xLabel == "x^(4)":
-        data.transformX(transform.toX4, transform.errToX4)
-        xunits = convert_unit(4, xunits)
-        xLabel = "%s^{4}(%s)" % (xname, xunits)
-    if xLabel == "ln(x)":
-        data.transformX(transform.toLogX, transform.errToLogX)
-        xLabel = "\ln{(%s)}(%s)" % (xname, xunits)
-    if xLabel == "log10(x)":
-        data.transformX(transform.toX_pos, transform.errToX_pos)
-        xscale = 'log'
-        xLabel = "%s(%s)" % (xname, xunits)
-    if xLabel == "log10(x^(4))":
-        data.transformX(transform.toX4, transform.errToX4)
-        xunits = convert_unit(4, xunits)
-        xLabel = "%s^{4}(%s)" % (xname, xunits)
-        xscale = 'log'
-
-    # Y
-    if yLabel == "ln(y)":
-        data.transformY(transform.toLogX, transform.errToLogX)
-        yLabel = "\ln{(%s)}(%s)" % (yname, yunits)
-    if yLabel == "y":
-        data.transformY(transform.toX, transform.errToX)
-        yLabel = "%s(%s)" % (yname, yunits)
-    if yLabel == "log10(y)":
-        data.transformY(transform.toX_pos, transform.errToX_pos)
-        yscale = 'log'
-        yLabel = "%s(%s)" % (yname, yunits)
-    if yLabel == "y^(2)":
-        data.transformY(transform.toX2, transform.errToX2)
-        yunits = convert_unit(2, yunits)
-        yLabel = "%s^{2}(%s)" % (yname, yunits)
-    if yLabel == "1/y":
-        data.transformY(transform.toOneOverX, transform.errOneOverX)
-        yunits = convert_unit(-1, yunits)
-        yLabel = "1/%s(%s)" % (yname, yunits)
-    if yLabel == "y*x^(2)":
-        data.transformY(transform.toYX2, transform.errToYX2)
-        xunits = convert_unit(2, xunits)
-        yLabel = "%s \ \ %s^{2}(%s%s)" % (yname, xname, yunits, xunits)
-    if yLabel == "y*x^(4)":
-        data.transformY(transform.toYX4, transform.errToYX4)
-        xunits = convert_unit(4, xunits)
-        yLabel = "%s \ \ %s^{4}(%s%s)" % (yname, xname, yunits, xunits)
-    if yLabel == "1/sqrt(y)":
-        data.transformY(transform.toOneOverSqrtX,
-                                transform.errOneOverSqrtX)
-        yunits = convert_unit(-0.5, yunits)
-        yLabel = "1/\sqrt{%s}(%s)" % (yname, yunits)
-    if yLabel == "ln(y*x)":
-        data.transformY(transform.toLogXY, transform.errToLogXY)
-        yLabel = "\ln{(%s \ \ %s)}(%s%s)" % (yname, xname, yunits, xunits)
-    if yLabel == "ln(y*x^(2))":
-        data.transformY(transform.toLogYX2, transform.errToLogYX2)
-        xunits = convert_unit(2, xunits)
-        yLabel = "\ln (%s \ \ %s^{2})(%s%s)" % (yname, xname, yunits, xunits)
-    if yLabel == "ln(y*x^(4))":
-        data.transformY(transform.toLogYX4, transform.errToLogYX4)
-        xunits = convert_unit(4, xunits)
-        yLabel = "\ln (%s \ \ %s^{4})(%s%s)" % (yname, xname, yunits, xunits)
-    if yLabel == "log10(y*x^(4))":
-        data.transformY(transform.toYX4, transform.errToYX4)
-        xunits = convert_unit(4, xunits)
-        yscale = 'log'
-        yLabel = "%s \ \ %s^{4}(%s%s)" % (yname, xname, yunits, xunits)
-
-    # Perform the transformation of data in data1d->View
-    data.transformView()
-
-    return (xLabel, yLabel, xscale, yscale)
-
-def dataFromItem(item):
-    """
-    Retrieve Data1D/2D component from QStandardItem.
-    The assumption - data stored in SasView standard, in child 0
-    """
-    return item.child(0).data().toPyObject()
-
-def formatNumber(value, high=False):
-    """
-    Return a float in a standardized, human-readable formatted string.
-    This is used to output readable (e.g. x.xxxe-y) values to the panel.
-    """
-    try:
-        value = float(value)
-    except:
-        output = "NaN"
-        return output.lstrip().rstrip()
-
-    if high:
-        output = "%-6.4g" % value
-
-    else:
-        output = "%-5.3g" % value
-    return output.lstrip().rstrip()
Index: c/sas/qtgui/IPythonWidget.py
===================================================================
--- src/sas/qtgui/IPythonWidget.py	(revision ff49d4d70a8ec63e6a8c37a7418fb61223560491)
+++ 	(revision )
@@ -1,28 +1,0 @@
-from qtconsole.rich_jupyter_widget import RichJupyterWidget
-from qtconsole.inprocess import QtInProcessKernelManager
-from IPython.lib import guisupport
-
-MODULES_TO_IMPORT = [
-    ('sas', 'sas'),
-    ('sasmodels', 'sasmodels'),
-    ('numpy', 'np')]
-
-class IPythonWidget(RichJupyterWidget):
-    def __init__(self, parent=None, **kwargs):
-        super(self.__class__, self).__init__(parent)
-        app = guisupport.get_app_qt4()
-
-       # Create an in-process kernel
-        kernel_manager = QtInProcessKernelManager()
-        kernel_manager.start_kernel()
-        kernel = kernel_manager.kernel
-        kernel.gui = 'qt4'
-
-        kernel_client = kernel_manager.client()
-        kernel_client.start_channels()
-
-        self.kernel_manager = kernel_manager
-        self.kernel_client = kernel_client
-
-        self.kernel_manager.kernel.shell.run_code(
-            '\n'.join('import %s as %s' % t for t in MODULES_TO_IMPORT))
Index: c/sas/qtgui/KiessigPanel.py
===================================================================
--- src/sas/qtgui/KiessigPanel.py	(revision 040529d59cec22934096b06caeb1e05dcbeb7f7f)
+++ 	(revision )
@@ -1,62 +1,0 @@
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-from UI.KiessigPanel import Ui_KiessigPanel
-
-# sas-global
-from sas.sascalc.calculator.kiessig_calculator import KiessigThicknessCalculator
-
-
-class KiessigPanel(QtGui.QDialog, Ui_KiessigPanel):
-    def __init__(self, parent=None):
-        super(KiessigPanel, self).__init__()
-        self.setupUi(self)
-
-        self.setWindowTitle("Kiessig Thickness Calculator")
-
-        self.manager = parent
-        self.thickness = KiessigThicknessCalculator()
-
-        self.deltaq_in.setText("0.05")
-
-        # signals
-        self.helpButton.clicked.connect(self.onHelp)
-        self.computeButton.clicked.connect(self.onCompute)
-        self.closeButton.clicked.connect(self.onClose)
-
-        # no reason to have this widget resizable
-        self.setFixedSize(self.minimumSizeHint())
-
-    def onHelp(self):
-        """
-        Bring up the Kiessig fringe calculator Documentation whenever
-        the HELP button is clicked.
-        Calls DocumentationWindow with the path of the location within the
-        documentation tree (after /doc/ ....".
-        """
-        try:
-            location = self.manager.HELP_DIRECTORY_LOCATION + \
-                "/user/sasgui/perspectives/calculator/kiessig_calculator_help.html"
-
-            self.manager._helpView.load(QtCore.QUrl(location))
-            self.manager._helpView.show()
-        except AttributeError:
-            # No manager defined - testing and standalone runs
-            pass
-
-    def onCompute(self):
-        """
-        Execute the computation of thickness
-        """
-        try:
-            self.thickness.set_deltaq(dq=float(self.deltaq_in.text()))
-            kiessing_result = self.thickness.compute_thickness()
-            float_as_str = "{:.3f}".format(kiessing_result)
-            self.lengthscale_out.setText(float_as_str)
-        except (ArithmeticError, ValueError):
-            self.lengthscale_out.setText("")
-
-    def onClose(self):
-        """
-        close the window containing this panel
-        """
-        self.close()
Index: c/sas/qtgui/LinearFit.py
===================================================================
--- src/sas/qtgui/LinearFit.py	(revision 2e3e95954828438b02ef55c47cd9553fe9a7a87a)
+++ 	(revision )
@@ -1,255 +1,0 @@
-"""
-Adds a linear fit plot to the chart
-"""
-import re
-import numpy
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-
-#from sas.sasgui.transform import 
-from sas.qtgui.GuiUtils import formatNumber
-from sas.sasgui.plottools import fittings
-from sas.sasgui.plottools import transform
-
-from sas.sasgui.plottools.LineModel import LineModel
-
-# Local UI
-from sas.qtgui.UI.LinearFitUI import Ui_LinearFitUI
-
-class LinearFit(QtGui.QDialog, Ui_LinearFitUI):
-    def __init__(self, parent=None,
-                 data=None,
-                 max_range=(0.0, 0.0),
-                 fit_range=(0.0, 0.0),
-                 xlabel="",
-                 ylabel=""):
-        super(LinearFit, self).__init__()
-
-        self.setupUi(self)
-        assert(isinstance(max_range, tuple))
-        assert(isinstance(fit_range, tuple))
-
-        self.data = data
-        self.parent = parent
-
-        self.max_range = max_range
-        self.fit_range = fit_range
-        self.xLabel = xlabel
-        self.yLabel = ylabel
-
-        self.x_is_log = self.xLabel == "log10(x)"
-        self.y_is_log = self.yLabel == "log10(y)"
-
-        self.txtFitRangeMin.setValidator(QtGui.QDoubleValidator())
-        self.txtFitRangeMax.setValidator(QtGui.QDoubleValidator())
-
-        # Default values in the line edits
-        self.txtA.setText("1")
-        self.txtB.setText("1")
-        self.txtAerr.setText("0")
-        self.txtBerr.setText("0")
-        self.txtChi2.setText("0")
-
-        # Initial ranges
-        self.txtRangeMin.setText(str(max_range[0]))
-        self.txtRangeMax.setText(str(max_range[1]))
-        self.txtFitRangeMin.setText(str(fit_range[0]))
-        self.txtFitRangeMax.setText(str(fit_range[1]))
-
-        # cast xLabel into html
-        label = re.sub(r'\^\((.)\)(.*)', r'<span style=" vertical-align:super;">\1</span>\2',
-                      str(self.xLabel).rstrip())
-        self.lblRange.setText('Fit range of ' + label)
-
-        self.model = LineModel()
-        # Display the fittings values
-        self.default_A = self.model.getParam('A')
-        self.default_B = self.model.getParam('B')
-        self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
-        self.cstB = fittings.Parameter(self.model, 'B', self.default_B)
-        self.transform = transform
-
-        self.setFixedSize(self.minimumSizeHint())
-
-        # connect Fit button
-        self.cmdFit.clicked.connect(self.fit)
-
-    def setRangeLabel(self, label=""):
-        """
-        Overwrite default fit range label to correspond to actual unit
-        """
-        assert(isinstance(label, basestring))
-        self.lblRange.setText(label)
-
-    def range(self):
-        return (float(self.txtFitRangeMin.text()), float(self.txtFitRangeMax.text()))
-
-    def fit(self, event):
-        """
-        Performs the fit. Receive an event when clicking on
-        the button Fit.Computes chisqr ,
-        A and B parameters of the best linear fit y=Ax +B
-        Push a plottable to the caller
-        """
-        tempx = []
-        tempy = []
-        tempdy = []
-
-        # Checks to assure data correctness
-        if len(self.data.view.x) < 2:
-            return
-        if not self.checkFitValues(self.txtFitRangeMin):
-            return
-
-        self.xminFit, self.xmaxFit = self.range()
-
-        xmin = self.xminFit
-        xmax = self.xmaxFit
-        xminView = xmin
-        xmaxView = xmax
-
-        # Set the qmin and qmax in the panel that matches the
-        # transformed min and max
-        #value_xmin = X_VAL_DICT[self.xLabel].floatTransform(xmin)
-        #value_xmax = X_VAL_DICT[self.xLabel].floatTransform(xmax)
-
-        value_xmin = self.floatInvTransform(xmin)
-        value_xmax = self.floatInvTransform(xmax)
-        self.txtRangeMin.setText(formatNumber(value_xmin))
-        self.txtRangeMax.setText(formatNumber(value_xmax))
-
-        tempx, tempy, tempdy = self.origData()
-
-        # Find the fitting parameters
-        self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
-        self.cstB = fittings.Parameter(self.model, 'B', self.default_B)
-        tempdy = numpy.asarray(tempdy)
-        tempdy[tempdy == 0] = 1
-
-        if self.x_is_log:
-            xmin = numpy.log10(xmin)
-            xmax = numpy.log10(xmax)
-
-        chisqr, out, cov = fittings.sasfit(self.model,
-                                           [self.cstA, self.cstB],
-                                           tempx, tempy, tempdy,
-                                           xmin, xmax)
-        # Use chi2/dof
-        if len(tempx) > 0:
-            chisqr = chisqr / len(tempx)
-
-        # Check that cov and out are iterable before displaying them
-        errA = numpy.sqrt(cov[0][0]) if cov is not None else 0
-        errB = numpy.sqrt(cov[1][1]) if cov is not None else 0
-        cstA = out[0] if out is not None else 0.0
-        cstB = out[1] if out is not None else 0.0
-
-        # Reset model with the right values of A and B
-        self.model.setParam('A', float(cstA))
-        self.model.setParam('B', float(cstB))
-
-        tempx = []
-        tempy = []
-        y_model = 0.0
-
-        # load tempy with the minimum transformation
-        y_model = self.model.run(xmin)
-        tempx.append(xminView)
-        tempy.append(numpy.power(10, y_model) if self.y_is_log else y_model)
-
-        # load tempy with the maximum transformation
-        y_model = self.model.run(xmax)
-        tempx.append(xmaxView)
-        tempy.append(numpy.power(10, y_model) if self.y_is_log else y_model)
-
-        # Set the fit parameter display when  FitDialog is opened again
-        self.Avalue = cstA
-        self.Bvalue = cstB
-        self.ErrAvalue = errA
-        self.ErrBvalue = errB
-        self.Chivalue = chisqr
-
-        # Update the widget
-        self.txtA.setText(formatNumber(self.Avalue))
-        self.txtAerr.setText(formatNumber(self.ErrAvalue))
-        self.txtB.setText(formatNumber(self.Bvalue))
-        self.txtBerr.setText(formatNumber(self.ErrBvalue))
-        self.txtChi2.setText(formatNumber(self.Chivalue))
-
-        #self.parent.updatePlot.emit((tempx, tempy))
-        self.parent.emit(QtCore.SIGNAL('updatePlot'), (tempx, tempy))
-
-    def origData(self):
-        # Store the transformed values of view x, y and dy before the fit
-        xmin_check = numpy.log10(self.xminFit)
-        # Local shortcuts
-        x = self.data.view.x
-        y = self.data.view.y
-        dy = self.data.view.dy
-
-        if self.y_is_log:
-            if self.x_is_log:
-                tempy  = [numpy.log10(y[i])
-                         for i in range(len(x)) if x[i] >= xmin_check]
-                tempdy = [transform.errToLogX(y[i], 0, dy[i], 0)
-                         for i in range(len(x)) if x[i] >= xmin_check]
-            else:
-                tempy = map(numpy.log10, y)
-                tempdy = map(lambda t1,t2:transform.errToLogX(t1,0,t2,0),y,dy)
-        else:
-            tempy = y
-            tempdy = dy
-
-        if self.x_is_log:
-            tempx = [numpy.log10(x) for x in self.data.view.x if x > xmin_check]
-        else:
-            tempx = x
-
-        return tempx, tempy, tempdy
-
-    def checkFitValues(self, item):
-        """
-        Check the validity of input values
-        """
-        flag = True
-        value = item.text()
-        p_white = item.palette()
-        p_white.setColor(item.backgroundRole(), QtCore.Qt.white)
-        p_pink = item.palette()
-        p_pink.setColor(item.backgroundRole(), QtGui.QColor(255, 128, 128))
-        item.setAutoFillBackground(True)
-        # Check for possible values entered
-        if self.x_is_log:
-            if float(value) > 0:
-                item.setPalette(p_white)
-            else:
-                flag = False
-                item.setPalette(p_pink)
-        return flag
-
-    def floatInvTransform(self, x):
-        """
-        transform a float.It is used to determine the x.View min and x.View
-        max for values not in x.  Also used to properly calculate RgQmin,
-        RgQmax and to update qmin and qmax in the linear range boxes on the
-        panel.
-
-        """
-        # TODO: refactor this. This is just a hack to make the
-        # functionality work without rewritting the whole code
-        # with good design (which really should be done...).
-        if self.xLabel == "x":
-            return x
-        elif self.xLabel == "x^(2)":
-            return numpy.sqrt(x)
-        elif self.xLabel == "x^(4)":
-            return numpy.sqrt(numpy.sqrt(x))
-        elif self.xLabel == "log10(x)":
-            return numpy.power(10, x)
-        elif self.xLabel == "ln(x)":
-            return numpy.exp(x)
-        elif self.xLabel == "log10(x^(4))":
-            return numpy.sqrt(numpy.sqrt(numpy.power(10, x)))
-        return x
-
-
Index: c/sas/qtgui/LocalConfig.py
===================================================================
--- src/sas/qtgui/LocalConfig.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,147 +1,0 @@
-"""
-    Application settings
-"""
-import time
-import os
-import logging
-
-from sas.sasgui.guiframe.gui_style import GUIFRAME
-import sas.sasview
-
-# Version of the application
-__appname__ = "SasView"
-__version__ = sas.sasview.__version__
-__build__ = sas.sasview.__build__
-__download_page__ = 'https://github.com/SasView/sasview/releases'
-__update_URL__ = 'http://www.sasview.org/latestversion.json'
-
-# Debug message flag
-__EVT_DEBUG__ = False
-
-# Flag for automated testing
-__TEST__ = False
-
-# Debug message should be written to a file?
-__EVT_DEBUG_2_FILE__ = False
-__EVT_DEBUG_FILENAME__ = "debug.log"
-
-# About box info
-_do_aboutbox = True
-_do_acknowledge = True
-_do_tutorial = True
-_acknowledgement_preamble =\
-'''To ensure the long term support and development of this software please''' +\
-''' remember to do the following.'''
-_acknowledgement_preamble_bullet1 =\
-'''Acknowledge its use in your publications as suggested below'''
-_acknowledgement_preamble_bullet2 =\
-'''Reference the following website: http://www.sasview.org'''
-_acknowledgement_preamble_bullet3 =\
-'''Reference the model you used if appropriate (see documentation for refs)'''
-_acknowledgement_preamble_bullet4 =\
-'''Send us your reference for our records: developers@sasview.org'''
-_acknowledgement_publications = \
-'''This work benefited from the use of the SasView application, originally
-developed under NSF award DMR-0520547.
-'''
-_acknowledgement =  \
-'''This work originally developed as part of the DANSE project funded by the NSF
-under grant DMR-0520547, and currently maintained by NIST, UMD, ORNL, ISIS, ESS
-and ILL.
-
-'''
-_homepage = "http://www.sasview.org"
-_download = __download_page__
-_authors = []
-_paper = "http://sourceforge.net/p/sasview/tickets/"
-_license = "mailto:help@sasview.org"
-
-icon_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "images"))
-
-#logging.info("icon path: %s", icon_path)
-
-media_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "media"))
-test_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "test"))
-
-_nist_logo = os.path.join(icon_path, "nist_logo.png")
-_umd_logo = os.path.join(icon_path, "umd_logo.png")
-_sns_logo = os.path.join(icon_path, "sns_logo.png")
-_isis_logo = os.path.join(icon_path, "isis_logo.png")
-_ess_logo = os.path.join(icon_path, "ess_logo.png")
-_ill_logo = os.path.join(icon_path, "ill_logo.png")
-_ansto_logo = os.path.join(icon_path, "ansto_logo.png")
-_nsf_logo = os.path.join(icon_path, "nsf_logo.png")
-_danse_logo = os.path.join(icon_path, "danse_logo.png")
-_inst_logo = os.path.join(icon_path, "utlogo.gif")
-_nist_url = "http://www.nist.gov/"
-_umd_url = "http://www.umd.edu/"
-_sns_url = "http://neutrons.ornl.gov/"
-_nsf_url = "http://www.nsf.gov"
-_isis_url = "http://www.isis.stfc.ac.uk/"
-_ess_url = "http://ess-scandinavia.eu/"
-_ill_url = "http://www.ill.eu/"
-_ansto_url = "http://www.ansto.gov.au/"
-_danse_url = "http://www.cacr.caltech.edu/projects/danse/release/index.html"
-_inst_url = "http://www.utk.edu"
-_corner_image = os.path.join(icon_path, "angles_flat.png")
-_welcome_image = os.path.join(icon_path, "SVwelcome.png")
-_copyright = "(c) 2009 - 2013, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL and ANSTO"
-
-
-#edit the list of file state your plugin can read
-APPLICATION_WLIST = 'SasView files (*.svs)|*.svs'
-APPLICATION_STATE_EXTENSION = '.svs'
-GUIFRAME_WIDTH = 1150
-GUIFRAME_HEIGHT = 840
-PLUGIN_STATE_EXTENSIONS = ['.fitv', '.inv', '.prv']
-PLUGINS_WLIST = ['Fitting files (*.fitv)|*.fitv',
-                 'Invariant files (*.inv)|*.inv',
-                 'P(r) files (*.prv)|*.prv']
-PLOPANEL_WIDTH = 415
-PLOPANEL_HEIGTH = 370
-DATAPANEL_WIDTH = 235
-DATAPANEL_HEIGHT = 700
-SPLASH_SCREEN_PATH = os.path.join(icon_path, "SVwelcome_mini.png")
-TUTORIAL_PATH = os.path.join(media_path, "Tutorial.pdf")
-DEFAULT_STYLE = GUIFRAME.MULTIPLE_APPLICATIONS|GUIFRAME.MANAGER_ON\
-                    |GUIFRAME.CALCULATOR_ON|GUIFRAME.TOOLBAR_ON
-SPLASH_SCREEN_WIDTH = 512
-SPLASH_SCREEN_HEIGHT = 366
-SS_MAX_DISPLAY_TIME = 2000
-WELCOME_PANEL_ON = True
-WELCOME_PANEL_SHOW = False
-CLEANUP_PLOT = False
-# OPEN and SAVE project menu
-OPEN_SAVE_PROJECT_MENU = True
-#VIEW MENU
-VIEW_MENU = True
-#EDIT MENU
-EDIT_MENU = True
-
-SetupIconFile_win = os.path.join(icon_path, "ball.ico")
-SetupIconFile_mac = os.path.join(icon_path, "ball.icns")
-DefaultGroupName = "."
-OutputBaseFilename = "setupSasView"
-
-FIXED_PANEL = True
-DATALOADER_SHOW = True
-CLEANUP_PLOT = False
-WELCOME_PANEL_SHOW = False
-#Show or hide toolbar at the start up
-TOOLBAR_SHOW = True
-# set a default perspective
-DEFAULT_PERSPECTIVE = 'None'
-
-# Time out for updating sasview
-UPDATE_TIMEOUT = 2
-def printEVT(message):
-    """
-    Post a debug message to console/file
-    """
-    if __EVT_DEBUG__:
-        print "%g:  %s" % (time.clock(), message)
-
-        if __EVT_DEBUG_2_FILE__:
-            out = open(__EVT_DEBUG_FILENAME__, 'a')
-            out.write("%10g:  %s\n" % (time.clock(), message))
-            out.close()
Index: c/sas/qtgui/MainWindow.py
===================================================================
--- src/sas/qtgui/MainWindow.py	(revision 6fd4e36d87aa2c634f1fe31123e473984cad066c)
+++ 	(revision )
@@ -1,69 +1,0 @@
-# UNLESS EXEPTIONALLY REQUIRED TRY TO AVOID IMPORTING ANY MODULES HERE
-# ESPECIALLY ANYTHING IN SAS, SASMODELS NAMESPACE
-from PyQt4 import QtGui
-
-# Local UI
-from UI.MainWindowUI import Ui_MainWindow
-
-# Initialize logging
-import SasviewLogger
-
-class MainSasViewWindow(QtGui.QMainWindow, Ui_MainWindow):
-    # Main window of the application
-    def __init__(self, parent=None):
-        super(MainSasViewWindow, self).__init__(parent)
-        self.setupUi(self)
-
-        # define workspace for dialogs.
-        self.workspace = QtGui.QWorkspace(self)
-        self.setCentralWidget(self.workspace)
-
-        # Create the gui manager
-        from GuiManager import GuiManager
-        self.guiManager = GuiManager(self)
-
-    def closeEvent(self, event):
-        if self.guiManager.quitApplication():
-            event.accept()
-        else:
-            event.ignore()
-
-
-def SplashScreen():
-    """
-    Displays splash screen as soon as humanely possible.
-    The screen will disappear as soon as the event loop starts.
-    """
-    # TODO: standardize path to images
-    pixmap = QtGui.QPixmap("src/sas/qtgui/images/SVwelcome_mini.png")
-    splashScreen = QtGui.QSplashScreen(pixmap)
-    return splashScreen
-
-def run():
-    app = QtGui.QApplication([])
-
-    # Main must have reference to the splash screen, so making it explicit
-    splash = SplashScreen()
-    splash.show()
-
-    # DO NOT move the following import to the top!
-    # (unless you know what you're doing)
-    import qt4reactor
-    # Using the Qt4 reactor wrapper from https://github.com/ghtdak/qtreactor
-    qt4reactor.install()
-
-    # DO NOT move the following import to the top!
-    from twisted.internet import reactor
-
-    # Show the main SV window
-    mainwindow = MainSasViewWindow()
-    mainwindow.showMaximized()
-
-    # no more splash screen
-    splash.finish(mainwindow)
-
-    # No need to .exec_ - the reactor takes care of it.
-    reactor.run()
-
-if __name__ == "__main__":
-    run()
Index: src/sas/qtgui/MainWindow/AboutBox.py
===================================================================
--- src/sas/qtgui/MainWindow/AboutBox.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/AboutBox.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,65 @@
+import functools
+from PyQt4 import QtGui
+
+import sas.sasview
+import sas.qtgui.Utilities.LocalConfig as LocalConfig
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+
+from UI.AboutUI import Ui_AboutUI
+
+class AboutBox(QtGui.QDialog, Ui_AboutUI):
+    def __init__(self, parent=None):
+        super(AboutBox, self).__init__(parent)
+        self.setupUi(self)
+
+        self.setWindowTitle("About")
+
+        self.addText()
+
+        self.addActions()
+
+    def addText(self):
+        """
+        Modify the labels so the text corresponds to the current version
+        """
+        version = sas.sasview.__version__
+
+        self.lblVersion.setText(str(version))
+        lbl_font = self.font()
+        lbl_font.setPointSize(24)
+        self.lblVersion.setFont(lbl_font)
+        about_text = r'<html><head/><body><p>'
+        about_text += '<p>Build ' + str(LocalConfig.__build__) +'</p>'
+        about_text += '<p>' + LocalConfig._copyright + '</p>'
+        about_text += r'<p><a href=http://www.sasview.org>http://www.sasview.org</a></p><br/>'
+        about_text += '<p>Comments? Bugs? Requests?<br/>'
+        about_text += r'<a href=mailto:help@sasview.org>Send us a ticket</a></p><br/>'
+        about_text += r'<a href=' + str(LocalConfig.__download_page__)\
+                   + 'Get the latest version</a></p><br/>'
+        self.lblAbout.setText(about_text)
+
+        # Enable link clicking on the label
+        self.lblAbout.setOpenExternalLinks(True)
+
+    def addActions(self):
+        """
+        Add actions to the logo push buttons
+        """
+        self.cmdLinkUT.clicked.connect(functools.partial(
+            GuiUtils.openLink, LocalConfig._inst_url))
+        self.cmdLinkUMD.clicked.connect(functools.partial(
+            GuiUtils.openLink, LocalConfig._umd_url))
+        self.cmdLinkNIST.clicked.connect(functools.partial(
+            GuiUtils.openLink, LocalConfig._nist_url))
+        self.cmdLinkSNS.clicked.connect(functools.partial(
+            GuiUtils.openLink, LocalConfig._sns_url))
+        self.cmdLinkISIS.clicked.connect(functools.partial(
+            GuiUtils.openLink, LocalConfig._isis_url))
+        self.cmdLinkESS.clicked.connect(functools.partial(
+            GuiUtils.openLink, LocalConfig._ess_url))
+        self.cmdLinkILL.clicked.connect(functools.partial(
+            GuiUtils.openLink, LocalConfig._ill_url))
+        self.cmdLinkANSTO.clicked.connect(functools.partial(
+            GuiUtils.openLink, LocalConfig._ansto_url))
+
+        self.cmdOK.clicked.connect(self.close)
Index: src/sas/qtgui/MainWindow/DataExplorer.py
===================================================================
--- src/sas/qtgui/MainWindow/DataExplorer.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/DataExplorer.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,1011 @@
+# global
+import sys
+import os
+import time
+import logging
+
+from PyQt4 import QtCore
+from PyQt4 import QtGui
+from PyQt4 import QtWebKit
+from PyQt4.Qt import QMutex
+
+from twisted.internet import threads
+
+# SAS
+from sas.sascalc.dataloader.loader import Loader
+from sas.sasgui.guiframe.data_manager import DataManager
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+import sas.qtgui.Plotting.PlotHelper as PlotHelper
+from sas.qtgui.Plotting.Plotter import Plotter
+from sas.qtgui.Plotting.Plotter2D import Plotter2D
+from sas.qtgui.MainWindow.DroppableDataLoadWidget import DroppableDataLoadWidget
+from sas.qtgui.Plotting.MaskEditor import MaskEditor
+
+import sas.qtgui.Perspectives as Perspectives
+
+class DataExplorerWindow(DroppableDataLoadWidget):
+    # The controller which is responsible for managing signal slots connections
+    # for the gui and providing an interface to the data model.
+
+    def __init__(self, parent=None, guimanager=None, manager=None):
+        super(DataExplorerWindow, self).__init__(parent, guimanager)
+
+        # Main model for keeping loaded data
+        self.model = QtGui.QStandardItemModel(self)
+
+        # Secondary model for keeping frozen data sets
+        self.theory_model = QtGui.QStandardItemModel(self)
+
+        # GuiManager is the actual parent, but we needed to also pass the QMainWindow
+        # in order to set the widget parentage properly.
+        self.parent = guimanager
+        self.loader = Loader()
+        self.manager = manager if manager is not None else DataManager()
+        self.txt_widget = QtGui.QTextEdit(None)
+
+        # Be careful with twisted threads.
+        self.mutex = QMutex()
+
+        # Active plots
+        self.active_plots = {}
+
+        # Connect the buttons
+        self.cmdLoad.clicked.connect(self.loadFile)
+        self.cmdDeleteData.clicked.connect(self.deleteFile)
+        self.cmdDeleteTheory.clicked.connect(self.deleteTheory)
+        self.cmdFreeze.clicked.connect(self.freezeTheory)
+        self.cmdSendTo.clicked.connect(self.sendData)
+        self.cmdNew.clicked.connect(self.newPlot)
+        self.cmdNew_2.clicked.connect(self.newPlot)
+        self.cmdAppend.clicked.connect(self.appendPlot)
+        self.cmdHelp.clicked.connect(self.displayHelp)
+        self.cmdHelp_2.clicked.connect(self.displayHelp)
+
+        # Display HTML content
+        self._helpView = QtWebKit.QWebView()
+
+        # Fill in the perspectives combo
+        self.initPerspectives()
+
+        # Custom context menu
+        self.treeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
+        self.treeView.customContextMenuRequested.connect(self.onCustomContextMenu)
+        self.contextMenu()
+
+        # Same menus for the theory view
+        self.freezeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
+        self.freezeView.customContextMenuRequested.connect(self.onCustomContextMenu)
+
+        # Connect the comboboxes
+        self.cbSelect.currentIndexChanged.connect(self.selectData)
+
+        #self.closeEvent.connect(self.closeEvent)
+        self.currentChanged.connect(self.onTabSwitch)
+        self.communicator = self.parent.communicator()
+        self.communicator.fileReadSignal.connect(self.loadFromURL)
+        self.communicator.activeGraphsSignal.connect(self.updateGraphCombo)
+        self.communicator.activeGraphName.connect(self.updatePlotName)
+        self.communicator.plotUpdateSignal.connect(self.updatePlot)
+        self.cbgraph.editTextChanged.connect(self.enableGraphCombo)
+        self.cbgraph.currentIndexChanged.connect(self.enableGraphCombo)
+
+        # Proxy model for showing a subset of Data1D/Data2D content
+        self.data_proxy = QtGui.QSortFilterProxyModel(self)
+        self.data_proxy.setSourceModel(self.model)
+
+        # Don't show "empty" rows with data objects
+        self.data_proxy.setFilterRegExp(r"[^()]")
+
+        # The Data viewer is QTreeView showing the proxy model
+        self.treeView.setModel(self.data_proxy)
+
+        # Proxy model for showing a subset of Theory content
+        self.theory_proxy = QtGui.QSortFilterProxyModel(self)
+        self.theory_proxy.setSourceModel(self.theory_model)
+
+        # Don't show "empty" rows with data objects
+        self.theory_proxy.setFilterRegExp(r"[^()]")
+
+        # Theory model view
+        self.freezeView.setModel(self.theory_proxy)
+
+        self.enableGraphCombo(None)
+
+        # Current view on model
+        self.current_view = self.treeView
+
+    def closeEvent(self, event):
+        """
+        Overwrite the close event - no close!
+        """
+        event.ignore()
+
+    def onTabSwitch(self, index):
+        """ Callback for tab switching signal """
+        if index == 0:
+            self.current_view = self.treeView
+        else:
+            self.current_view = self.freezeView
+
+    def displayHelp(self):
+        """
+        Show the "Loading data" section of help
+        """
+        tree_location = self.parent.HELP_DIRECTORY_LOCATION +\
+            "/user/sasgui/guiframe/data_explorer_help.html"
+        self._helpView.load(QtCore.QUrl(tree_location))
+        self._helpView.show()
+
+    def enableGraphCombo(self, combo_text):
+        """
+        Enables/disables "Assign Plot" elements
+        """
+        self.cbgraph.setEnabled(len(PlotHelper.currentPlots()) > 0)
+        self.cmdAppend.setEnabled(len(PlotHelper.currentPlots()) > 0)
+
+    def initPerspectives(self):
+        """
+        Populate the Perspective combobox and define callbacks
+        """
+        available_perspectives = sorted([p for p in Perspectives.PERSPECTIVES.keys()])
+        if available_perspectives:
+            self.cbFitting.clear()
+            self.cbFitting.addItems(available_perspectives)
+        self.cbFitting.currentIndexChanged.connect(self.updatePerspectiveCombo)
+        # Set the index so we see the default (Fitting)
+        self.updatePerspectiveCombo(0)
+
+    def _perspective(self):
+        """
+        Returns the current perspective
+        """
+        return self.parent.perspective()
+
+    def loadFromURL(self, url):
+        """
+        Threaded file load
+        """
+        load_thread = threads.deferToThread(self.readData, url)
+        load_thread.addCallback(self.loadComplete)
+
+    def loadFile(self, event=None):
+        """
+        Called when the "Load" button pressed.
+        Opens the Qt "Open File..." dialog
+        """
+        path_str = self.chooseFiles()
+        if not path_str:
+            return
+        self.loadFromURL(path_str)
+
+    def loadFolder(self, event=None):
+        """
+        Called when the "File/Load Folder" menu item chosen.
+        Opens the Qt "Open Folder..." dialog
+        """
+        folder = QtGui.QFileDialog.getExistingDirectory(self, "Choose a directory", "",
+              QtGui.QFileDialog.ShowDirsOnly | QtGui.QFileDialog.DontUseNativeDialog)
+        if folder is None:
+            return
+
+        folder = str(folder)
+
+        if not os.path.isdir(folder):
+            return
+
+        # get content of dir into a list
+        path_str = [os.path.join(os.path.abspath(folder), filename)
+                    for filename in os.listdir(folder)]
+
+        self.loadFromURL(path_str)
+
+    def loadProject(self):
+        """
+        Called when the "Open Project" menu item chosen.
+        """
+        kwargs = {
+            'parent'    : self,
+            'caption'   : 'Open Project',
+            'filter'    : 'Project (*.json);;All files (*.*)',
+            'options'   : QtGui.QFileDialog.DontUseNativeDialog
+        }
+        filename = str(QtGui.QFileDialog.getOpenFileName(**kwargs))
+        if filename:
+            load_thread = threads.deferToThread(self.readProject, filename)
+            load_thread.addCallback(self.readProjectComplete)
+
+    def readProject(self, filename):
+        self.communicator.statusBarUpdateSignal.emit("Loading Project... %s" % os.path.basename(filename))
+        try:
+            manager = DataManager()
+            with open(filename, 'r') as infile:
+                manager.load_from_readable(infile)
+
+            self.communicator.statusBarUpdateSignal.emit("Loaded Project: %s" % os.path.basename(filename))
+            return manager
+
+        except:
+            self.communicator.statusBarUpdateSignal.emit("Failed: %s" % os.path.basename(filename))
+            raise
+
+    def readProjectComplete(self, manager):
+        self.model.clear()
+
+        self.manager.assign(manager)
+        for id, item in self.manager.get_all_data().iteritems():
+            self.updateModel(item.data, item.path)
+
+        self.model.reset()
+
+    def saveProject(self):
+        """
+        Called when the "Save Project" menu item chosen.
+        """
+        kwargs = {
+            'parent'    : self,
+            'caption'   : 'Save Project',
+            'filter'    : 'Project (*.json)',
+            'options'   : QtGui.QFileDialog.DontUseNativeDialog
+        }
+        filename = str(QtGui.QFileDialog.getSaveFileName(**kwargs))
+        if filename:
+            self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename))
+            with open(filename, 'w') as outfile:
+                self.manager.save_to_writable(outfile)
+
+    def deleteFile(self, event):
+        """
+        Delete selected rows from the model
+        """
+        # Assure this is indeed wanted
+        delete_msg = "This operation will delete the checked data sets and all the dependents." +\
+                     "\nDo you want to continue?"
+        reply = QtGui.QMessageBox.question(self,
+                                           'Warning',
+                                           delete_msg,
+                                           QtGui.QMessageBox.Yes,
+                                           QtGui.QMessageBox.No)
+
+        if reply == QtGui.QMessageBox.No:
+            return
+
+        # Figure out which rows are checked
+        ind = -1
+        # Use 'while' so the row count is forced at every iteration
+        while ind < self.model.rowCount():
+            ind += 1
+            item = self.model.item(ind)
+            if item and item.isCheckable() and item.checkState() == QtCore.Qt.Checked:
+                # Delete these rows from the model
+                self.model.removeRow(ind)
+                # Decrement index since we just deleted it
+                ind -= 1
+
+        # pass temporarily kept as a breakpoint anchor
+        pass
+
+    def deleteTheory(self, event):
+        """
+        Delete selected rows from the theory model
+        """
+        # Assure this is indeed wanted
+        delete_msg = "This operation will delete the checked data sets and all the dependents." +\
+                     "\nDo you want to continue?"
+        reply = QtGui.QMessageBox.question(self,
+                                           'Warning',
+                                           delete_msg,
+                                           QtGui.QMessageBox.Yes,
+                                           QtGui.QMessageBox.No)
+
+        if reply == QtGui.QMessageBox.No:
+            return
+
+        # Figure out which rows are checked
+        ind = -1
+        # Use 'while' so the row count is forced at every iteration
+        while ind < self.theory_model.rowCount():
+            ind += 1
+            item = self.theory_model.item(ind)
+            if item and item.isCheckable() and item.checkState() == QtCore.Qt.Checked:
+                # Delete these rows from the model
+                self.theory_model.removeRow(ind)
+                # Decrement index since we just deleted it
+                ind -= 1
+
+        # pass temporarily kept as a breakpoint anchor
+        pass
+
+    def sendData(self, event):
+        """
+        Send selected item data to the current perspective and set the relevant notifiers
+        """
+        # Set the signal handlers
+        self.communicator.updateModelFromPerspectiveSignal.connect(self.updateModelFromPerspective)
+
+        def isItemReady(index):
+            item = self.model.item(index)
+            return item.isCheckable() and item.checkState() == QtCore.Qt.Checked
+
+        # Figure out which rows are checked
+        selected_items = [self.model.item(index)
+                          for index in xrange(self.model.rowCount())
+                          if isItemReady(index)]
+
+        if len(selected_items) < 1:
+            return
+
+        # Which perspective has been selected?
+        if len(selected_items) > 1 and not self._perspective().allowBatch():
+            msg = self._perspective().title() + " does not allow multiple data."
+            msgbox = QtGui.QMessageBox()
+            msgbox.setIcon(QtGui.QMessageBox.Critical)
+            msgbox.setText(msg)
+            msgbox.setStandardButtons(QtGui.QMessageBox.Ok)
+            retval = msgbox.exec_()
+            return
+
+        # Notify the GuiManager about the send request
+        self._perspective().setData(data_item=selected_items)
+
+    def freezeTheory(self, event):
+        """
+        Freeze selected theory rows.
+
+        "Freezing" means taking the plottable data from the Theory item
+        and copying it to a separate top-level item in Data.
+        """
+        # Figure out which rows are checked
+        # Use 'while' so the row count is forced at every iteration
+        outer_index = -1
+        theories_copied = 0
+        while outer_index < self.theory_model.rowCount():
+            outer_index += 1
+            outer_item = self.theory_model.item(outer_index)
+            if not outer_item:
+                continue
+            if outer_item.isCheckable() and \
+                   outer_item.checkState() == QtCore.Qt.Checked:
+                theories_copied += 1
+                new_item = self.recursivelyCloneItem(outer_item)
+                # Append a "unique" descriptor to the name
+                time_bit = str(time.time())[7:-1].replace('.', '')
+                new_name = new_item.text() + '_@' + time_bit
+                new_item.setText(new_name)
+                self.model.appendRow(new_item)
+            self.model.reset()
+
+        freeze_msg = ""
+        if theories_copied == 0:
+            return
+        elif theories_copied == 1:
+            freeze_msg = "1 theory copied from the Theory tab as a data set"
+        elif theories_copied > 1:
+            freeze_msg = "%i theories copied from the Theory tab as data sets" % theories_copied
+        else:
+            freeze_msg = "Unexpected number of theories copied: %i" % theories_copied
+            raise AttributeError, freeze_msg
+        self.communicator.statusBarUpdateSignal.emit(freeze_msg)
+        # Actively switch tabs
+        self.setCurrentIndex(1)
+
+    def recursivelyCloneItem(self, item):
+        """
+        Clone QStandardItem() object
+        """
+        new_item = item.clone()
+        # clone doesn't do deepcopy :(
+        for child_index in xrange(item.rowCount()):
+            child_item = self.recursivelyCloneItem(item.child(child_index))
+            new_item.setChild(child_index, child_item)
+        return new_item
+
+    def updatePlotName(self, name_tuple):
+        """
+        Modify the name of the current plot
+        """
+        old_name, current_name = name_tuple
+        ind = self.cbgraph.findText(old_name)
+        self.cbgraph.setCurrentIndex(ind)
+        self.cbgraph.setItemText(ind, current_name)
+
+    def updateGraphCombo(self, graph_list):
+        """
+        Modify Graph combo box on graph add/delete
+        """
+        orig_text = self.cbgraph.currentText()
+        self.cbgraph.clear()
+        #graph_titles= [str(graph) for graph in graph_list]
+
+        #self.cbgraph.insertItems(0, graph_titles)
+        self.cbgraph.insertItems(0, graph_list)
+        ind = self.cbgraph.findText(orig_text)
+        if ind > 0:
+            self.cbgraph.setCurrentIndex(ind)
+
+    def updatePerspectiveCombo(self, index):
+        """
+        Notify the gui manager about the new perspective chosen.
+        """
+        self.communicator.perspectiveChangedSignal.emit(self.cbFitting.currentText())
+        self.chkBatch.setEnabled(self.parent.perspective().allowBatch())
+
+    def newPlot(self):
+        """
+        Create a new matplotlib chart from selected data
+        """
+        # Check which tab is currently active
+        if self.current_view == self.treeView:
+            plots = GuiUtils.plotsFromCheckedItems(self.model)
+        else:
+            plots = GuiUtils.plotsFromCheckedItems(self.theory_model)
+
+        # Call show on requested plots
+        # All same-type charts in one plot
+        new_plot = Plotter(self)
+
+        def addDataPlot2D(plot_set, item):
+            plot2D = Plotter2D(self)
+            plot2D.item = item
+            plot2D.plot(plot_set)
+            self.plotAdd(plot2D)
+            #============================================
+            ## Attach silx
+            #from silx.gui import qt
+            #from silx.gui.plot import StackView
+            #sv = StackView()
+            #sv.setColormap("jet", autoscale=True)
+            #sv.setStack(plot_set.data.reshape(1,100,100))
+            ##sv.setLabels(["x: -10 to 10 (200 samples)",
+            ##              "y: -10 to 5 (150 samples)"])
+            #sv.show()
+            #============================================
+
+        for item, plot_set in plots:
+            if isinstance(plot_set, Data1D):
+                new_plot.plot(plot_set)
+            elif isinstance(plot_set, Data2D):
+                addDataPlot2D(plot_set, item)
+            else:
+                msg = "Incorrect data type passed to Plotting"
+                raise AttributeError, msg
+
+        if plots and \
+            hasattr(new_plot, 'data') and \
+            isinstance(new_plot.data, Data1D):
+                self.plotAdd(new_plot)
+
+    def plotAdd(self, new_plot):
+        """
+        Helper method for plot bookkeeping
+        """
+        # Update the global plot counter
+        title = str(PlotHelper.idOfPlot(new_plot))
+        new_plot.setWindowTitle(title)
+
+        # Add the plot to the workspace
+        self.parent.workspace().addWindow(new_plot)
+
+        # Show the plot
+        new_plot.show()
+
+        # Update the active chart list
+        self.active_plots[new_plot.data.id] = new_plot
+
+    def appendPlot(self):
+        """
+        Add data set(s) to the existing matplotlib chart
+        """
+        # new plot data
+        new_plots = GuiUtils.plotsFromCheckedItems(self.model)
+
+        # old plot data
+        plot_id = str(self.cbgraph.currentText())
+
+        assert plot_id in PlotHelper.currentPlots(), "No such plot: %s"%(plot_id)
+
+        old_plot = PlotHelper.plotById(plot_id)
+
+        # Add new data to the old plot, if data type is the same.
+        for _, plot_set in new_plots:
+            if type(plot_set) is type(old_plot._data):
+                old_plot.data = plot_set
+                old_plot.plot()
+
+    def updatePlot(self, new_data):
+        """
+        Modify existing plot for immediate response
+        """
+        data = new_data[0]
+        assert type(data).__name__ in ['Data1D', 'Data2D']
+
+        id = data.id
+        if data.id in self.active_plots.keys():
+            self.active_plots[id].replacePlot(id, data)
+
+    def chooseFiles(self):
+        """
+        Shows the Open file dialog and returns the chosen path(s)
+        """
+        # List of known extensions
+        wlist = self.getWlist()
+
+        # Location is automatically saved - no need to keep track of the last dir
+        # But only with Qt built-in dialog (non-platform native)
+        paths = QtGui.QFileDialog.getOpenFileNames(self, "Choose a file", "",
+                wlist, None, QtGui.QFileDialog.DontUseNativeDialog)
+        if paths is None:
+            return
+
+        if isinstance(paths, QtCore.QStringList):
+            paths = [str(f) for f in paths]
+
+        if not isinstance(paths, list):
+            paths = [paths]
+
+        return paths
+
+    def readData(self, path):
+        """
+        verbatim copy-paste from
+           sasgui.guiframe.local_perspectives.data_loader.data_loader.py
+        slightly modified for clarity
+        """
+        message = ""
+        log_msg = ''
+        output = {}
+        any_error = False
+        data_error = False
+        error_message = ""
+        number_of_files = len(path)
+        self.communicator.progressBarUpdateSignal.emit(0.0)
+
+        for index, p_file in enumerate(path):
+            basename = os.path.basename(p_file)
+            _, extension = os.path.splitext(basename)
+            if extension.lower() in GuiUtils.EXTENSIONS:
+                any_error = True
+                log_msg = "Data Loader cannot "
+                log_msg += "load: %s\n" % str(p_file)
+                log_msg += """Please try to open that file from "open project" """
+                log_msg += """or "open analysis" menu\n"""
+                error_message = log_msg + "\n"
+                logging.info(log_msg)
+                continue
+
+            try:
+                message = "Loading Data... " + str(basename) + "\n"
+
+                # change this to signal notification in GuiManager
+                self.communicator.statusBarUpdateSignal.emit(message)
+
+                output_objects = self.loader.load(p_file)
+
+                # Some loaders return a list and some just a single Data1D object.
+                # Standardize.
+                if not isinstance(output_objects, list):
+                    output_objects = [output_objects]
+
+                for item in output_objects:
+                    # cast sascalc.dataloader.data_info.Data1D into
+                    # sasgui.guiframe.dataFitting.Data1D
+                    # TODO : Fix it
+                    new_data = self.manager.create_gui_data(item, p_file)
+                    output[new_data.id] = new_data
+
+                    # Model update should be protected
+                    self.mutex.lock()
+                    self.updateModel(new_data, p_file)
+                    self.model.reset()
+                    QtGui.qApp.processEvents()
+                    self.mutex.unlock()
+
+                    if hasattr(item, 'errors'):
+                        for error_data in item.errors:
+                            data_error = True
+                            message += "\tError: {0}\n".format(error_data)
+                    else:
+
+                        logging.error("Loader returned an invalid object:\n %s" % str(item))
+                        data_error = True
+
+            except Exception as ex:
+                logging.error(sys.exc_value)
+
+                any_error = True
+            if any_error or error_message != "":
+                if error_message == "":
+                    error = "Error: " + str(sys.exc_info()[1]) + "\n"
+                    error += "while loading Data: \n%s\n" % str(basename)
+                    error_message += "The data file you selected could not be loaded.\n"
+                    error_message += "Make sure the content of your file"
+                    error_message += " is properly formatted.\n\n"
+                    error_message += "When contacting the SasView team, mention the"
+                    error_message += " following:\n%s" % str(error)
+                elif data_error:
+                    base_message = "Errors occurred while loading "
+                    base_message += "{0}\n".format(basename)
+                    base_message += "The data file loaded but with errors.\n"
+                    error_message = base_message + error_message
+                else:
+                    error_message += "%s\n" % str(p_file)
+
+            current_percentage = int(100.0* index/number_of_files)
+            self.communicator.progressBarUpdateSignal.emit(current_percentage)
+
+        if any_error or error_message:
+            logging.error(error_message)
+            status_bar_message = "Errors occurred while loading %s" % format(basename)
+            self.communicator.statusBarUpdateSignal.emit(status_bar_message)
+
+        else:
+            message = "Loading Data Complete! "
+        message += log_msg
+        # Notify the progress bar that the updates are over.
+        self.communicator.progressBarUpdateSignal.emit(-1)
+        self.communicator.statusBarUpdateSignal.emit(message)
+
+        return output, message
+
+    def getWlist(self):
+        """
+        Wildcards of files we know the format of.
+        """
+        # Display the Qt Load File module
+        cards = self.loader.get_wildcards()
+
+        # get rid of the wx remnant in wildcards
+        # TODO: modify sasview loader get_wildcards method, after merge,
+        # so this kludge can be avoided
+        new_cards = []
+        for item in cards:
+            new_cards.append(item[:item.find("|")])
+        wlist = ';;'.join(new_cards)
+
+        return wlist
+
+    def selectData(self, index):
+        """
+        Callback method for modifying the TreeView on Selection Options change
+        """
+        if not isinstance(index, int):
+            msg = "Incorrect type passed to DataExplorer.selectData()"
+            raise AttributeError, msg
+
+        # Respond appropriately
+        if index == 0:
+            # Select All
+            for index in range(self.model.rowCount()):
+                item = self.model.item(index)
+                if item.isCheckable() and item.checkState() == QtCore.Qt.Unchecked:
+                    item.setCheckState(QtCore.Qt.Checked)
+        elif index == 1:
+            # De-select All
+            for index in range(self.model.rowCount()):
+                item = self.model.item(index)
+                if item.isCheckable() and item.checkState() == QtCore.Qt.Checked:
+                    item.setCheckState(QtCore.Qt.Unchecked)
+
+        elif index == 2:
+            # Select All 1-D
+            for index in range(self.model.rowCount()):
+                item = self.model.item(index)
+                item.setCheckState(QtCore.Qt.Unchecked)
+
+                try:
+                    is1D = isinstance(GuiUtils.dataFromItem(item), Data1D)
+                except AttributeError:
+                    msg = "Bad structure of the data model."
+                    raise RuntimeError, msg
+
+                if is1D:
+                    item.setCheckState(QtCore.Qt.Checked)
+
+        elif index == 3:
+            # Unselect All 1-D
+            for index in range(self.model.rowCount()):
+                item = self.model.item(index)
+
+                try:
+                    is1D = isinstance(GuiUtils.dataFromItem(item), Data1D)
+                except AttributeError:
+                    msg = "Bad structure of the data model."
+                    raise RuntimeError, msg
+
+                if item.isCheckable() and item.checkState() == QtCore.Qt.Checked and is1D:
+                    item.setCheckState(QtCore.Qt.Unchecked)
+
+        elif index == 4:
+            # Select All 2-D
+            for index in range(self.model.rowCount()):
+                item = self.model.item(index)
+                item.setCheckState(QtCore.Qt.Unchecked)
+                try:
+                    is2D = isinstance(GuiUtils.dataFromItem(item), Data2D)
+                except AttributeError:
+                    msg = "Bad structure of the data model."
+                    raise RuntimeError, msg
+
+                if is2D:
+                    item.setCheckState(QtCore.Qt.Checked)
+
+        elif index == 5:
+            # Unselect All 2-D
+            for index in range(self.model.rowCount()):
+                item = self.model.item(index)
+
+                try:
+                    is2D = isinstance(GuiUtils.dataFromItem(item), Data2D)
+                except AttributeError:
+                    msg = "Bad structure of the data model."
+                    raise RuntimeError, msg
+
+                if item.isCheckable() and item.checkState() == QtCore.Qt.Checked and is2D:
+                    item.setCheckState(QtCore.Qt.Unchecked)
+
+        else:
+            msg = "Incorrect value in the Selection Option"
+            # Change this to a proper logging action
+            raise Exception, msg
+
+    def contextMenu(self):
+        """
+        Define actions and layout of the right click context menu
+        """
+        # Create a custom menu based on actions defined in the UI file
+        self.context_menu = QtGui.QMenu(self)
+        self.context_menu.addAction(self.actionDataInfo)
+        self.context_menu.addAction(self.actionSaveAs)
+        self.context_menu.addAction(self.actionQuickPlot)
+        self.context_menu.addSeparator()
+        self.context_menu.addAction(self.actionQuick3DPlot)
+        self.context_menu.addAction(self.actionEditMask)
+
+        # Define the callbacks
+        self.actionDataInfo.triggered.connect(self.showDataInfo)
+        self.actionSaveAs.triggered.connect(self.saveDataAs)
+        self.actionQuickPlot.triggered.connect(self.quickDataPlot)
+        self.actionQuick3DPlot.triggered.connect(self.quickData3DPlot)
+        self.actionEditMask.triggered.connect(self.showEditDataMask)
+
+    def onCustomContextMenu(self, position):
+        """
+        Show the right-click context menu in the data treeview
+        """
+        index = self.current_view.indexAt(position)
+        proxy = self.current_view.model()
+        model = proxy.sourceModel()
+
+        if index.isValid():
+            model_item = model.itemFromIndex(proxy.mapToSource(index))
+            # Find the mapped index
+            orig_index = model_item.isCheckable()
+            if orig_index:
+                # Check the data to enable/disable actions
+                is_2D = isinstance(GuiUtils.dataFromItem(model_item), Data2D)
+                self.actionQuick3DPlot.setEnabled(is_2D)
+                self.actionEditMask.setEnabled(is_2D)
+                # Fire up the menu
+                self.context_menu.exec_(self.current_view.mapToGlobal(position))
+
+    def showDataInfo(self):
+        """
+        Show a simple read-only text edit with data information.
+        """
+        index = self.current_view.selectedIndexes()[0]
+        proxy = self.current_view.model()
+        model = proxy.sourceModel()
+        model_item = model.itemFromIndex(proxy.mapToSource(index))
+
+        data = GuiUtils.dataFromItem(model_item)
+        if isinstance(data, Data1D):
+            text_to_show = GuiUtils.retrieveData1d(data)
+            # Hardcoded sizes to enable full width rendering with default font
+            self.txt_widget.resize(420,600)
+        else:
+            text_to_show = GuiUtils.retrieveData2d(data)
+            # Hardcoded sizes to enable full width rendering with default font
+            self.txt_widget.resize(700,600)
+
+        self.txt_widget.setReadOnly(True)
+        self.txt_widget.setWindowFlags(QtCore.Qt.Window)
+        self.txt_widget.setWindowIcon(QtGui.QIcon(":/res/ball.ico"))
+        self.txt_widget.setWindowTitle("Data Info: %s" % data.filename)
+        self.txt_widget.insertPlainText(text_to_show)
+
+        self.txt_widget.show()
+        # Move the slider all the way up, if present
+        vertical_scroll_bar = self.txt_widget.verticalScrollBar()
+        vertical_scroll_bar.triggerAction(QtGui.QScrollBar.SliderToMinimum)
+
+    def saveDataAs(self):
+        """
+        Save the data points as either txt or xml
+        """
+        index = self.current_view.selectedIndexes()[0]
+        proxy = self.current_view.model()
+        model = proxy.sourceModel()
+        model_item = model.itemFromIndex(proxy.mapToSource(index))
+
+        data = GuiUtils.dataFromItem(model_item)
+        if isinstance(data, Data1D):
+            GuiUtils.saveData1D(data)
+        else:
+            GuiUtils.saveData2D(data)
+
+    def quickDataPlot(self):
+        """
+        Frozen plot - display an image of the plot
+        """
+        index = self.current_view.selectedIndexes()[0]
+        proxy = self.current_view.model()
+        model = proxy.sourceModel()
+        model_item = model.itemFromIndex(proxy.mapToSource(index))
+
+        data = GuiUtils.dataFromItem(model_item)
+
+        method_name = 'Plotter'
+        if isinstance(data, Data2D):
+            method_name='Plotter2D'
+
+        new_plot = globals()[method_name](self, quickplot=True)
+        new_plot.data = data
+        #new_plot.plot(marker='o')
+        new_plot.plot()
+
+        # Update the global plot counter
+        title = "Plot " + data.name
+        new_plot.setWindowTitle(title)
+
+        # Show the plot
+        new_plot.show()
+
+    def quickData3DPlot(self):
+        """
+        Slowish 3D plot
+        """
+        index = self.current_view.selectedIndexes()[0]
+        proxy = self.current_view.model()
+        model = proxy.sourceModel()
+        model_item = model.itemFromIndex(proxy.mapToSource(index))
+
+        data = GuiUtils.dataFromItem(model_item)
+
+        new_plot = Plotter2D(self, quickplot=True, dimension=3)
+        new_plot.data = data
+        new_plot.plot()
+
+        # Update the global plot counter
+        title = "Plot " + data.name
+        new_plot.setWindowTitle(title)
+
+        # Show the plot
+        new_plot.show()
+
+    def showEditDataMask(self):
+        """
+        Mask Editor for 2D plots
+        """
+        index = self.current_view.selectedIndexes()[0]
+        proxy = self.current_view.model()
+        model = proxy.sourceModel()
+        model_item = model.itemFromIndex(proxy.mapToSource(index))
+
+        data = GuiUtils.dataFromItem(model_item)
+
+        mask_editor = MaskEditor(self, data)
+        # Modal dialog here.
+        mask_editor.exec_()
+
+    def loadComplete(self, output):
+        """
+        Post message to status bar and update the data manager
+        """
+        assert isinstance(output, tuple)
+
+        # Reset the model so the view gets updated.
+        self.model.reset()
+        self.communicator.progressBarUpdateSignal.emit(-1)
+
+        output_data = output[0]
+        message = output[1]
+        # Notify the manager of the new data available
+        self.communicator.statusBarUpdateSignal.emit(message)
+        self.communicator.fileDataReceivedSignal.emit(output_data)
+        self.manager.add_data(data_list=output_data)
+
+    def updateModel(self, data, p_file):
+        """
+        Add data and Info fields to the model item
+        """
+        # Structure of the model
+        # checkbox + basename
+        #     |-------> Data.D object
+        #     |-------> Info
+        #                 |----> Title:
+        #                 |----> Run:
+        #                 |----> Type:
+        #                 |----> Path:
+        #                 |----> Process
+        #                          |-----> process[0].name
+        #     |-------> THEORIES
+
+        # Top-level item: checkbox with label
+        checkbox_item = QtGui.QStandardItem(True)
+        checkbox_item.setCheckable(True)
+        checkbox_item.setCheckState(QtCore.Qt.Checked)
+        checkbox_item.setText(os.path.basename(p_file))
+
+        # Add the actual Data1D/Data2D object
+        object_item = QtGui.QStandardItem()
+        object_item.setData(QtCore.QVariant(data))
+
+        checkbox_item.setChild(0, object_item)
+
+        # Add rows for display in the view
+        info_item = GuiUtils.infoFromData(data)
+
+        # Set info_item as the first child
+        checkbox_item.setChild(1, info_item)
+
+        # Caption for the theories
+        checkbox_item.setChild(2, QtGui.QStandardItem("THEORIES"))
+
+        # New row in the model
+        self.model.appendRow(checkbox_item)
+
+
+    def updateModelFromPerspective(self, model_item):
+        """
+        Receive an update model item from a perspective
+        Make sure it is valid and if so, replace it in the model
+        """
+        # Assert the correct type
+        if not isinstance(model_item, QtGui.QStandardItem):
+            msg = "Wrong data type returned from calculations."
+            raise AttributeError, msg
+
+        # TODO: Assert other properties
+
+        # Reset the view
+        self.model.reset()
+        # Pass acting as a debugger anchor
+        pass
+
+    def updateTheoryFromPerspective(self, model_item):
+        """
+        Receive an update theory item from a perspective
+        Make sure it is valid and if so, replace/add in the model
+        """
+        # Assert the correct type
+        if not isinstance(model_item, QtGui.QStandardItem):
+            msg = "Wrong data type returned from calculations."
+            raise AttributeError, msg
+
+        # Check if there are any other items for this tab
+        # If so, delete them
+        # TODO: fix this to resemble GuiUtils.updateModelItemWithPlot
+        # 
+        current_tab_name = model_item.text()[:2]
+        for current_index in xrange(self.theory_model.rowCount()):
+            if current_tab_name in self.theory_model.item(current_index).text():
+                self.theory_model.removeRow(current_index)
+                break
+
+        # Reset the view
+        self.model.reset()
+
+        # Reset the view
+        self.theory_model.appendRow(model_item)
+
+        # Pass acting as a debugger anchor
+        pass
+
+
+if __name__ == "__main__":
+    app = QtGui.QApplication([])
+    dlg = DataExplorerWindow()
+    dlg.show()
+    sys.exit(app.exec_())
Index: src/sas/qtgui/MainWindow/DroppableDataLoadWidget.py
===================================================================
--- src/sas/qtgui/MainWindow/DroppableDataLoadWidget.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/DroppableDataLoadWidget.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,67 @@
+# global
+from PyQt4 import QtGui, QtCore
+
+# UI
+from sas.qtgui.MainWindow.UI.DataExplorerUI import Ui_DataLoadWidget
+
+class DroppableDataLoadWidget(QtGui.QTabWidget, Ui_DataLoadWidget):
+    """
+    Overwrite drag and drop methods in the base class
+    so users can drop files directly onto the Data Explorer
+    """
+    def __init__(self, parent=None, guimanager=None):
+        super(DroppableDataLoadWidget, self).__init__(parent)
+        self.setupUi(self)
+
+        # Enable file drag-drop on treeView
+        self.setAcceptDrops(True)
+        self.communicator = guimanager.communicator()
+        flags = QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowSystemMenuHint
+        self.setWindowFlags(flags)
+
+    def dragIsOK(self, event):
+        """
+        Return True if the event contain URLs
+        """
+        # Analyze mime data
+        return bool(event.mimeData().hasUrls() and self.currentIndex() == 0)
+
+    def dragEnterEvent(self, event):
+        """
+        Called automatically on a drag into the treeview
+        """
+        if self.dragIsOK(event):
+            event.setDropAction(QtCore.Qt.CopyAction)
+            event.accept()
+        else:
+            event.ignore()
+
+    def dragMoveEvent(self, event):
+        """
+        Called automatically when a drag is
+        moved inside the treeview
+        """
+        if self.dragIsOK(event):
+            event.accept()
+        else:
+            event.ignore()
+
+    def dropEvent(self, event):
+        """
+        Called automatically when a drop
+        is added to the treeview.
+        """
+        if self.dragIsOK(event):
+            filenames=[]
+            for url in event.mimeData().urls():
+                filenames.append(str(url.toLocalFile()))
+            self.communicator.fileReadSignal.emit(filenames)
+            event.accept()
+        else:
+            event.ignore()
+
+    def closeEvent(self, event):
+        """
+        Overwrite the close event - no close!
+        """
+        event.ignore()
Index: src/sas/qtgui/MainWindow/GuiManager.py
===================================================================
--- src/sas/qtgui/MainWindow/GuiManager.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/GuiManager.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,740 @@
+import sys
+import os
+import subprocess
+import logging
+import json
+import webbrowser
+
+from PyQt4 import QtCore
+from PyQt4 import QtGui
+from PyQt4 import QtWebKit
+
+from twisted.internet import reactor
+# General SAS imports
+
+from sas.sasgui.guiframe.data_manager import DataManager
+from sas.sasgui.guiframe.proxy import Connection
+from sas.qtgui.Utilities.SasviewLogger import XStream
+from sas.qtgui.Utilities.IPythonWidget import IPythonWidget
+import sas.qtgui.Utilities.LocalConfig as LocalConfig
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+
+from sas.qtgui.MainWindow.UI.AcknowledgementsUI import Ui_Acknowledgements
+from sas.qtgui.MainWindow.AboutBox import AboutBox
+from sas.qtgui.MainWindow.WelcomePanel import WelcomePanel
+
+from sas.qtgui.Calculators.SldPanel import SldPanel
+from sas.qtgui.Calculators.DensityPanel import DensityPanel
+from sas.qtgui.Calculators.KiessigPanel import KiessigPanel
+from sas.qtgui.Calculators.SlitSizeCalculator import SlitSizeCalculator
+
+# Perspectives
+import sas.qtgui.Perspectives as Perspectives
+from sas.qtgui.Perspectives.Fitting.FittingPerspective import FittingWindow
+from sas.qtgui.MainWindow.DataExplorer import DataExplorerWindow
+
+class Acknowledgements(QtGui.QDialog, Ui_Acknowledgements):
+    def __init__(self, parent=None):
+        QtGui.QDialog.__init__(self, parent)
+        self.setupUi(self)
+
+class GuiManager(object):
+    """
+    Main SasView window functionality
+    """
+    ## TODO: CHANGE FOR SHIPPED PATH IN RELEASE
+    HELP_DIRECTORY_LOCATION = "docs/sphinx-docs/build/html"
+
+    def __init__(self, parent=None):
+        """
+        Initialize the manager as a child of MainWindow.
+        """
+        self._workspace = parent
+        self._parent = parent
+
+        # Reactor - singleton
+        self.setReactor(reactor)
+
+        # Add signal callbacks
+        self.addCallbacks()
+
+        # Create the data manager
+        # TODO: pull out all required methods from DataManager and reimplement
+        self._data_manager = DataManager()
+
+        # Create action triggers
+        self.addTriggers()
+
+        # Populate menus with dynamic data
+        #
+        # Analysis/Perspectives - potentially
+        # Window/current windows
+        #
+        # Widgets
+        #
+        # Current displayed perspective
+        self._current_perspective = None
+
+        # Invoke the initial perspective
+        self.perspectiveChanged("Fitting")
+
+        self.addWidgets()
+
+        # Fork off logging messages to the Log Window
+        XStream.stdout().messageWritten.connect(self.listWidget.insertPlainText)
+        XStream.stderr().messageWritten.connect(self.listWidget.insertPlainText)
+
+        # Log the start of the session
+        logging.info(" --- SasView session started ---")
+        # Log the python version
+        logging.info("Python: %s" % sys.version)
+
+        # Set up the status bar
+        self.statusBarSetup()
+
+        # Show the Welcome panel
+        self.welcomePanel = WelcomePanel()
+        self._workspace.workspace.addWindow(self.welcomePanel)
+
+        # Current help file
+        self._helpView = QtWebKit.QWebView()
+        # Needs URL like path, so no path.join() here
+        self._helpLocation = self.HELP_DIRECTORY_LOCATION + "/index.html"
+
+        # Current tutorial location
+        self._tutorialLocation = os.path.abspath(os.path.join(self.HELP_DIRECTORY_LOCATION,
+                                              "_downloads",
+                                              "Tutorial.pdf"))
+    def addWidgets(self):
+        """
+        Populate the main window with widgets
+
+        TODO: overwrite close() on Log and DR widgets so they can be hidden/shown
+        on request
+        """
+        # Add FileDialog widget as docked
+        self.filesWidget = DataExplorerWindow(self._parent, self, manager=self._data_manager)
+
+        self.dockedFilesWidget = QtGui.QDockWidget("Data Explorer", self._workspace)
+        self.dockedFilesWidget.setWidget(self.filesWidget)
+
+        # Disable maximize/minimize and close buttons
+        self.dockedFilesWidget.setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures)
+        self._workspace.addDockWidget(QtCore.Qt.LeftDockWidgetArea,
+                                      self.dockedFilesWidget)
+
+        # Add the console window as another docked widget
+        self.logDockWidget = QtGui.QDockWidget("Log Explorer", self._workspace)
+        self.logDockWidget.setObjectName("LogDockWidget")
+        self.listWidget = QtGui.QTextBrowser()
+        self.logDockWidget.setWidget(self.listWidget)
+        self._workspace.addDockWidget(QtCore.Qt.BottomDockWidgetArea,
+                                      self.logDockWidget)
+
+        # Add other, minor widgets
+        self.ackWidget = Acknowledgements()
+        self.aboutWidget = AboutBox()
+
+        # Add calculators - floating for usability
+        self.SLDCalculator = SldPanel(self)
+        self.DVCalculator = DensityPanel(self)
+        #self.KIESSIGCalculator = DensityPanel(self)#KiessigPanel(self)
+        self.KIESSIGCalculator = KiessigPanel(self)
+        self.SlitSizeCalculator = SlitSizeCalculator(self)
+
+    def statusBarSetup(self):
+        """
+        Define the status bar.
+        | <message label> .... | Progress Bar |
+
+        Progress bar invisible until explicitly shown
+        """
+        self.progress = QtGui.QProgressBar()
+        self._workspace.statusbar.setSizeGripEnabled(False)
+
+        self.statusLabel = QtGui.QLabel()
+        self.statusLabel.setText("Welcome to SasView")
+        self._workspace.statusbar.addPermanentWidget(self.statusLabel, 1)
+        self._workspace.statusbar.addPermanentWidget(self.progress, stretch=0)
+        self.progress.setRange(0, 100)
+        self.progress.setValue(0)
+        self.progress.setTextVisible(True)
+        self.progress.setVisible(False)
+
+    def fileRead(self, data):
+        """
+        Callback for fileDataReceivedSignal
+        """
+        pass
+
+    def workspace(self):
+        """
+        Accessor for the main window workspace
+        """
+        return self._workspace.workspace
+
+    def perspectiveChanged(self, perspective_name):
+        """
+        Respond to change of the perspective signal
+        """
+        # Close the previous perspective
+        if self._current_perspective:
+            self._current_perspective.setClosable()
+            self._current_perspective.close()
+        # Default perspective
+        self._current_perspective = Perspectives.PERSPECTIVES[str(perspective_name)](parent=self)
+
+        self._workspace.workspace.addWindow(self._current_perspective)
+        # Resize to the workspace height
+        workspace_height = self._workspace.workspace.sizeHint().height()
+        perspective_size = self._current_perspective.sizeHint()
+        if workspace_height < perspective_size.height:
+            perspective_width = perspective_size.width()
+            self._current_perspective.resize(perspective_width, workspace_height-10)
+        self._current_perspective.show()
+
+    def updatePerspective(self, data):
+        """
+        Update perspective with data sent.
+        """
+        assert isinstance(data, list)
+        if self._current_perspective is not None:
+            self._current_perspective.setData(data.values())
+        else:
+            msg = "No perspective is currently active."
+            logging.info(msg)
+
+    def communicator(self):
+        """ Accessor for the communicator """
+        return self.communicate
+
+    def reactor(self):
+        """ Accessor for the reactor """
+        return self._reactor
+
+    def setReactor(self, reactor):
+        """ Reactor setter """
+        self._reactor = reactor
+
+    def perspective(self):
+        """ Accessor for the perspective """
+        return self._current_perspective
+
+    def updateProgressBar(self, value):
+        """
+        Update progress bar with the required value (0-100)
+        """
+        assert -1 <= value <= 100
+        if value == -1:
+            self.progress.setVisible(False)
+            return
+        if not self.progress.isVisible():
+            self.progress.setTextVisible(True)
+            self.progress.setVisible(True)
+
+        self.progress.setValue(value)
+
+    def updateStatusBar(self, text):
+        """
+        Set the status bar text
+        """
+        self.statusLabel.setText(text)
+
+    def createGuiData(self, item, p_file=None):
+        """
+        Access the Data1D -> plottable Data1D conversion
+        """
+        return self._data_manager.create_gui_data(item, p_file)
+
+    def setData(self, data):
+        """
+        Sends data to current perspective
+        """
+        if self._current_perspective is not None:
+            self._current_perspective.setData(data.values())
+        else:
+            msg = "Guiframe does not have a current perspective"
+            logging.info(msg)
+
+    def quitApplication(self):
+        """
+        Close the reactor and exit nicely.
+        """
+        # Display confirmation messagebox
+        quit_msg = "Are you sure you want to exit the application?"
+        reply = QtGui.QMessageBox.question(
+            self._parent,
+            'Information',
+            quit_msg,
+            QtGui.QMessageBox.Yes,
+            QtGui.QMessageBox.No)
+
+        # Exit if yes
+        if reply == QtGui.QMessageBox.Yes:
+            reactor.callFromThread(reactor.stop)
+            return True
+
+        return False
+
+    def checkUpdate(self):
+        """
+        Check with the deployment server whether a new version
+        of the application is available.
+        A thread is started for the connecting with the server. The thread calls
+        a call-back method when the current version number has been obtained.
+        """
+        version_info = {"version": "0.0.0"}
+        c = Connection(LocalConfig.__update_URL__, LocalConfig.UPDATE_TIMEOUT)
+        response = c.connect()
+        if response is None:
+            return
+        try:
+            content = response.read().strip()
+            logging.info("Connected to www.sasview.org. Latest version: %s"
+                            % (content))
+            version_info = json.loads(content)
+            self.processVersion(version_info)
+        except ValueError, ex:
+            logging.info("Failed to connect to www.sasview.org:", ex)
+
+    def processVersion(self, version_info):
+        """
+        Call-back method for the process of checking for updates.
+        This methods is called by a VersionThread object once the current
+        version number has been obtained. If the check is being done in the
+        background, the user will not be notified unless there's an update.
+
+        :param version: version string
+        """
+        try:
+            version = version_info["version"]
+            if version == "0.0.0":
+                msg = "Could not connect to the application server."
+                msg += " Please try again later."
+                self.communicate.statusBarUpdateSignal.emit(msg)
+
+            elif cmp(version, LocalConfig.__version__) > 0:
+                msg = "Version %s is available! " % str(version)
+                if "download_url" in version_info:
+                    webbrowser.open(version_info["download_url"])
+                else:
+                    webbrowser.open(LocalConfig.__download_page__)
+                self.communicate.statusBarUpdateSignal.emit(msg)
+            else:
+                msg = "You have the latest version"
+                msg += " of %s" % str(LocalConfig.__appname__)
+                self.communicate.statusBarUpdateSignal.emit(msg)
+        except:
+            msg = "guiframe: could not get latest application"
+            msg += " version number\n  %s" % sys.exc_value
+            logging.error(msg)
+            msg = "Could not connect to the application server."
+            msg += " Please try again later."
+            self.communicate.statusBarUpdateSignal.emit(msg)
+
+    def addCallbacks(self):
+        """
+        Method defining all signal connections for the gui manager
+        """
+        self.communicate = GuiUtils.Communicate()
+        self.communicate.fileDataReceivedSignal.connect(self.fileRead)
+        self.communicate.statusBarUpdateSignal.connect(self.updateStatusBar)
+        self.communicate.updatePerspectiveWithDataSignal.connect(self.updatePerspective)
+        self.communicate.progressBarUpdateSignal.connect(self.updateProgressBar)
+        self.communicate.perspectiveChangedSignal.connect(self.perspectiveChanged)
+        self.communicate.updateTheoryFromPerspectiveSignal.connect(self.updateTheoryFromPerspective)
+
+    def addTriggers(self):
+        """
+        Trigger definitions for all menu/toolbar actions.
+        """
+        # File
+        self._workspace.actionLoadData.triggered.connect(self.actionLoadData)
+        self._workspace.actionLoad_Data_Folder.triggered.connect(self.actionLoad_Data_Folder)
+        self._workspace.actionOpen_Project.triggered.connect(self.actionOpen_Project)
+        self._workspace.actionOpen_Analysis.triggered.connect(self.actionOpen_Analysis)
+        self._workspace.actionSave.triggered.connect(self.actionSave)
+        self._workspace.actionSave_Analysis.triggered.connect(self.actionSave_Analysis)
+        self._workspace.actionQuit.triggered.connect(self.actionQuit)
+        # Edit
+        self._workspace.actionUndo.triggered.connect(self.actionUndo)
+        self._workspace.actionRedo.triggered.connect(self.actionRedo)
+        self._workspace.actionCopy.triggered.connect(self.actionCopy)
+        self._workspace.actionPaste.triggered.connect(self.actionPaste)
+        self._workspace.actionReport.triggered.connect(self.actionReport)
+        self._workspace.actionReset.triggered.connect(self.actionReset)
+        self._workspace.actionExcel.triggered.connect(self.actionExcel)
+        self._workspace.actionLatex.triggered.connect(self.actionLatex)
+
+        # View
+        self._workspace.actionShow_Grid_Window.triggered.connect(self.actionShow_Grid_Window)
+        self._workspace.actionHide_Toolbar.triggered.connect(self.actionHide_Toolbar)
+        self._workspace.actionStartup_Settings.triggered.connect(self.actionStartup_Settings)
+        self._workspace.actionCategry_Manager.triggered.connect(self.actionCategry_Manager)
+        # Tools
+        self._workspace.actionData_Operation.triggered.connect(self.actionData_Operation)
+        self._workspace.actionSLD_Calculator.triggered.connect(self.actionSLD_Calculator)
+        self._workspace.actionDensity_Volume_Calculator.triggered.connect(self.actionDensity_Volume_Calculator)
+        self._workspace.actionKeissig_Calculator.triggered.connect(self.actionKiessig_Calculator)
+        #self._workspace.actionKIESSING_Calculator.triggered.connect(self.actionKIESSING_Calculator)
+        self._workspace.actionSlit_Size_Calculator.triggered.connect(self.actionSlit_Size_Calculator)
+        self._workspace.actionSAS_Resolution_Estimator.triggered.connect(self.actionSAS_Resolution_Estimator)
+        self._workspace.actionGeneric_Scattering_Calculator.triggered.connect(self.actionGeneric_Scattering_Calculator)
+        self._workspace.actionPython_Shell_Editor.triggered.connect(self.actionPython_Shell_Editor)
+        self._workspace.actionImage_Viewer.triggered.connect(self.actionImage_Viewer)
+        # Fitting
+        self._workspace.actionNew_Fit_Page.triggered.connect(self.actionNew_Fit_Page)
+        self._workspace.actionConstrained_Fit.triggered.connect(self.actionConstrained_Fit)
+        self._workspace.actionCombine_Batch_Fit.triggered.connect(self.actionCombine_Batch_Fit)
+        self._workspace.actionFit_Options.triggered.connect(self.actionFit_Options)
+        self._workspace.actionFit_Results.triggered.connect(self.actionFit_Results)
+        self._workspace.actionChain_Fitting.triggered.connect(self.actionChain_Fitting)
+        self._workspace.actionEdit_Custom_Model.triggered.connect(self.actionEdit_Custom_Model)
+        # Window
+        self._workspace.actionCascade.triggered.connect(self.actionCascade)
+        self._workspace.actionTile.triggered.connect(self.actionTile)
+        self._workspace.actionArrange_Icons.triggered.connect(self.actionArrange_Icons)
+        self._workspace.actionNext.triggered.connect(self.actionNext)
+        self._workspace.actionPrevious.triggered.connect(self.actionPrevious)
+        # Analysis
+        self._workspace.actionFitting.triggered.connect(self.actionFitting)
+        self._workspace.actionInversion.triggered.connect(self.actionInversion)
+        self._workspace.actionInvariant.triggered.connect(self.actionInvariant)
+        # Help
+        self._workspace.actionDocumentation.triggered.connect(self.actionDocumentation)
+        self._workspace.actionTutorial.triggered.connect(self.actionTutorial)
+        self._workspace.actionAcknowledge.triggered.connect(self.actionAcknowledge)
+        self._workspace.actionAbout.triggered.connect(self.actionAbout)
+        self._workspace.actionCheck_for_update.triggered.connect(self.actionCheck_for_update)
+
+    #============ FILE =================
+    def actionLoadData(self):
+        """
+        Menu File/Load Data File(s)
+        """
+        self.filesWidget.loadFile()
+
+    def actionLoad_Data_Folder(self):
+        """
+        Menu File/Load Data Folder
+        """
+        self.filesWidget.loadFolder()
+
+    def actionOpen_Project(self):
+        """
+        Menu Open Project
+        """
+        self.filesWidget.loadProject()
+
+    def actionOpen_Analysis(self):
+        """
+        """
+        print("actionOpen_Analysis TRIGGERED")
+        pass
+
+    def actionSave(self):
+        """
+        Menu Save Project
+        """
+        self.filesWidget.saveProject()
+
+    def actionSave_Analysis(self):
+        """
+        """
+        print("actionSave_Analysis TRIGGERED")
+
+        pass
+
+    def actionQuit(self):
+        """
+        Close the reactor, exit the application.
+        """
+        self.quitApplication()
+
+    #============ EDIT =================
+    def actionUndo(self):
+        """
+        """
+        print("actionUndo TRIGGERED")
+        pass
+
+    def actionRedo(self):
+        """
+        """
+        print("actionRedo TRIGGERED")
+        pass
+
+    def actionCopy(self):
+        """
+        """
+        print("actionCopy TRIGGERED")
+        pass
+
+    def actionPaste(self):
+        """
+        """
+        print("actionPaste TRIGGERED")
+        pass
+
+    def actionReport(self):
+        """
+        """
+        print("actionReport TRIGGERED")
+        pass
+
+    def actionReset(self):
+        """
+        """
+        logging.warning(" *** actionOpen_Analysis logging *******")
+        print("actionReset print TRIGGERED")
+        sys.stderr.write("STDERR - TRIGGERED")
+        pass
+
+    def actionExcel(self):
+        """
+        """
+        print("actionExcel TRIGGERED")
+        pass
+
+    def actionLatex(self):
+        """
+        """
+        print("actionLatex TRIGGERED")
+        pass
+
+    #============ VIEW =================
+    def actionShow_Grid_Window(self):
+        """
+        """
+        print("actionShow_Grid_Window TRIGGERED")
+        pass
+
+    def actionHide_Toolbar(self):
+        """
+        Toggle toolbar vsibility
+        """
+        if self._workspace.toolBar.isVisible():
+            self._workspace.actionHide_Toolbar.setText("Show Toolbar")
+            self._workspace.toolBar.setVisible(False)
+        else:
+            self._workspace.actionHide_Toolbar.setText("Hide Toolbar")
+            self._workspace.toolBar.setVisible(True)
+        pass
+
+    def actionStartup_Settings(self):
+        """
+        """
+        print("actionStartup_Settings TRIGGERED")
+        pass
+
+    def actionCategry_Manager(self):
+        """
+        """
+        print("actionCategry_Manager TRIGGERED")
+        pass
+
+    #============ TOOLS =================
+    def actionData_Operation(self):
+        """
+        """
+        print("actionData_Operation TRIGGERED")
+        pass
+
+    def actionSLD_Calculator(self):
+        """
+        """
+        self.SLDCalculator.show()
+
+    def actionDensity_Volume_Calculator(self):
+        """
+        """
+        self.DVCalculator.show()
+
+    def actionKiessig_Calculator(self):
+        """
+        """
+        #self.DVCalculator.show()
+        self.KIESSIGCalculator.show()
+
+    def actionSlit_Size_Calculator(self):
+        """
+        """
+        self.SlitSizeCalculator.show()
+
+    def actionSAS_Resolution_Estimator(self):
+        """
+        """
+        print("actionSAS_Resolution_Estimator TRIGGERED")
+        pass
+
+    def actionGeneric_Scattering_Calculator(self):
+        """
+        """
+        print("actionGeneric_Scattering_Calculator TRIGGERED")
+        pass
+
+    def actionPython_Shell_Editor(self):
+        """
+        Display the Jupyter console as a docked widget.
+        """
+        terminal = IPythonWidget()
+
+        # Add the console window as another docked widget
+        self.ipDockWidget = QtGui.QDockWidget("IPython", self._workspace)
+        self.ipDockWidget.setObjectName("IPythonDockWidget")
+        self.ipDockWidget.setWidget(terminal)
+        self._workspace.addDockWidget(QtCore.Qt.RightDockWidgetArea,
+                                      self.ipDockWidget)
+
+    def actionImage_Viewer(self):
+        """
+        """
+        print("actionImage_Viewer TRIGGERED")
+        pass
+
+    #============ FITTING =================
+    def actionNew_Fit_Page(self):
+        """
+        Add a new, empty Fit page in the fitting perspective.
+        """
+        # Make sure the perspective is correct
+        per = self.perspective()
+        if not isinstance(per, FittingWindow):
+            return
+        per.addFit(None)
+
+    def actionConstrained_Fit(self):
+        """
+        """
+        print("actionConstrained_Fit TRIGGERED")
+        pass
+
+    def actionCombine_Batch_Fit(self):
+        """
+        """
+        print("actionCombine_Batch_Fit TRIGGERED")
+        pass
+
+    def actionFit_Options(self):
+        """
+        """
+        print("actionFit_Options TRIGGERED")
+        pass
+
+    def actionFit_Results(self):
+        """
+        """
+        print("actionFit_Results TRIGGERED")
+        pass
+
+    def actionChain_Fitting(self):
+        """
+        """
+        print("actionChain_Fitting TRIGGERED")
+        pass
+
+    def actionEdit_Custom_Model(self):
+        """
+        """
+        print("actionEdit_Custom_Model TRIGGERED")
+        pass
+
+    #============ ANALYSIS =================
+    def actionFitting(self):
+        """
+        """
+        print("actionFitting TRIGGERED")
+        pass
+
+    def actionInversion(self):
+        """
+        """
+        print("actionInversion TRIGGERED")
+        pass
+
+    def actionInvariant(self):
+        """
+        """
+        print("actionInvariant TRIGGERED")
+        pass
+
+    #============ WINDOW =================
+    def actionCascade(self):
+        """
+        Arranges all the child windows in a cascade pattern.
+        """
+        self._workspace.workspace.cascade()
+
+    def actionTile(self):
+        """
+        Tile workspace windows
+        """
+        self._workspace.workspace.tile()
+
+    def actionArrange_Icons(self):
+        """
+        Arranges all iconified windows at the bottom of the workspace
+        """
+        self._workspace.workspace.arrangeIcons()
+
+    def actionNext(self):
+        """
+        Gives the input focus to the next window in the list of child windows.
+        """
+        self._workspace.workspace.activateNextWindow()
+
+    def actionPrevious(self):
+        """
+        Gives the input focus to the previous window in the list of child windows.
+        """
+        self._workspace.workspace.activatePreviousWindow()
+
+    #============ HELP =================
+    def actionDocumentation(self):
+        """
+        Display the documentation
+
+        TODO: use QNetworkAccessManager to assure _helpLocation is valid
+        """
+        self._helpView.load(QtCore.QUrl(self._helpLocation))
+        self._helpView.show()
+
+    def actionTutorial(self):
+        """
+        Open the tutorial PDF file with default PDF renderer
+        """
+        # Not terribly safe here. Shell injection warning.
+        # isfile() helps but this probably needs a better solution.
+        if os.path.isfile(self._tutorialLocation):
+            result = subprocess.Popen([self._tutorialLocation], shell=True)
+
+    def actionAcknowledge(self):
+        """
+        Open the Acknowledgements widget
+        """
+        self.ackWidget.show()
+
+    def actionAbout(self):
+        """
+        Open the About box
+        """
+        # Update the about box with current version and stuff
+
+        # TODO: proper sizing
+        self.aboutWidget.show()
+
+    def actionCheck_for_update(self):
+        """
+        Menu Help/Check for Update
+        """
+        self.checkUpdate()
+
+    def updateTheoryFromPerspective(self, index):
+        """
+        Catch the theory update signal from a perspective
+        Send the request to the DataExplorer for updating the theory model.
+        """
+        self.filesWidget.updateTheoryFromPerspective(index)
+
+
+
Index: src/sas/qtgui/MainWindow/MainWindow.py
===================================================================
--- src/sas/qtgui/MainWindow/MainWindow.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/MainWindow.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,69 @@
+# UNLESS EXEPTIONALLY REQUIRED TRY TO AVOID IMPORTING ANY MODULES HERE
+# ESPECIALLY ANYTHING IN SAS, SASMODELS NAMESPACE
+from PyQt4 import QtGui
+
+# Local UI
+from UI.MainWindowUI import Ui_MainWindow
+
+# Initialize logging
+import sas.qtgui.Utilities.SasviewLogger
+
+class MainSasViewWindow(QtGui.QMainWindow, Ui_MainWindow):
+    # Main window of the application
+    def __init__(self, parent=None):
+        super(MainSasViewWindow, self).__init__(parent)
+        self.setupUi(self)
+
+        # define workspace for dialogs.
+        self.workspace = QtGui.QWorkspace(self)
+        self.setCentralWidget(self.workspace)
+
+        # Create the gui manager
+        from GuiManager import GuiManager
+        self.guiManager = GuiManager(self)
+
+    def closeEvent(self, event):
+        if self.guiManager.quitApplication():
+            event.accept()
+        else:
+            event.ignore()
+
+
+def SplashScreen():
+    """
+    Displays splash screen as soon as humanely possible.
+    The screen will disappear as soon as the event loop starts.
+    """
+    # TODO: standardize path to images
+    pixmap = QtGui.QPixmap("src/sas/qtgui/images/SVwelcome_mini.png")
+    splashScreen = QtGui.QSplashScreen(pixmap)
+    return splashScreen
+
+def run():
+    app = QtGui.QApplication([])
+
+    # Main must have reference to the splash screen, so making it explicit
+    splash = SplashScreen()
+    splash.show()
+
+    # DO NOT move the following import to the top!
+    # (unless you know what you're doing)
+    import qt4reactor
+    # Using the Qt4 reactor wrapper from https://github.com/ghtdak/qtreactor
+    qt4reactor.install()
+
+    # DO NOT move the following import to the top!
+    from twisted.internet import reactor
+
+    # Show the main SV window
+    mainwindow = MainSasViewWindow()
+    mainwindow.showMaximized()
+
+    # no more splash screen
+    splash.finish(mainwindow)
+
+    # No need to .exec_ - the reactor takes care of it.
+    reactor.run()
+
+if __name__ == "__main__":
+    run()
Index: src/sas/qtgui/MainWindow/UI/AboutUI.ui
===================================================================
--- src/sas/qtgui/MainWindow/UI/AboutUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UI/AboutUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AboutUI</class>
+ <widget class="QWidget" name="AboutUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1107</width>
+    <height>449</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0" rowspan="2">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string/>
+     </property>
+     <property name="pixmap">
+      <pixmap>:/about/angles_flat.png</pixmap>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;SasView&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="2">
+    <widget class="QLabel" name="lblVersion">
+     <property name="text">
+      <string>TextLabel</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0" colspan="4">
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0">
+      <widget class="QPushButton" name="cmdLinkUT">
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset>
+         <normaloff>:/about/utlogo.gif</normaloff>:/about/utlogo.gif</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>48</width>
+         <height>48</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QPushButton" name="cmdLinkUMD">
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset>
+         <normaloff>:/about/umd_logo.png</normaloff>:/about/umd_logo.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>48</width>
+         <height>48</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QPushButton" name="cmdLinkNIST">
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset>
+         <normaloff>:/about/nist_logo.png</normaloff>:/about/nist_logo.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>110</width>
+         <height>48</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="3">
+      <widget class="QPushButton" name="cmdLinkSNS">
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset>
+         <normaloff>:/about/sns_logo.png</normaloff>:/about/sns_logo.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>64</width>
+         <height>48</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="4">
+      <widget class="QPushButton" name="cmdLinkISIS">
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset>
+         <normaloff>:/about/isis_logo.png</normaloff>:/about/isis_logo.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>128</width>
+         <height>48</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="5">
+      <widget class="QPushButton" name="cmdLinkESS">
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset>
+         <normaloff>:/about/ess_logo.png</normaloff>:/about/ess_logo.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>48</width>
+         <height>48</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="6">
+      <widget class="QPushButton" name="cmdLinkILL">
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset>
+         <normaloff>:/about/ill_logo.png</normaloff>:/about/ill_logo.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>48</width>
+         <height>48</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="7">
+      <widget class="QPushButton" name="cmdLinkANSTO">
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset>
+         <normaloff>:/about/ansto_logo.png</normaloff>:/about/ansto_logo.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>175</width>
+         <height>48</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="5" column="0" colspan="3">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>593</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="5" column="3">
+    <widget class="QPushButton" name="cmdOK">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>OK</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1" colspan="2">
+    <widget class="QLabel" name="lblAbout">
+     <property name="text">
+      <string>TextLabel</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="4">
+    <widget class="Line" name="line">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="4">
+    <widget class="QLabel" name="lblText">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This work originally developed as part of the DANSE project funded by the NSF under grant DMR-0520547, and currently maintained by NIST, UMD, ORNL, ISIS, ESS, ILL and last but not least ANSTO.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../UI/main_resources.qrc"/>
+  <include location="../images/images.qrc"/>
+ </resources>
+ <connections/>
+</ui>
Index: src/sas/qtgui/MainWindow/UI/AcknowledgementsUI.ui
===================================================================
--- src/sas/qtgui/MainWindow/UI/AcknowledgementsUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UI/AcknowledgementsUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Acknowledgements</class>
+ <widget class="QWidget" name="Acknowledgements">
+  <property name="windowModality">
+   <enum>Qt::ApplicationModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>436</width>
+    <height>212</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Acknowledging SasView</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;To ensure the long term support and development of this software please remember to&lt;/p&gt;&lt;ol style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Acknowledge its use in your publications as suggested below&lt;br/&gt;&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Reference the following website: http://www.sasview.org&lt;br/&gt;&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Reference the model you used if appropriate (see documentation for refs) &lt;br/&gt;&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Send us your reference for our records: developers@sasview.org&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QTextBrowser" name="textBrowser">
+     <property name="html">
+      <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;This work benefited from the use of the SasView application, originally&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;developed under NSF award DMR-0520547.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
Index: src/sas/qtgui/MainWindow/UI/DataExplorerUI.ui
===================================================================
--- src/sas/qtgui/MainWindow/UI/DataExplorerUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UI/DataExplorerUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,488 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DataLoadWidget</class>
+ <widget class="QTabWidget" name="DataLoadWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>405</width>
+    <height>630</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>5</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>TabWidget</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="../../UI/main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <property name="currentIndex">
+   <number>0</number>
+  </property>
+  <widget class="QWidget" name="dataTab">
+   <attribute name="title">
+    <string>Data</string>
+   </attribute>
+   <layout class="QGridLayout" name="gridLayout_11">
+    <item row="0" column="0">
+     <widget class="QGroupBox" name="groupBox">
+      <property name="title">
+       <string>Data</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout_9">
+       <item row="0" column="0">
+        <layout class="QGridLayout" name="gridLayout">
+         <item row="0" column="0" rowspan="2">
+          <widget class="QPushButton" name="cmdLoad">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>5</horstretch>
+             <verstretch>5</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>154</width>
+             <height>50</height>
+            </size>
+           </property>
+           <property name="baseSize">
+            <size>
+             <width>100</width>
+             <height>50</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Load a file with data&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="styleSheet">
+            <string notr="true">font: 13pt &quot;MS Shell Dlg 2&quot;;</string>
+           </property>
+           <property name="text">
+            <string>Load data</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../../UI/main_resources.qrc">
+             <normaloff>:/res/down-grey.png</normaloff>:/res/down-grey.png</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>48</width>
+             <height>48</height>
+            </size>
+           </property>
+           <property name="shortcut">
+            <string>Ctrl+R</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QPushButton" name="cmdDeleteData">
+           <property name="text">
+            <string>Delete</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QComboBox" name="cbSelect">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <item>
+            <property name="text">
+             <string>Select all</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Unselect all</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Select all 1D</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Unselect all 1D</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Select all 2D</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Unselect all 2D</string>
+            </property>
+           </item>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="0" column="1">
+        <spacer name="horizontalSpacer_7">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>92</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="2" column="0">
+        <layout class="QGridLayout" name="gridLayout_2">
+         <item row="0" column="0" rowspan="2">
+          <widget class="QPushButton" name="cmdSendTo">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>5</horstretch>
+             <verstretch>5</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>170</width>
+             <height>50</height>
+            </size>
+           </property>
+           <property name="baseSize">
+            <size>
+             <width>100</width>
+             <height>50</height>
+            </size>
+           </property>
+           <property name="font">
+            <font>
+             <pointsize>13</pointsize>
+            </font>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Send data to perspective&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="styleSheet">
+            <string notr="true">font: 13pt &quot;MS Shell Dlg 2&quot;;</string>
+           </property>
+           <property name="text">
+            <string>Send data to</string>
+           </property>
+           <property name="icon">
+            <iconset resource="../../UI/main_resources.qrc">
+             <normaloff>:/res/right-grey.png</normaloff>:/res/right-grey.png</iconset>
+           </property>
+           <property name="iconSize">
+            <size>
+             <width>48</width>
+             <height>48</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QComboBox" name="cbFitting">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="sizeAdjustPolicy">
+            <enum>QComboBox::AdjustToContents</enum>
+           </property>
+           <item>
+            <property name="text">
+             <string>Fitting</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Pr inversion</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Invariant</string>
+            </property>
+           </item>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QCheckBox" name="chkBatch">
+           <property name="text">
+            <string>Batch mode</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="1" column="0" colspan="2">
+        <widget class="QTreeView" name="treeView">
+         <property name="contextMenuPolicy">
+          <enum>Qt::NoContextMenu</enum>
+         </property>
+         <property name="acceptDrops">
+          <bool>true</bool>
+         </property>
+         <property name="editTriggers">
+          <set>QAbstractItemView::NoEditTriggers</set>
+         </property>
+         <property name="dragEnabled">
+          <bool>true</bool>
+         </property>
+         <property name="dragDropOverwriteMode">
+          <bool>true</bool>
+         </property>
+         <property name="dragDropMode">
+          <enum>QAbstractItemView::DropOnly</enum>
+         </property>
+         <property name="defaultDropAction">
+          <enum>Qt::CopyAction</enum>
+         </property>
+         <property name="selectionMode">
+          <enum>QAbstractItemView::ExtendedSelection</enum>
+         </property>
+         <attribute name="headerVisible">
+          <bool>false</bool>
+         </attribute>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item row="1" column="0">
+     <layout class="QGridLayout" name="gridLayout_10">
+      <item row="0" column="0" rowspan="2">
+       <layout class="QGridLayout" name="gridLayout_6">
+        <item row="0" column="0">
+         <widget class="QGroupBox" name="groupBox_3">
+          <property name="title">
+           <string>Plot</string>
+          </property>
+          <property name="flat">
+           <bool>false</bool>
+          </property>
+          <property name="checkable">
+           <bool>false</bool>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_3">
+           <item row="0" column="0">
+            <widget class="QPushButton" name="cmdNew">
+             <property name="text">
+              <string>Create New</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QPushButton" name="cmdAppend">
+             <property name="text">
+              <string>Append to</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QComboBox" name="cbgraph">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="sizeAdjustPolicy">
+              <enum>QComboBox::AdjustToContents</enum>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <spacer name="horizontalSpacer_3">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>103</width>
+            <height>48</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+      <item row="1" column="1">
+       <widget class="QPushButton" name="cmdHelp">
+        <property name="text">
+         <string>Help</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWidget" name="theoryTab">
+   <attribute name="title">
+    <string>Theory</string>
+   </attribute>
+   <layout class="QGridLayout" name="gridLayout_8">
+    <item row="0" column="0">
+     <widget class="QGroupBox" name="groupBox_2">
+      <property name="title">
+       <string>Theory</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout_4">
+       <item row="0" column="0">
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <item>
+          <widget class="QPushButton" name="cmdFreeze">
+           <property name="text">
+            <string>Freeze Theory</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_5">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>218</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QPushButton" name="cmdDeleteTheory">
+           <property name="text">
+            <string>Delete</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="1" column="0">
+        <widget class="QTreeView" name="freezeView">
+         <attribute name="headerVisible">
+          <bool>false</bool>
+         </attribute>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item row="1" column="0">
+     <layout class="QGridLayout" name="gridLayout_5">
+      <item row="0" column="0">
+       <widget class="QGroupBox" name="groupBox_4">
+        <property name="title">
+         <string>Plot</string>
+        </property>
+        <layout class="QGridLayout" name="gridLayout_7">
+         <item row="0" column="0">
+          <widget class="QPushButton" name="cmdNew_2">
+           <property name="text">
+            <string>Create New</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QPushButton" name="cmdAppend_2">
+           <property name="text">
+            <string>Append to</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QComboBox" name="cbgraph_2">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="sizeAdjustPolicy">
+            <enum>QComboBox::AdjustToContents</enum>
+           </property>
+           <item>
+            <property name="text">
+             <string>Graph1</string>
+            </property>
+           </item>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <spacer name="horizontalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>108</width>
+          <height>111</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="2" alignment="Qt::AlignBottom">
+       <widget class="QPushButton" name="cmdHelp_2">
+        <property name="text">
+         <string>Help</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <action name="actionDataInfo">
+   <property name="text">
+    <string>Data Info</string>
+   </property>
+  </action>
+  <action name="actionSaveAs">
+   <property name="text">
+    <string>Save As</string>
+   </property>
+  </action>
+  <action name="actionQuickPlot">
+   <property name="text">
+    <string>Quick Plot</string>
+   </property>
+  </action>
+  <action name="actionQuick3DPlot">
+   <property name="text">
+    <string>Quick 3DPlot (slow)</string>
+   </property>
+  </action>
+  <action name="actionEditMask">
+   <property name="text">
+    <string>Edit Mask</string>
+   </property>
+  </action>
+ </widget>
+ <resources>
+  <include location="../../UI/main_resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
Index: src/sas/qtgui/MainWindow/UI/MainWindowUI.ui
===================================================================
--- src/sas/qtgui/MainWindow/UI/MainWindowUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UI/MainWindowUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,503 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>915</width>
+    <height>527</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="../../UI/main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <widget class="QWidget" name="centralwidget"/>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>915</width>
+     <height>21</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menu_File">
+    <property name="title">
+     <string>&amp;File</string>
+    </property>
+    <addaction name="actionLoadData"/>
+    <addaction name="actionLoad_Data_Folder"/>
+    <addaction name="separator"/>
+    <addaction name="actionOpen_Project"/>
+    <addaction name="actionOpen_Analysis"/>
+    <addaction name="separator"/>
+    <addaction name="actionSave"/>
+    <addaction name="actionSave_Analysis"/>
+    <addaction name="separator"/>
+    <addaction name="actionQuit"/>
+   </widget>
+   <widget class="QMenu" name="menuEdit">
+    <property name="title">
+     <string>Edit</string>
+    </property>
+    <widget class="QMenu" name="menuCopy_Params_As">
+     <property name="title">
+      <string>Copy Params To Format...</string>
+     </property>
+     <addaction name="actionExcel"/>
+     <addaction name="actionLatex"/>
+    </widget>
+    <addaction name="actionUndo"/>
+    <addaction name="actionRedo"/>
+    <addaction name="separator"/>
+    <addaction name="actionCopy"/>
+    <addaction name="actionPaste"/>
+    <addaction name="separator"/>
+    <addaction name="menuCopy_Params_As"/>
+    <addaction name="separator"/>
+    <addaction name="actionReport"/>
+    <addaction name="actionReset"/>
+   </widget>
+   <widget class="QMenu" name="menuView">
+    <property name="title">
+     <string>View</string>
+    </property>
+    <addaction name="actionShow_Grid_Window"/>
+    <addaction name="separator"/>
+    <addaction name="actionHide_Toolbar"/>
+    <addaction name="separator"/>
+    <addaction name="actionStartup_Settings"/>
+    <addaction name="separator"/>
+    <addaction name="actionCategry_Manager"/>
+   </widget>
+   <widget class="QMenu" name="menuTool">
+    <property name="title">
+     <string>Tool</string>
+    </property>
+    <addaction name="actionData_Operation"/>
+    <addaction name="separator"/>
+    <addaction name="actionSLD_Calculator"/>
+    <addaction name="actionDensity_Volume_Calculator"/>
+    <addaction name="actionSlit_Size_Calculator"/>
+    <addaction name="actionKeissig_Calculator"/>
+    <addaction name="actionSAS_Resolution_Estimator"/>
+    <addaction name="actionGeneric_Scattering_Calculator"/>
+    <addaction name="separator"/>
+    <addaction name="actionPython_Shell_Editor"/>
+    <addaction name="actionImage_Viewer"/>
+   </widget>
+   <widget class="QMenu" name="menuFitting">
+    <property name="title">
+     <string>Fitting</string>
+    </property>
+    <addaction name="actionNew_Fit_Page"/>
+    <addaction name="separator"/>
+    <addaction name="actionConstrained_Fit"/>
+    <addaction name="actionCombine_Batch_Fit"/>
+    <addaction name="separator"/>
+    <addaction name="actionFit_Options"/>
+    <addaction name="actionFit_Results"/>
+    <addaction name="separator"/>
+    <addaction name="actionChain_Fitting"/>
+    <addaction name="separator"/>
+    <addaction name="actionEdit_Custom_Model"/>
+   </widget>
+   <widget class="QMenu" name="menuWindow">
+    <property name="title">
+     <string>Window</string>
+    </property>
+    <addaction name="actionCascade"/>
+    <addaction name="actionTile"/>
+    <addaction name="separator"/>
+    <addaction name="actionArrange_Icons"/>
+    <addaction name="actionNext"/>
+    <addaction name="actionPrevious"/>
+    <addaction name="separator"/>
+   </widget>
+   <widget class="QMenu" name="menuAnalysis">
+    <property name="title">
+     <string>Analysis</string>
+    </property>
+    <addaction name="actionFitting"/>
+    <addaction name="actionInversion"/>
+    <addaction name="actionInvariant"/>
+   </widget>
+   <widget class="QMenu" name="menuHelp">
+    <property name="title">
+     <string>Help</string>
+    </property>
+    <addaction name="actionDocumentation"/>
+    <addaction name="separator"/>
+    <addaction name="actionTutorial"/>
+    <addaction name="separator"/>
+    <addaction name="actionAcknowledge"/>
+    <addaction name="separator"/>
+    <addaction name="actionAbout"/>
+    <addaction name="actionCheck_for_update"/>
+   </widget>
+   <addaction name="menu_File"/>
+   <addaction name="menuEdit"/>
+   <addaction name="menuView"/>
+   <addaction name="menuTool"/>
+   <addaction name="menuAnalysis"/>
+   <addaction name="menuFitting"/>
+   <addaction name="menuWindow"/>
+   <addaction name="menuHelp"/>
+  </widget>
+  <widget class="QStatusBar" name="statusbar">
+   <property name="sizePolicy">
+    <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+     <horstretch>0</horstretch>
+     <verstretch>0</verstretch>
+    </sizepolicy>
+   </property>
+  </widget>
+  <widget class="QToolBar" name="toolBar">
+   <property name="windowTitle">
+    <string>toolBar</string>
+   </property>
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+   <addaction name="actionReset"/>
+   <addaction name="actionSave"/>
+   <addaction name="actionReport"/>
+   <addaction name="actionUndo"/>
+   <addaction name="actionRedo"/>
+   <addaction name="actionCopy"/>
+   <addaction name="actionPaste"/>
+   <addaction name="actionBookmarks"/>
+  </widget>
+  <action name="actionReset">
+   <property name="icon">
+    <iconset resource="../../UI/main_resources.qrc">
+     <normaloff>:/res/reset.png</normaloff>:/res/reset.png</iconset>
+   </property>
+   <property name="text">
+    <string>Reset Page</string>
+   </property>
+   <property name="toolTip">
+    <string>Reset</string>
+   </property>
+  </action>
+  <action name="actionSave">
+   <property name="icon">
+    <iconset resource="../../UI/main_resources.qrc">
+     <normaloff>:/res/save.png</normaloff>:/res/save.png</iconset>
+   </property>
+   <property name="text">
+    <string>Save Project</string>
+   </property>
+   <property name="toolTip">
+    <string>Save</string>
+   </property>
+  </action>
+  <action name="actionReport">
+   <property name="icon">
+    <iconset resource="../../UI/main_resources.qrc">
+     <normaloff>:/res/report.png</normaloff>:/res/report.png</iconset>
+   </property>
+   <property name="text">
+    <string>Report Results</string>
+   </property>
+   <property name="toolTip">
+    <string>report</string>
+   </property>
+  </action>
+  <action name="actionUndo">
+   <property name="icon">
+    <iconset resource="../../UI/main_resources.qrc">
+     <normaloff>:/res/undo.png</normaloff>
+     <normalon>res/undo.png</normalon>:/res/undo.png</iconset>
+   </property>
+   <property name="text">
+    <string>Undo</string>
+   </property>
+  </action>
+  <action name="actionRedo">
+   <property name="icon">
+    <iconset resource="../../UI/main_resources.qrc">
+     <normaloff>:/res/redo.png</normaloff>:/res/redo.png</iconset>
+   </property>
+   <property name="text">
+    <string>Redo</string>
+   </property>
+   <property name="toolTip">
+    <string>Redo</string>
+   </property>
+  </action>
+  <action name="actionCopy">
+   <property name="icon">
+    <iconset resource="../../UI/main_resources.qrc">
+     <normaloff>:/res/copy.png</normaloff>:/res/copy.png</iconset>
+   </property>
+   <property name="text">
+    <string>Copy Params</string>
+   </property>
+   <property name="toolTip">
+    <string>Copy parameter values</string>
+   </property>
+  </action>
+  <action name="actionPaste">
+   <property name="icon">
+    <iconset resource="../../UI/main_resources.qrc">
+     <normaloff>:/res/paste.png</normaloff>:/res/paste.png</iconset>
+   </property>
+   <property name="text">
+    <string>Paste Params</string>
+   </property>
+   <property name="toolTip">
+    <string>Paste parameter values</string>
+   </property>
+  </action>
+  <action name="actionBookmarks">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="../../UI/main_resources.qrc">
+     <normaloff>:/res/bookmark.png</normaloff>:/res/bookmark.png</iconset>
+   </property>
+   <property name="text">
+    <string>Bookmarks</string>
+   </property>
+  </action>
+  <action name="actionPerspective">
+   <property name="text">
+    <string>Perspective</string>
+   </property>
+  </action>
+  <action name="actionLoadData">
+   <property name="text">
+    <string>Load Data File(s)</string>
+   </property>
+  </action>
+  <action name="actionLoad_Data_Folder">
+   <property name="text">
+    <string>Load Data Folder</string>
+   </property>
+  </action>
+  <action name="actionOpen_Project">
+   <property name="text">
+    <string>Open Project</string>
+   </property>
+  </action>
+  <action name="actionOpen_Analysis">
+   <property name="text">
+    <string>Open Analysis</string>
+   </property>
+  </action>
+  <action name="actionSave_Analysis">
+   <property name="text">
+    <string>Save Analysis</string>
+   </property>
+  </action>
+  <action name="actionQuit">
+   <property name="text">
+    <string>Quit</string>
+   </property>
+  </action>
+  <action name="actionShow_Grid_Window">
+   <property name="text">
+    <string>Show Grid Window</string>
+   </property>
+  </action>
+  <action name="actionHide_Toolbar">
+   <property name="text">
+    <string>Hide Toolbar</string>
+   </property>
+  </action>
+  <action name="actionStartup_Settings">
+   <property name="text">
+    <string>Startup Settings</string>
+   </property>
+  </action>
+  <action name="actionCategry_Manager">
+   <property name="text">
+    <string>Categry Manager</string>
+   </property>
+  </action>
+  <action name="actionData_Operation">
+   <property name="text">
+    <string>Data Operation</string>
+   </property>
+  </action>
+  <action name="actionSLD_Calculator">
+   <property name="text">
+    <string>SLD Calculator</string>
+   </property>
+  </action>
+  <action name="actionDensity_Volume_Calculator">
+   <property name="text">
+    <string>Density/Volume Calculator</string>
+   </property>
+  </action>
+  <action name="actionSlit_Size_Calculator">
+   <property name="text">
+    <string>Slit Size Calculator</string>
+   </property>
+  </action>
+  <action name="actionSAS_Resolution_Estimator">
+   <property name="text">
+    <string>SAS Resolution Estimator</string>
+   </property>
+  </action>
+  <action name="actionGeneric_Scattering_Calculator">
+   <property name="text">
+    <string>Generic Scattering Calculator</string>
+   </property>
+  </action>
+  <action name="actionPython_Shell_Editor">
+   <property name="text">
+    <string>Python Shell/Editor</string>
+   </property>
+  </action>
+  <action name="actionImage_Viewer">
+   <property name="text">
+    <string>Image Viewer</string>
+   </property>
+  </action>
+  <action name="actionNew_Fit_Page">
+   <property name="text">
+    <string>New Fit Page</string>
+   </property>
+  </action>
+  <action name="actionConstrained_Fit">
+   <property name="text">
+    <string>Constrained or Simultaneous Fit</string>
+   </property>
+  </action>
+  <action name="actionCombine_Batch_Fit">
+   <property name="text">
+    <string>Combine Batch Fit</string>
+   </property>
+  </action>
+  <action name="actionFit_Options">
+   <property name="text">
+    <string>Fit Options</string>
+   </property>
+  </action>
+  <action name="actionFit_Results">
+   <property name="text">
+    <string>Fit Results</string>
+   </property>
+  </action>
+  <action name="actionChain_Fitting">
+   <property name="text">
+    <string>Chain Fitting (BatchFit only)</string>
+   </property>
+  </action>
+  <action name="actionEdit_Custom_Model">
+   <property name="text">
+    <string>Edit Custom Model</string>
+   </property>
+  </action>
+  <action name="actionCascade">
+   <property name="text">
+    <string>Cascade</string>
+   </property>
+  </action>
+  <action name="actionTile">
+   <property name="text">
+    <string>Tile</string>
+   </property>
+  </action>
+  <action name="actionTile_Vertically">
+   <property name="text">
+    <string>Tile Vertically</string>
+   </property>
+  </action>
+  <action name="actionArrange_Icons">
+   <property name="text">
+    <string>Arrange Icons</string>
+   </property>
+  </action>
+  <action name="actionNext">
+   <property name="text">
+    <string>Next</string>
+   </property>
+  </action>
+  <action name="actionPrevious">
+   <property name="text">
+    <string>Previous</string>
+   </property>
+  </action>
+  <action name="actionFitting">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Fitting</string>
+   </property>
+  </action>
+  <action name="actionInversion">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Pr Inversion</string>
+   </property>
+  </action>
+  <action name="actionInvariant">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Invariant</string>
+   </property>
+  </action>
+  <action name="actionDocumentation">
+   <property name="text">
+    <string>Documentation</string>
+   </property>
+  </action>
+  <action name="actionTutorial">
+   <property name="text">
+    <string>Tutorial</string>
+   </property>
+  </action>
+  <action name="actionAcknowledge">
+   <property name="text">
+    <string>Acknowledge</string>
+   </property>
+  </action>
+  <action name="actionAbout">
+   <property name="text">
+    <string>About</string>
+   </property>
+  </action>
+  <action name="actionCheck_for_update">
+   <property name="text">
+    <string>Check for update</string>
+   </property>
+  </action>
+  <action name="actionExcel">
+   <property name="text">
+    <string>Excel</string>
+   </property>
+  </action>
+  <action name="actionLatex">
+   <property name="text">
+    <string>Latex</string>
+   </property>
+  </action>
+  <action name="actionKeissig_Calculator">
+   <property name="text">
+    <string>Kiessig Thickness Calculator</string>
+   </property>
+  </action>
+ </widget>
+ <resources>
+  <include location="../../UI/main_resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
Index: src/sas/qtgui/MainWindow/UI/TabbedFileLoadUI.ui
===================================================================
--- src/sas/qtgui/MainWindow/UI/TabbedFileLoadUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UI/TabbedFileLoadUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DataLoadWidget</class>
+ <widget class="QTabWidget" name="DataLoadWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>481</width>
+    <height>620</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>TabWidget</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="../../UI/main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <property name="currentIndex">
+   <number>0</number>
+  </property>
+  <widget class="QWidget" name="dataTab">
+   <attribute name="title">
+    <string>Data</string>
+   </attribute>
+   <layout class="QGridLayout" name="gridLayout_6">
+    <item row="0" column="0">
+     <widget class="QLabel" name="label">
+      <property name="text">
+       <string>Selection Options</string>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="0">
+     <widget class="QComboBox" name="cbSelect">
+      <item>
+       <property name="text">
+        <string>Select all</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>Unselect all</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>Select all 1D</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>Unselect all 1D</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>Select all 2D</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>Unselect all 2D</string>
+       </property>
+      </item>
+     </widget>
+    </item>
+    <item row="1" column="1" colspan="2">
+     <spacer name="horizontalSpacer_2">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>352</width>
+        <height>20</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item row="2" column="0" colspan="3">
+     <widget class="QGroupBox" name="groupBox">
+      <property name="title">
+       <string>Data</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout_2">
+       <item row="0" column="0">
+        <layout class="QGridLayout" name="gridLayout">
+         <item row="0" column="0" colspan="4">
+          <widget class="QTreeView" name="treeView">
+           <attribute name="headerVisible">
+            <bool>false</bool>
+           </attribute>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QPushButton" name="cmdLoad">
+           <property name="text">
+            <string>Load</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QPushButton" name="cmdFreeze">
+           <property name="text">
+            <string>Freeze</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="2">
+          <spacer name="horizontalSpacer_4">
+           <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 row="1" column="3">
+          <widget class="QPushButton" name="cmdDeleteData">
+           <property name="text">
+            <string>Delete</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="1" column="0">
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <item>
+          <widget class="QPushButton" name="cmdSendTo">
+           <property name="text">
+            <string>Send to</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QComboBox" name="cbFitting">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="sizeAdjustPolicy">
+            <enum>QComboBox::AdjustToContents</enum>
+           </property>
+           <item>
+            <property name="text">
+             <string>Fitting</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Pr inversion</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Invariant</string>
+            </property>
+           </item>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="chkBatch">
+           <property name="text">
+            <string>Batch mode</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>197</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item row="3" column="0" colspan="2">
+     <widget class="QGroupBox" name="groupBox_3">
+      <property name="title">
+       <string>Plot</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout_3">
+       <item row="0" column="0">
+        <widget class="QPushButton" name="cmdNew">
+         <property name="text">
+          <string>New</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QPushButton" name="cmdAppend">
+         <property name="text">
+          <string>Append to</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QComboBox" name="cbgraph">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="sizeAdjustPolicy">
+          <enum>QComboBox::AdjustToContents</enum>
+         </property>
+         <item>
+          <property name="text">
+           <string>Graph1</string>
+          </property>
+         </item>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item row="3" column="2">
+     <spacer name="horizontalSpacer_3">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>287</width>
+        <height>20</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWidget" name="theoryTab">
+   <attribute name="title">
+    <string>Theory</string>
+   </attribute>
+   <layout class="QGridLayout" name="gridLayout_7">
+    <item row="0" column="0" colspan="2">
+     <widget class="QGroupBox" name="groupBox_2">
+      <property name="title">
+       <string>Theory</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout_4">
+       <item row="1" column="0">
+        <widget class="QPushButton" name="cmdDeleteTheory">
+         <property name="text">
+          <string>Delete</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <spacer name="horizontalSpacer_5">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>353</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="0" column="0" colspan="2">
+        <widget class="QTreeView" name="freezeView">
+         <attribute name="headerVisible">
+          <bool>false</bool>
+         </attribute>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item row="1" column="0">
+     <widget class="QGroupBox" name="groupBox_4">
+      <property name="title">
+       <string>Plot</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout_5">
+       <item row="0" column="0">
+        <widget class="QPushButton" name="cmdNew_2">
+         <property name="text">
+          <string>New</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QPushButton" name="cmdAppend_2">
+         <property name="text">
+          <string>Append to</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QComboBox" name="cbgraph_2">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="sizeAdjustPolicy">
+          <enum>QComboBox::AdjustToContents</enum>
+         </property>
+         <item>
+          <property name="text">
+           <string>Graph1</string>
+          </property>
+         </item>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item row="1" column="1">
+     <spacer name="horizontalSpacer_6">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>287</width>
+        <height>20</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <resources>
+  <include location="../../UI/main_resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
Index: src/sas/qtgui/MainWindow/UI/WelcomePanelUI.ui
===================================================================
--- src/sas/qtgui/MainWindow/UI/WelcomePanelUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UI/WelcomePanelUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>WelcomePanelUI</class>
+ <widget class="QDialog" name="WelcomePanelUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>746</width>
+    <height>947</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="imgSasView">
+     <property name="text">
+      <string/>
+     </property>
+     <property name="pixmap">
+      <pixmap resource="../../UI/main_resources.qrc">:/res/SVwelcome.png</pixmap>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QLabel" name="lblAcknowledgements">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>This work originally developed as part of the DANSE project funded by the NSF under grant DMR-0520547, and currently maintained by NIST, UMD, ORNL, ISIS, ESS, ILL and ANSTO.</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0">
+    <widget class="QLabel" name="lblVersion">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;SasView 4.0.0-Alpha&lt;br/&gt;Build: 1&lt;br/&gt;(c) 2009 - 2017, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL and ANSTO&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <widget class="QLabel" name="lblLink">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Comments? Bugs? Requests?&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;mailto:help@sasview.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Send us a ticket at: help@sasview.org&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../UI/main_resources.qrc"/>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
Index: src/sas/qtgui/MainWindow/UnitTesting/AboutBoxTest.py
===================================================================
--- src/sas/qtgui/MainWindow/UnitTesting/AboutBoxTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UnitTesting/AboutBoxTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,103 @@
+import sys
+import unittest
+import webbrowser
+
+from PyQt4.QtGui import *
+from PyQt4.QtTest import QTest
+from PyQt4.QtCore import *
+from mock import MagicMock
+
+# set up import paths
+import path_prepare
+
+# Local
+from sas.qtgui.MainWindow.AboutBox import AboutBox
+import sas.qtgui.Utilities.LocalConfig as LocalConfig
+
+app = QApplication(sys.argv)
+
+class AboutBoxTest(unittest.TestCase):
+    '''Test the AboutBox'''
+    def setUp(self):
+        '''Create the AboutBox'''
+        self.widget = AboutBox(None)
+
+    def tearDown(self):
+        '''Destroy the AboutBox'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QWidget)
+        self.assertEqual(self.widget.windowTitle(), "About")
+        self.assertEqual(self.widget.cmdOK.text(), "OK")
+
+        self.assertIn("SasView", self.widget.label_2.text())
+        # Link buttons pixmaps don't contain image filenames, so can't check this.
+        # self.assertEqual(self.widget.cmdLinkUT.icon().name(), "utlogo.gif")
+
+
+    def testVersion(self):
+        """
+        Assure the version number is as expected
+        """
+        version = self.widget.lblVersion
+        self.assertIsInstance(version, QLabel)
+        self.assertEqual(str(version.text()), str(LocalConfig.__version__))
+
+    def testAbout(self):
+        """
+        Assure the about label is filled properly
+        """
+        about = self.widget.lblAbout
+        self.assertIsInstance(about, QLabel)
+        # build version
+        self.assertIn(str(LocalConfig.__build__), about.text())
+        # License
+        self.assertIn(str(LocalConfig._copyright), about.text())
+        # URLs
+        self.assertIn(str(LocalConfig._homepage), about.text())
+        self.assertIn(str(LocalConfig.__download_page__), about.text())
+        self.assertIn(str(LocalConfig._license), about.text())
+
+        # Are links enabled?
+        self.assertTrue(about.openExternalLinks())
+
+    def testAddActions(self):
+        """
+        Assure link buttons are set up correctly
+        """
+        webbrowser.open = MagicMock()
+        all_hosts = [
+                LocalConfig._nist_url,
+                LocalConfig._umd_url,
+                LocalConfig._sns_url,
+                LocalConfig._nsf_url,
+                LocalConfig._isis_url,
+                LocalConfig._ess_url,
+                LocalConfig._ill_url,
+                LocalConfig._ansto_url,
+                LocalConfig._inst_url]
+
+        # Press the buttons
+        buttonList = self.widget.findChildren(QPushButton)
+        for button in buttonList:
+            QTest.mouseClick(button, Qt.LeftButton)
+            #open_link = webbrowser.open.call_args
+            args, _ = webbrowser.open.call_args
+            # args[0] contains the actual argument sent to open()
+            self.assertIn(args[0], all_hosts)
+
+        # The above test also greedily catches the OK button,
+        # so let's test it separately.
+        # Show the widget
+        self.widget.show()
+        self.assertTrue(self.widget.isVisible())
+        # Click on the OK button
+        QTest.mouseClick(self.widget.cmdOK, Qt.LeftButton)
+        # assure the widget is no longer seen
+        self.assertFalse(self.widget.isVisible())
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/MainWindow/UnitTesting/DataExplorerTest.py
===================================================================
--- src/sas/qtgui/MainWindow/UnitTesting/DataExplorerTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UnitTesting/DataExplorerTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,807 @@
+import sys
+import unittest
+
+from PyQt4.QtGui import *
+from PyQt4.QtTest import QTest
+from PyQt4.QtCore import *
+from mock import MagicMock
+from mock import patch
+from mpl_toolkits.mplot3d import Axes3D
+
+# set up import paths
+import path_prepare
+
+# Local
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sascalc.dataloader.loader import Loader
+from sas.sasgui.guiframe.data_manager import DataManager
+
+from sas.qtgui.MainWindow.DataExplorer import DataExplorerWindow
+from sas.qtgui.MainWindow.GuiManager import GuiManager
+from sas.qtgui.Utilities.GuiUtils import *
+from UnitTesting.TestUtils import QtSignalSpy
+from sas.qtgui.Plotting.Plotter import Plotter
+from sas.qtgui.Plotting.Plotter2D import Plotter2D
+import sas.qtgui.Plotting.PlotHelper as PlotHelper
+
+app = QApplication(sys.argv)
+
+class DataExplorerTest(unittest.TestCase):
+    '''Test the Data Explorer GUI'''
+    def setUp(self):
+        '''Create the GUI'''
+        class MyPerspective(object):
+            def communicator(self):
+                return Communicate()
+            def allowBatch(self):
+                return False
+            def setData(self, data_item=None):
+                return None
+            def title(self):
+                return "Dummy Perspective"
+
+        class dummy_manager(object):
+            def communicator(self):
+                return Communicate()
+            def perspective(self):
+                return MyPerspective()
+            def workspace(self):
+                return None
+
+        self.form = DataExplorerWindow(None, dummy_manager())
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.form.close()
+        self.form = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        # Tab widget
+        self.assertIsInstance(self.form, QTabWidget)
+        self.assertEqual(self.form.count(), 2)
+
+        # Buttons - data tab
+        self.assertEqual(self.form.cmdLoad.text(), "Load data")
+        self.assertEqual(self.form.cmdDeleteData.text(), "Delete")
+        self.assertEqual(self.form.cmdDeleteTheory.text(), "Delete")
+        self.assertEqual(self.form.cmdFreeze.text(), "Freeze Theory")
+        self.assertEqual(self.form.cmdSendTo.text(), "Send data to")
+        self.assertEqual(self.form.cmdSendTo.iconSize(), QSize(48, 48))
+        self.assertIsInstance(self.form.cmdSendTo.icon(), QIcon)
+        self.assertEqual(self.form.chkBatch.text(), "Batch mode")
+        self.assertFalse(self.form.chkBatch.isChecked())
+
+        # Buttons - theory tab
+
+        # Combo boxes
+        self.assertEqual(self.form.cbSelect.count(), 6)
+        self.assertEqual(self.form.cbSelect.currentIndex(), 0)
+
+        # Models - data
+        self.assertIsInstance(self.form.model, QStandardItemModel)
+        self.assertEqual(self.form.treeView.model().rowCount(), 0)
+        self.assertEqual(self.form.treeView.model().columnCount(), 0)
+        self.assertEqual(self.form.model.rowCount(), 0)
+        self.assertEqual(self.form.model.columnCount(), 0)
+        self.assertIsInstance(self.form.data_proxy, QSortFilterProxyModel)
+        self.assertEqual(self.form.data_proxy.sourceModel(), self.form.model)
+        self.assertEqual("[^()]", str(self.form.data_proxy.filterRegExp().pattern()))
+        self.assertIsInstance(self.form.treeView, QTreeView)
+
+        # Models - theory
+        self.assertIsInstance(self.form.theory_model, QStandardItemModel)
+        self.assertEqual(self.form.freezeView.model().rowCount(), 0)
+        self.assertEqual(self.form.freezeView.model().columnCount(), 0)
+        self.assertEqual(self.form.theory_model.rowCount(), 0)
+        self.assertEqual(self.form.theory_model.columnCount(), 0)
+        self.assertIsInstance(self.form.theory_proxy, QSortFilterProxyModel)
+        self.assertEqual(self.form.theory_proxy.sourceModel(), self.form.theory_model)
+        self.assertEqual("[^()]", str(self.form.theory_proxy.filterRegExp().pattern()))
+        self.assertIsInstance(self.form.freezeView, QTreeView)
+
+    def testWidgets(self):
+        """
+        Test if all required widgets got added
+        """
+    def testLoadButton(self):
+        loadButton = self.form.cmdLoad
+
+        filename = "cyl_400_20.txt"
+        # Initialize signal spy instances
+        spy_file_read = QtSignalSpy(self.form, self.form.communicator.fileReadSignal)
+
+        # Return no files.
+        QtGui.QFileDialog.getOpenFileNames = MagicMock(return_value=None)
+
+        # Click on the Load button
+        QTest.mouseClick(loadButton, Qt.LeftButton)
+
+        # Test the getOpenFileName() dialog called once
+        self.assertTrue(QtGui.QFileDialog.getOpenFileNames.called)
+        QtGui.QFileDialog.getOpenFileNames.assert_called_once()
+
+        # Make sure the signal has not been emitted
+        self.assertEqual(spy_file_read.count(), 0)
+
+        # Now, return a single file
+        QtGui.QFileDialog.getOpenFileNames = MagicMock(return_value=filename)
+
+        # Click on the Load button
+        QTest.mouseClick(loadButton, Qt.LeftButton)
+        QtGui.qApp.processEvents()
+
+        # Test the getOpenFileName() dialog called once
+        self.assertTrue(QtGui.QFileDialog.getOpenFileNames.called)
+        QtGui.QFileDialog.getOpenFileNames.assert_called_once()
+
+        # Expected one spy instance
+        #self.assertEqual(spy_file_read.count(), 1)
+        #self.assertIn(filename, str(spy_file_read.called()[0]['args'][0]))
+
+    def testLoadFiles(self):
+        """
+        Test progress bar update while loading of multiple files
+        """
+        # Set up the spy on progress bar update signal
+        spy_progress_bar_update = QtSignalSpy(self.form,
+            self.form.communicator.progressBarUpdateSignal)
+
+        # Populate the model
+        filename = ["cyl_400_20.txt", "Dec07031.ASC", "cyl_400_20.txt"]
+        self.form.readData(filename)
+
+        # 0, 0, 33, 66, -1 -> 5 signals reaching progressBar
+        self.assertEqual(spy_progress_bar_update.count(), 5)
+
+        expected_list = [0, 0, 33, 66, -1]
+        spied_list = [spy_progress_bar_update.called()[i]['args'][0] for i in xrange(5)]
+        self.assertEqual(expected_list, spied_list)
+        
+    def testDeleteButton(self):
+        """
+        Functionality of the delete button
+        """
+        deleteButton = self.form.cmdDeleteData
+
+        # Mock the confirmation dialog with return=No
+        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.No)
+
+        # Populate the model
+        filename = ["cyl_400_20.txt", "Dec07031.ASC", "cyl_400_20.txt"]
+        self.form.readData(filename)
+
+        # Assure the model contains three items
+        self.assertEqual(self.form.model.rowCount(), 3)
+
+        # Assure the checkboxes are on
+        item1 = self.form.model.item(0)
+        item2 = self.form.model.item(1)
+        item3 = self.form.model.item(2)
+        self.assertTrue(item1.checkState() == QtCore.Qt.Checked)
+        self.assertTrue(item2.checkState() == QtCore.Qt.Checked)
+        self.assertTrue(item3.checkState() == QtCore.Qt.Checked)
+
+        # Click on the delete  button
+        QTest.mouseClick(deleteButton, Qt.LeftButton)
+
+        # Test the warning dialog called once
+        self.assertTrue(QtGui.QMessageBox.question.called)
+
+        # Assure the model still contains the items
+        self.assertEqual(self.form.model.rowCount(), 3)
+
+        # Now, mock the confirmation dialog with return=Yes
+        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.Yes)
+
+        # Click on the delete  button
+        QTest.mouseClick(deleteButton, Qt.LeftButton)
+
+        # Test the warning dialog called once
+        self.assertTrue(QtGui.QMessageBox.question.called)
+
+        # Assure the model contains no items
+        self.assertEqual(self.form.model.rowCount(), 0)
+
+        # Click delete once again to assure no nasty behaviour on empty model
+        QTest.mouseClick(deleteButton, Qt.LeftButton)
+
+    def testDeleteTheory(self):
+        """
+        Test that clicking "Delete" in theories tab removes selected indices
+        """
+        deleteButton = self.form.cmdDeleteTheory
+
+        # Mock the confirmation dialog with return=No
+        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.No)
+
+        # Populate the model
+        item1 = QtGui.QStandardItem(True)
+        item1.setCheckable(True)
+        item1.setCheckState(QtCore.Qt.Checked)
+        item1.setText("item 1")
+        self.form.theory_model.appendRow(item1)
+        item2 = QtGui.QStandardItem(True)
+        item2.setCheckable(True)
+        item2.setCheckState(QtCore.Qt.Unchecked)
+        item2.setText("item 2")
+        self.form.theory_model.appendRow(item2)
+
+        # Assure the model contains two items
+        self.assertEqual(self.form.theory_model.rowCount(), 2)
+
+        # Assure the checkboxes are on
+        self.assertTrue(item1.checkState() == QtCore.Qt.Checked)
+        self.assertTrue(item2.checkState() == QtCore.Qt.Unchecked)
+
+        # Click on the delete  button
+        QTest.mouseClick(deleteButton, Qt.LeftButton)
+
+        # Test the warning dialog called once
+        self.assertTrue(QtGui.QMessageBox.question.called)
+
+        # Assure the model still contains the items
+        self.assertEqual(self.form.theory_model.rowCount(), 2)
+
+        # Now, mock the confirmation dialog with return=Yes
+        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.Yes)
+
+        # Click on the delete  button
+        QTest.mouseClick(deleteButton, Qt.LeftButton)
+
+        # Test the warning dialog called once
+        self.assertTrue(QtGui.QMessageBox.question.called)
+
+        # Assure the model contains 1 item
+        self.assertEqual(self.form.theory_model.rowCount(), 1)
+
+        # Set the remaining item to checked
+        self.form.theory_model.item(0).setCheckState(QtCore.Qt.Checked)
+
+        # Click on the delete button again
+        QTest.mouseClick(deleteButton, Qt.LeftButton)
+
+        # Assure the model contains no items
+        self.assertEqual(self.form.theory_model.rowCount(), 0)
+
+        # Click delete once again to assure no nasty behaviour on empty model
+        QTest.mouseClick(deleteButton, Qt.LeftButton)
+
+
+    def testSendToButton(self):
+        """
+        Test that clicking the Send To button sends checked data to a perspective
+        """
+        # Send empty data
+        mocked_perspective = self.form.parent.perspective()
+        mocked_perspective.setData = MagicMock()
+
+        # Click on the Send To  button
+        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
+
+        # The set_data method not called
+        self.assertFalse(mocked_perspective.setData.called)
+               
+        # Populate the model
+        filename = ["cyl_400_20.txt"]
+        self.form.readData(filename)
+
+        # setData is the method we want to see called
+        mocked_perspective = self.form.parent.perspective()
+        mocked_perspective.setData = MagicMock(filename)
+
+        # Assure the checkbox is on
+        self.form.cbSelect.setCurrentIndex(0)
+
+        # Click on the Send To  button
+        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
+
+        # Test the set_data method called once
+        #self.assertTrue(mocked_perspective.setData.called)
+
+        # open another file
+        filename = ["cyl_400_20.txt"]
+        self.form.readData(filename)
+
+        # Mock the warning message
+        QtGui.QMessageBox = MagicMock()
+
+        # Click on the button
+        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
+
+        # Assure the message box popped up
+        QtGui.QMessageBox.assert_called_once()
+
+    def testDataSelection(self):
+        """
+        Tests the functionality of the Selection Option combobox
+        """
+        # Populate the model with 1d and 2d data
+        filename = ["cyl_400_20.txt", "Dec07031.ASC"]
+        self.form.readData(filename)
+
+        # Unselect all data
+        self.form.cbSelect.setCurrentIndex(1)
+
+        # Test the current selection
+        item1D = self.form.model.item(0)
+        item2D = self.form.model.item(1)
+        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
+        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)        
+
+        # Select all data
+        self.form.cbSelect.setCurrentIndex(0)
+
+        # Test the current selection
+        self.assertTrue(item1D.checkState() == QtCore.Qt.Checked)
+        self.assertTrue(item2D.checkState() == QtCore.Qt.Checked)        
+
+        # select 1d data
+        self.form.cbSelect.setCurrentIndex(2)
+
+        # Test the current selection
+        self.assertTrue(item1D.checkState() == QtCore.Qt.Checked)
+        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)        
+
+        # unselect 1d data
+        self.form.cbSelect.setCurrentIndex(3)
+
+        # Test the current selection
+        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
+        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)        
+
+        # select 2d data
+        self.form.cbSelect.setCurrentIndex(4)
+
+        # Test the current selection
+        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
+        self.assertTrue(item2D.checkState() == QtCore.Qt.Checked)        
+
+        # unselect 2d data
+        self.form.cbSelect.setCurrentIndex(5)
+
+        # Test the current selection
+        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
+        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)        
+
+        # choose impossible index and assure the code raises
+        #with self.assertRaises(Exception):
+        #    self.form.cbSelect.setCurrentIndex(6)
+
+    def testFreezeTheory(self):
+        """
+        Assure theory freeze functionality works
+        """
+        # Not yet tested - agree on design first.
+        pass
+
+    def testRecursivelyCloneItem(self):
+        """
+        Test the rescursive QAbstractItem/QStandardItem clone
+        """
+        # Create an item with several branches
+        item1 = QtGui.QStandardItem()
+        item2 = QtGui.QStandardItem()
+        item3 = QtGui.QStandardItem()
+        item4 = QtGui.QStandardItem()
+        item5 = QtGui.QStandardItem()
+        item6 = QtGui.QStandardItem()
+
+        item4.appendRow(item5)
+        item2.appendRow(item4)
+        item2.appendRow(item6)
+        item1.appendRow(item2)
+        item1.appendRow(item3)
+
+        # Clone
+        new_item = self.form.recursivelyCloneItem(item1)
+
+        # assure the trees look identical
+        self.assertEqual(item1.rowCount(), new_item.rowCount())
+        self.assertEqual(item1.child(0).rowCount(), new_item.child(0).rowCount())
+        self.assertEqual(item1.child(1).rowCount(), new_item.child(1).rowCount())
+        self.assertEqual(item1.child(0).child(0).rowCount(), new_item.child(0).child(0).rowCount())
+
+    def testReadData(self):
+        """
+        Test the low level readData() method
+        """
+        filename = ["cyl_400_20.txt"]
+        self.form.manager.add_data = MagicMock()
+
+        # Initialize signal spy instances
+        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
+        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
+
+        # Read in the file
+        self.form.readData(filename)
+
+        # Expected two status bar updates
+        self.assertEqual(spy_status_update.count(), 2)
+        self.assertIn(filename[0], str(spy_status_update.called()[0]['args'][0]))
+
+
+        # Check that the model contains the item
+        self.assertEqual(self.form.model.rowCount(), 1)
+        self.assertEqual(self.form.model.columnCount(), 1)
+
+        # The 0th item header should be the name of the file
+        model_item = self.form.model.index(0,0)
+        model_name = str(self.form.model.data(model_item).toString())
+        self.assertEqual(model_name, filename[0])
+
+    def skip_testDisplayHelp(self): # Skip due to help path change
+        """
+        Test that the Help window gets shown correctly
+        """
+        partial_url = "sasgui/guiframe/data_explorer_help.html"
+        button1 = self.form.cmdHelp
+        button2 = self.form.cmdHelp_2
+
+        # Click on the Help button
+        QTest.mouseClick(button1, Qt.LeftButton)
+        qApp.processEvents()
+
+        # Check the browser
+        self.assertIn(partial_url, str(self.form._helpView.url()))
+        # Close the browser
+        self.form._helpView.close()
+
+        # Click on the Help_2 button
+        QTest.mouseClick(button2, Qt.LeftButton)
+        qApp.processEvents()
+        # Check the browser
+        self.assertIn(partial_url, str(self.form._helpView.url()))
+
+    def testLoadFile(self):
+        """
+        Test the threaded call to readData()
+        """
+        #self.form.loadFile()
+        pass
+
+    def testGetWList(self):
+        """
+        Test the list of known extensions
+        """
+        w_list = self.form.getWlist()
+
+        defaults = 'All (*.*);;canSAS files (*.xml);;SESANS files' +\
+            ' (*.ses);;ASCII files (*.txt);;IGOR 2D files (*.asc);;' +\
+            'IGOR/DAT 2D Q_map files (*.dat);;IGOR 1D files (*.abs);;'+\
+            'HFIR 1D files (*.d1d);;DANSE files (*.sans);;NXS files (*.nxs)'
+        default_list = defaults.split(';;')
+
+        for def_format in default_list:
+            self.assertIn(def_format, w_list)
+       
+    def testLoadComplete(self):
+        """
+        Test the callback method updating the data object
+        """
+        message="Loading Data Complete"
+        data_dict = {"a1":Data1D()}
+        output_data = (data_dict, message)
+
+        self.form.manager.add_data = MagicMock()
+
+        # Initialize signal spy instances
+        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
+        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
+
+        # Read in the file
+        self.form.loadComplete(output_data)
+
+        # "Loading data complete" no longer sent in LoadFile but in callback
+        self.assertIn("Loading Data Complete", str(spy_status_update.called()[0]['args'][0]))
+
+        # Expect one Data Received signal
+        self.assertEqual(spy_data_received.count(), 1)
+
+        # Assure returned dictionary has correct data
+        # We don't know the data ID, so need to iterate over dict
+        data_dict = spy_data_received.called()[0]['args'][0]
+        for data_key, data_value in data_dict.iteritems():
+            self.assertIsInstance(data_value, Data1D)
+
+        # Assure add_data on data_manager was called (last call)
+        self.assertTrue(self.form.manager.add_data.called)
+
+    def testNewPlot1D(self):
+        """
+        Creating new plots from Data1D/2D
+        """
+        loader = Loader()
+        manager = DataManager()
+        PlotHelper.clear()
+        self.form.enableGraphCombo(None)
+
+        # Make sure the controls are disabled
+        self.assertFalse(self.form.cbgraph.isEnabled())
+        self.assertFalse(self.form.cmdAppend.isEnabled())
+
+        # get Data1D
+        p_file="cyl_400_20.txt"
+        output_object = loader.load(p_file)
+        new_data = [manager.create_gui_data(output_object, p_file)]
+
+        # Mask retrieval of the data
+        self.form.plotsFromCheckedItems = MagicMock(return_value=new_data)
+
+        # Mask plotting
+        self.form.parent.workspace = MagicMock()
+
+        # Call the plotting method
+        self.form.newPlot()
+
+        # The plot was registered
+        self.assertEqual(len(PlotHelper.currentPlots()), 1)
+
+        self.assertTrue(self.form.cbgraph.isEnabled())
+        self.assertTrue(self.form.cmdAppend.isEnabled())
+
+    def testNewPlot2D(self):
+        """
+        Creating new plots from Data1D/2D
+        """
+        loader = Loader()
+        manager = DataManager()
+        PlotHelper.clear()
+        self.form.enableGraphCombo(None)
+
+        # Make sure the controls are disabled
+        self.assertFalse(self.form.cbgraph.isEnabled())
+        self.assertFalse(self.form.cmdAppend.isEnabled())
+
+        # get Data2D
+        p_file="Dec07031.ASC"
+        output_object = loader.load(p_file)
+        new_data = [manager.create_gui_data(output_object, p_file)]
+
+        # Mask retrieval of the data
+        self.form.plotsFromCheckedItems = MagicMock(return_value=new_data)
+
+        # Mask plotting
+        self.form.parent.workspace = MagicMock()
+
+        # Call the plotting method
+        self.form.newPlot()
+
+        # The plot was registered
+        self.assertEqual(len(PlotHelper.currentPlots()), 1)
+
+        self.assertTrue(self.form.cbgraph.isEnabled())
+        self.assertTrue(self.form.cmdAppend.isEnabled())
+
+    @patch('sas.qtgui.Utilities.GuiUtils.plotsFromCheckedItems')
+    def testAppendPlot(self, test_patch):
+        """
+        Creating new plots from Data1D/2D
+        """
+        loader = Loader()
+        manager = DataManager()
+
+        PlotHelper.clear()
+        self.form.enableGraphCombo(None)
+
+        # Make sure the controls are disabled
+        self.assertFalse(self.form.cbgraph.isEnabled())
+        self.assertFalse(self.form.cmdAppend.isEnabled())
+
+        # get Data1D
+        p_file="cyl_400_20.txt"
+        output_object = loader.load(p_file)
+        output_item = QtGui.QStandardItem()
+        new_data = [(output_item, manager.create_gui_data(output_object, p_file))]
+
+        # Mask plotting
+        self.form.parent.workspace = MagicMock()
+
+        # Mask the plot show call
+        Plotter.show = MagicMock()
+
+        # Mask retrieval of the data
+        test_patch.return_value = new_data
+
+        # Call the plotting method
+        self.form.newPlot()
+
+        # Call the plotting method again, so we have 2 graphs
+        self.form.newPlot()
+
+        # See that we have two plots
+        self.assertEqual(len(PlotHelper.currentPlots()), 2)
+
+        # Add data to plot #1
+        self.form.cbgraph.setCurrentIndex(1)
+        self.form.appendPlot()
+
+        # See that we still have two plots
+        self.assertEqual(len(PlotHelper.currentPlots()), 2)
+
+    def testUpdateGraphCombo(self):
+        """
+        Test the combo box update
+        """
+        PlotHelper.clear()
+
+        graph_list=["1","2","3"]
+        self.form.updateGraphCombo(graph_list)
+
+        self.assertEqual(self.form.cbgraph.count(), 3)
+        self.assertEqual(self.form.cbgraph.currentText(), '1')
+
+        graph_list=[]
+        self.form.updateGraphCombo(graph_list)
+        self.assertEqual(self.form.cbgraph.count(), 0)
+
+    def testUpdateModelFromPerspective(self):
+        """
+        Assure the model update is correct
+        """
+        good_item = QtGui.QStandardItem()
+        bad_item = "I'm so bad"
+
+        self.form.model.reset = MagicMock()
+
+        self.form.updateModelFromPerspective(good_item)
+
+        # See that the model got reset
+        self.form.model.reset.assert_called_once()
+
+        # See that the bad item causes raise
+        with self.assertRaises(Exception):
+            self.form.updateModelFromPerspective(bad_item)
+
+    def testContextMenu(self):
+        """
+        See if the context menu is present
+        """
+        # get Data1D
+        p_file=["cyl_400_20.txt"]
+        # Read in the file
+        output, message = self.form.readData(p_file)
+        self.form.loadComplete((output, message))
+
+        # Pick up the treeview index corresponding to that file
+        index = self.form.treeView.indexAt(QtCore.QPoint(5,5))
+        self.form.show()
+
+        # Find out the center pointof the treeView row
+        rect = self.form.treeView.visualRect(index).center()
+
+        self.form.context_menu.exec_ = MagicMock()
+
+        # Move the mouse pointer to the first row
+        QTest.mouseMove(self.form.treeView.viewport(), pos=rect)
+
+        # This doesn't invoke the action/signal. Investigate why?
+        # QTest.mouseClick(self.form.treeView.viewport(), Qt.RightButton, pos=rect)
+
+        # Instead, send the signal directly
+        self.form.treeView.customContextMenuRequested.emit(rect)
+
+        # app.exec_() # debug
+
+        # See that the menu has been shown
+        self.form.context_menu.exec_.assert_called_once()
+
+    def testShowDataInfo(self):
+        """
+        Test of the showDataInfo method
+        """
+        # get Data1D
+        p_file=["cyl_400_20.txt"]
+        # Read in the file
+        output, message = self.form.readData(p_file)
+        self.form.loadComplete((output, message))
+
+        # select the data
+        self.form.treeView.selectAll()
+
+        # Call the tested method
+        self.form.showDataInfo()
+
+        # Test the properties
+        self.assertTrue(self.form.txt_widget.isReadOnly())
+        self.assertEqual(self.form.txt_widget.windowTitle(), "Data Info: cyl_400_20.txt")
+        self.assertIn("Waveln_max", self.form.txt_widget.toPlainText())
+
+        # Slider moved all the way up
+        self.assertEqual(self.form.txt_widget.verticalScrollBar().sliderPosition(), 0)
+
+    def testSaveDataAs(self):
+        """
+        Test the Save As context menu action
+        """
+        # get Data1D
+        p_file=["cyl_400_20.txt"]
+        # Read in the file
+        output, message = self.form.readData(p_file)
+        self.form.loadComplete((output, message))
+
+        # select the data
+        self.form.treeView.selectAll()
+
+        QFileDialog.getSaveFileName = MagicMock()
+
+        # Call the tested method
+        self.form.saveDataAs()
+        QFileDialog.getSaveFileName.assert_called_with(
+                                caption="Save As",
+                                directory='cyl_400_20_out.txt',
+                                filter='Text files (*.txt);;CanSAS 1D files(*.xml)',
+                                parent=None)
+        QFileDialog.getSaveFileName.assert_called_once()
+
+        # get Data2D
+        p_file=["Dec07031.ASC"]
+        # Read in the file
+        output, message = self.form.readData(p_file)
+        self.form.loadComplete((output, message))
+
+        # select the data
+        index = self.form.model.index(1, 0)
+        selmodel = self.form.treeView.selectionModel()
+        selmodel.setCurrentIndex(index, QItemSelectionModel.NoUpdate)
+        selmodel.select(index, QItemSelectionModel.Select|QItemSelectionModel.Rows)
+
+        QFileDialog.getSaveFileName = MagicMock()
+
+        # Call the tested method
+        self.form.saveDataAs()
+        QFileDialog.getSaveFileName.assert_called_with(
+                                caption="Save As",
+                                directory='Dec07031_out.dat',
+                                filter='IGOR/DAT 2D file in Q_map (*.dat)',
+                                parent=None)
+        QFileDialog.getSaveFileName.assert_called_once()
+
+    def testQuickDataPlot(self):
+        """
+        Quick data plot generation.
+        """
+        # get Data1D
+        p_file=["cyl_400_20.txt"]
+        # Read in the file
+        output, message = self.form.readData(p_file)
+        self.form.loadComplete((output, message))
+
+        # select the data
+        self.form.treeView.selectAll()
+
+        Plotter.show = MagicMock() # for masking the display
+
+        self.form.quickDataPlot()
+        self.assertTrue(Plotter.show.called)
+
+    def testQuickData3DPlot(self):
+        """
+        Slow(er) 3D data plot generation.
+        """
+        # get Data1D
+        p_file=["Dec07031.ASC"]
+        # Read in the file
+        output, message = self.form.readData(p_file)
+        self.form.loadComplete((output, message))
+
+        # select the data
+        self.form.treeView.selectAll()
+
+        Plotter2D.show = MagicMock() # for masking the display
+
+        self.form.quickData3DPlot()
+
+        self.assertTrue(Plotter2D.show.called)
+
+    def testShowEditMask(self):
+        """
+        Edit mask on a 2D plot.
+
+        TODO: add content once plotting finalized
+        """
+        pass
+
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/MainWindow/UnitTesting/DroppableDataLoadWidgetTest.py
===================================================================
--- src/sas/qtgui/MainWindow/UnitTesting/DroppableDataLoadWidgetTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UnitTesting/DroppableDataLoadWidgetTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,75 @@
+import sys
+import unittest
+
+from PyQt4.QtGui import QApplication
+from PyQt4.QtTest import QTest
+from PyQt4 import QtCore
+
+# set up import paths
+import path_prepare
+
+from sas.qtgui.MainWindow.DroppableDataLoadWidget import DroppableDataLoadWidget
+from sas.qtgui.Utilities.GuiUtils import *
+from sas.qtgui.UnitTesting.TestUtils import QtSignalSpy
+
+app = QApplication(sys.argv)
+
+class DroppableDataLoadWidgetTest(unittest.TestCase):
+    '''Test the DroppableDataLoadWidget GUI'''
+    def setUp(self):
+        '''Create the GUI'''
+        class dummy_manager(object):
+            def communicator(self):
+                return Communicate()
+            def perspective(self):
+                return MyPerspective()
+
+        self.form = DroppableDataLoadWidget(None, guimanager=dummy_manager())
+
+        # create dummy mime object
+        self.mime_data = QtCore.QMimeData()
+        self.testfile = 'testfile.txt'
+        self.mime_data.setUrls([QtCore.QUrl(self.testfile)])
+
+    def testDragIsOK(self):
+        """
+        Test the item being dragged over the load widget
+        """
+        good_drag_event = QtGui.QDragMoveEvent(QtCore.QPoint(0,0),
+                                               QtCore.Qt.CopyAction,
+                                               self.mime_data,
+                                               QtCore.Qt.LeftButton,
+                                               QtCore.Qt.NoModifier)
+        mime_data = QtCore.QMimeData()
+        bad_drag_event = QtGui.QDragMoveEvent(QtCore.QPoint(0,0),
+                                               QtCore.Qt.CopyAction,
+                                               mime_data,
+                                               QtCore.Qt.LeftButton,
+                                               QtCore.Qt.NoModifier)
+
+        # Call the drag handler with good event
+        self.assertTrue(self.form.dragIsOK(good_drag_event))
+
+        # Call the drag handler with bad event
+        self.assertFalse(self.form.dragIsOK(bad_drag_event))
+
+    def testDropEvent(self):
+        """
+        Test what happens if an object is dropped onto the load widget
+        """
+        spy_file_read = QtSignalSpy(self.form, self.form.communicator.fileReadSignal)
+
+        drop_event = QtGui.QDropEvent(QtCore.QPoint(0,0),
+                                           QtCore.Qt.CopyAction,
+                                           self.mime_data,
+                                           QtCore.Qt.LeftButton,
+                                           QtCore.Qt.NoModifier)
+
+        self.form.dropEvent(drop_event)
+        QtGui.qApp.processEvents()
+        self.assertEqual(spy_file_read.count(), 1)
+        self.assertIn(self.testfile, str(spy_file_read.signal(index=0)))
+
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/MainWindow/UnitTesting/GuiManagerTest.py
===================================================================
--- src/sas/qtgui/MainWindow/UnitTesting/GuiManagerTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UnitTesting/GuiManagerTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,332 @@
+import sys
+import subprocess
+import unittest
+import webbrowser
+import logging
+
+from PyQt4.QtGui import *
+from PyQt4.QtTest import QTest
+from PyQt4.QtCore import *
+from PyQt4.QtWebKit import *
+from mock import MagicMock
+
+# set up import paths
+import path_prepare
+
+# Local
+from sas.qtgui.MainWindow.DataExplorer import DataExplorerWindow
+from sas.qtgui.MainWindow.AboutBox import AboutBox
+from sas.qtgui.MainWindow.WelcomePanel import WelcomePanel
+from sas.qtgui.Utilities.IPythonWidget import IPythonWidget
+
+from sas.qtgui.MainWindow.GuiManager import Acknowledgements, GuiManager
+from sas.qtgui.MainWindow.MainWindow import MainSasViewWindow
+from sas.qtgui.UnitTesting.TestUtils import QtSignalSpy
+
+app = QApplication(sys.argv)
+
+class GuiManagerTest(unittest.TestCase):
+    '''Test the Main Window functionality'''
+    def setUp(self):
+        '''Create the tested object'''
+        class MainWindow(MainSasViewWindow):
+            # Main window of the application
+            def __init__(self, reactor, parent=None):
+                super(MainWindow, self).__init__(parent)
+        
+                # define workspace for dialogs.
+                self.workspace = QWorkspace(self)
+                self.setCentralWidget(self.workspace)
+
+        self.manager = GuiManager(MainWindow(None))
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.manager = None
+
+    def testDefaults(self):
+        """
+        Test the object in its default state
+        """
+        self.assertIsInstance(self.manager.filesWidget, DataExplorerWindow)
+        self.assertIsInstance(self.manager.dockedFilesWidget, QDockWidget)
+        self.assertIsInstance(self.manager.dockedFilesWidget.widget(), DataExplorerWindow)
+        self.assertEqual(self.manager.dockedFilesWidget.features(), QDockWidget.NoDockWidgetFeatures)
+        self.assertEqual(self.manager._workspace.dockWidgetArea(self.manager.dockedFilesWidget), Qt.LeftDockWidgetArea)
+
+        self.assertIsInstance(self.manager.logDockWidget, QDockWidget)
+        self.assertIsInstance(self.manager.logDockWidget.widget(), QTextBrowser)
+        self.assertEqual(self.manager._workspace.dockWidgetArea(self.manager.logDockWidget), Qt.BottomDockWidgetArea)
+
+        self.assertIsInstance(self.manager.ackWidget, Acknowledgements)
+        self.assertIsInstance(self.manager.aboutWidget, AboutBox)
+        self.assertIsInstance(self.manager.welcomePanel, WelcomePanel)
+
+    def skip_testLogging(self):
+        """
+        Test logging of stdout, stderr and log messages
+        """
+        # See if the log window is empty
+        self.assertEqual(self.manager.logDockWidget.widget().toPlainText(), "")
+
+        # Now, send some message to stdout.
+        # We are in the MainWindow scope, so simple 'print' will work
+        message = "from stdout"
+        print message
+        self.assertIn(message, self.manager.logDockWidget.widget().toPlainText())
+
+        # Send some message to stderr
+        message = "from stderr"
+        sys.stderr.write(message)
+        self.assertIn(message, self.manager.logDockWidget.widget().toPlainText())
+
+        # And finally, send a log message
+        import logging
+        message = "from logging"
+        message_logged = "ERROR: " + message
+        logging.error(message)
+        self.assertIn(message_logged, self.manager.logDockWidget.widget().toPlainText())
+
+    def testConsole(self):
+        """
+        Test the docked QtConsole
+        """
+        # Invoke the console action
+        self.manager.actionPython_Shell_Editor()
+
+        # Test the widegt properties
+        self.assertIsInstance(self.manager.ipDockWidget, QDockWidget)
+        self.assertIsInstance(self.manager.ipDockWidget.widget(), IPythonWidget)
+        self.assertEqual(self.manager._workspace.dockWidgetArea(self.manager.ipDockWidget), Qt.RightDockWidgetArea)
+
+    def testUpdatePerspective(self):
+        """
+        """
+        pass
+
+    def testUpdateStatusBar(self):
+        """
+        """
+        pass
+
+    def testSetData(self):
+        """
+        """
+        pass
+
+    def testQuitApplication(self):
+        """
+        Test that the custom exit method is called on shutdown
+        """
+        self.manager._workspace.show()
+
+        # Must mask sys.exit, otherwise the whole testing process stops.
+        sys.exit = MagicMock()
+
+        # Say No to the close dialog
+        QMessageBox.question = MagicMock(return_value=QMessageBox.No)
+
+        # Open, then close the manager
+        self.manager.quitApplication()
+
+        # See that the MessageBox method got called
+        #self.assertTrue(QMessageBox.question.called)
+
+        # Say Yes to the close dialog
+        QMessageBox.question = MagicMock(return_value=QMessageBox.Yes)
+
+        # Open, then close the manager
+        self.manager.quitApplication()
+
+        # See that the MessageBox method got called
+        #self.assertTrue(QMessageBox.question.called)
+
+    def testCheckUpdate(self):
+        """
+        Tests the SasView website version polling
+        """
+        self.manager.processVersion = MagicMock()
+        version = {'update_url'  : 'http://www.sasview.org/sasview.latestversion', 
+                   'version'     : '4.1.0',
+                   'download_url': 'https://github.com/SasView/sasview/releases'}
+        self.manager.checkUpdate()
+
+        self.manager.processVersion.assert_called_with(version)
+
+        pass
+
+    def testProcessVersion(self):
+        """
+        Tests the version checker logic
+        """
+        # 1. version = 0.0.0
+        version_info = {u'version' : u'0.0.0'}
+        spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal)
+
+        self.manager.processVersion(version_info)
+
+        self.assertEqual(spy_status_update.count(), 1)
+        message = 'Could not connect to the application server. Please try again later.'
+        self.assertIn(message, str(spy_status_update.signal(index=0)))
+
+        # 2. version < LocalConfig.__version__
+        version_info = {u'version' : u'0.0.1'}
+        spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal)
+
+        self.manager.processVersion(version_info)
+
+        self.assertEqual(spy_status_update.count(), 1)
+        message = 'You have the latest version of SasView'
+        self.assertIn(message, str(spy_status_update.signal(index=0)))
+
+        # 3. version > LocalConfig.__version__
+        version_info = {u'version' : u'999.0.0'}
+        spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal)
+        webbrowser.open = MagicMock()
+
+        self.manager.processVersion(version_info)
+
+        self.assertEqual(spy_status_update.count(), 1)
+        message = 'Version 999.0.0 is available!'
+        self.assertIn(message, str(spy_status_update.signal(index=0)))
+
+        webbrowser.open.assert_called_with("https://github.com/SasView/sasview/releases")
+
+        # 4. couldn't load version
+        version_info = {}
+        logging.error = MagicMock()
+        spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal)
+
+        self.manager.processVersion(version_info)
+
+        # Retrieve and compare arguments of the mocked call
+        message = "guiframe: could not get latest application version number"
+        args, _ = logging.error.call_args
+        self.assertIn(message, args[0])
+
+        # Check the signal message
+        message = 'Could not connect to the application server.'
+        self.assertIn(message, str(spy_status_update.signal(index=0)))
+
+    def testActions(self):
+        """
+        """
+        pass
+
+    #### FILE ####
+    def testActionLoadData(self):
+        """
+        Menu File/Load Data File(s)
+        """
+        # Mock the system file open method
+        QFileDialog.getOpenFileNames = MagicMock(return_value=None)
+
+        # invoke the action
+        self.manager.actionLoadData()
+
+        # Test the getOpenFileName() dialog called once
+        self.assertTrue(QFileDialog.getOpenFileNames.called)
+
+    def testActionLoadDataFolder(self):
+        """
+        Menu File/Load Data Folder
+        """
+        # Mock the system file open method
+        QFileDialog.getExistingDirectory = MagicMock(return_value=None)
+
+        # invoke the action
+        self.manager.actionLoad_Data_Folder()
+
+        # Test the getOpenFileName() dialog called once
+        self.assertTrue(QFileDialog.getExistingDirectory.called)
+
+    #### VIEW ####
+    def testActionHideToolbar(self):
+        """
+        Menu View/Hide Toolbar
+        """
+        # Need to display the main window to initialize the toolbar.
+        self.manager._workspace.show()
+
+        # Check the initial state
+        self.assertTrue(self.manager._workspace.toolBar.isVisible())
+        self.assertEqual('Hide Toolbar', self.manager._workspace.actionHide_Toolbar.text())
+
+        # Invoke action
+        self.manager.actionHide_Toolbar()
+
+        # Assure changes propagated correctly
+        self.assertFalse(self.manager._workspace.toolBar.isVisible())
+        self.assertEqual('Show Toolbar', self.manager._workspace.actionHide_Toolbar.text())
+
+        # Revert
+        self.manager.actionHide_Toolbar()
+
+        # Assure the original values are back
+        self.assertTrue(self.manager._workspace.toolBar.isVisible())
+        self.assertEqual('Hide Toolbar', self.manager._workspace.actionHide_Toolbar.text())
+
+
+    #### HELP ####
+    def testActionDocumentation(self):
+        """
+        Menu Help/Documentation
+        """
+        #Mock the QWebView method
+        QWebView.show = MagicMock()
+
+        # Assure the filename is correct
+        self.assertIn("index.html", self.manager._helpLocation)
+
+        # Invoke the action
+        self.manager.actionDocumentation()
+
+        # Check if show() got called
+        self.assertTrue(QWebView.show.called)
+
+    def skip_testActionTutorial(self):
+        """
+        Menu Help/Tutorial
+        """
+        # Mock subprocess.Popen
+        subprocess.Popen = MagicMock()
+
+        tested_location = self.manager._tutorialLocation
+
+        # Assure the filename is correct
+        self.assertIn("Tutorial.pdf", tested_location)
+
+        # Invoke the action
+        self.manager.actionTutorial()
+
+        # Check if popen() got called
+        self.assertTrue(subprocess.Popen.called)
+
+        #Check the popen() call arguments
+        subprocess.Popen.assert_called_with([tested_location], shell=True)
+
+    def testActionAcknowledge(self):
+        """
+        Menu Help/Acknowledge
+        """
+        self.manager.actionAcknowledge()
+
+        # Check if the window is actually opened.
+        self.assertTrue(self.manager.ackWidget.isVisible())
+        self.assertIn("developers@sasview.org", self.manager.ackWidget.label.text())
+
+    def testActionCheck_for_update(self):
+        """
+        Menu Help/Check for update
+        """
+        # Just make sure checkUpdate is called.
+        self.manager.checkUpdate = MagicMock()
+
+        self.manager.actionCheck_for_update()
+
+        self.assertTrue(self.manager.checkUpdate.called)
+             
+       
+if __name__ == "__main__":
+    unittest.main()
+
Index: src/sas/qtgui/MainWindow/UnitTesting/MainWindowTest.py
===================================================================
--- src/sas/qtgui/MainWindow/UnitTesting/MainWindowTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UnitTesting/MainWindowTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,55 @@
+import sys
+import unittest
+
+from PyQt4 import QtGui
+from PyQt4 import QtTest
+from PyQt4 import QtCore
+from mock import MagicMock
+
+# set up import paths
+import path_prepare
+
+# Local
+from sas.qtgui.MainWindow.MainWindow import MainSasViewWindow
+from sas.qtgui.MainWindow.MainWindow import SplashScreen
+
+app = QtGui.QApplication(sys.argv)
+
+class MainWindowTest(unittest.TestCase):
+    """Test the Main Window GUI"""
+    def setUp(self):
+        """Create the GUI"""
+
+        self.widget = MainSasViewWindow(None)
+
+    def tearDown(self):
+        """Destroy the GUI"""
+        self.widget = None
+
+    def testDefaults(self):
+        """Test the GUI in its default state"""
+        self.assertIsInstance(self.widget, QtGui.QMainWindow)
+        self.assertIsInstance(self.widget.centralWidget(), QtGui.QWorkspace)
+        
+    def testSplashScreen(self):
+        """ Test the splash screen """
+        splash = SplashScreen()
+        self.assertIsInstance(splash, QtGui.QSplashScreen)
+
+    def testExit(self):
+        """
+        Test that the custom exit method is called on shutdown
+        """
+        # Must mask sys.exit, otherwise the whole testing process stops.
+        sys.exit = MagicMock()
+        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.Yes)
+
+        # Open, then close the main window
+        tmp_main = MainSasViewWindow(None)
+        tmp_main.close()
+
+        # See that the MessageBox method got called
+        self.assertTrue(QtGui.QMessageBox.question.called)
+       
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/MainWindow/UnitTesting/WelcomePanelTest.py
===================================================================
--- src/sas/qtgui/MainWindow/UnitTesting/WelcomePanelTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/UnitTesting/WelcomePanelTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,41 @@
+import sys
+import unittest
+
+from PyQt4 import QtGui
+
+# set up import paths
+import path_prepare
+
+# Local
+from sas.qtgui.MainWindow.WelcomePanel import WelcomePanel
+
+app = QtGui.QApplication(sys.argv)
+
+class WelcomePanelTest(unittest.TestCase):
+    '''Test the WelcomePanel'''
+    def setUp(self):
+        '''Create the WelcomePanel'''
+
+        self.widget = WelcomePanel(None)
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtGui.QDialog)
+        self.assertEqual(self.widget.windowTitle(), "Welcome")
+        
+    def testVersion(self):
+        '''Test the version string'''
+        version = self.widget.lblVersion
+        self.assertIsInstance(version, QtGui.QLabel)
+
+        self.assertIn("SasView", version.text())
+        self.assertIn("Build:", version.text())
+        self.assertIn("UTK, UMD, NIST, ORNL, ISIS, ESS, ILL and ANSTO", version.text())
+       
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/MainWindow/WelcomePanel.py
===================================================================
--- src/sas/qtgui/MainWindow/WelcomePanel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/WelcomePanel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,28 @@
+# global
+import sys
+import os
+from PyQt4 import QtCore
+from PyQt4 import QtGui
+from PyQt4 import QtWebKit
+
+import sas.sasview
+import sas.qtgui.Utilities.LocalConfig as LocalConfig
+
+from sas.qtgui.MainWindow.UI.WelcomePanelUI import Ui_WelcomePanelUI
+
+class WelcomePanel(QtGui.QDialog, Ui_WelcomePanelUI):
+    def __init__(self, parent=None):
+        super(WelcomePanel, self).__init__(parent)
+        self.setupUi(self)
+
+        self.setWindowTitle("Welcome")
+
+        version = sas.sasview.__version__
+        build = sas.sasview.__build__
+
+        ver = "\nSasView %s\nBuild: %s\n%s" % (version, build, LocalConfig._copyright)
+
+        self.lblVersion.setText(ver)
+
+        # no reason to have this widget resizable
+        self.setFixedSize(self.minimumSizeHint())
Index: c/sas/qtgui/MaskEditor.py
===================================================================
--- src/sas/qtgui/MaskEditor.py	(revision 416fa8fe6ed121e335fb8f0e75cdd9a8ab89b80d)
+++ 	(revision )
@@ -1,30 +1,0 @@
-from PyQt4 import QtGui
-
-from sas.sasgui.guiframe.dataFitting import Data2D
-
-# Local UI
-from sas.qtgui.UI.MaskEditorUI import Ui_MaskEditorUI
-from sas.qtgui.Plotter2D import Plotter2DWidget
-
-class MaskEditor(QtGui.QDialog, Ui_MaskEditorUI):
-    def __init__(self, parent=None, data=None):
-        super(MaskEditor, self).__init__()
-
-        assert(isinstance(data, Data2D))
-
-        self.setupUi(self)
-
-        self.data = data
-        filename = data.name
-        self.setWindowTitle("Mask Editor for %s" % filename)
-
-        self.plotter = Plotter2DWidget(self, manager=parent, quickplot=True)
-        self.plotter.data = self.data
-
-        layout = QtGui.QHBoxLayout()
-        layout.setContentsMargins(0, 0, 0, 0)
-        self.frame.setLayout(layout)
-        layout.addWidget(self.plotter)
-
-        self.plotter.plot()
-
Index: src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py	(revision 6c8fb2ce67ed94f8fd44ef74eff5f71b3cd6b6f6)
+++ src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -5,5 +5,5 @@
 from PyQt4 import QtGui
 
-import sas.qtgui.GuiUtils as GuiUtils
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
 
 from FittingWidget import FittingWidget
Index: src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision 6c8fb2ce67ed94f8fd44ef74eff5f71b3cd6b6f6)
+++ src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -22,5 +22,5 @@
 from sas.sasgui.guiframe.dataFitting import Data1D
 from sas.sasgui.guiframe.dataFitting import Data2D
-import sas.qtgui.GuiUtils as GuiUtils
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
 from sas.sasgui.perspectives.fitting.model_thread import Calc1D
 from sas.sasgui.perspectives.fitting.model_thread import Calc2D
Index: src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingLogicTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingLogicTest.py	(revision 2155824bc3dcd6c0afe1204caa0357472cf9b060)
+++ src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingLogicTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -9,5 +9,5 @@
 
 # Local
-from sas.qtgui.GuiUtils import *
+from sas.qtgui.Utilities.GuiUtils import *
 from sas.qtgui.Perspectives.Fitting.FittingWidget import *
 from sas.sasgui.guiframe.dataFitting import Data1D
Index: src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingPerspectiveTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingPerspectiveTest.py	(revision 2155824bc3dcd6c0afe1204caa0357472cf9b060)
+++ src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingPerspectiveTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -12,5 +12,5 @@
 
 # Local
-import sas.qtgui.GuiUtils as GuiUtils
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
 from sas.sasgui.guiframe.dataFitting import Data1D
 
Index: src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py	(revision 2155824bc3dcd6c0afe1204caa0357472cf9b060)
+++ src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -12,5 +12,5 @@
 
 # Local
-from sas.qtgui.GuiUtils import *
+from sas.qtgui.Utilities.GuiUtils import *
 from sas.qtgui.Perspectives.Fitting.FittingWidget import *
 from sas.qtgui.UnitTesting.TestUtils import QtSignalSpy
Index: src/sas/qtgui/Perspectives/Invariant/InvariantDetails.py
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/InvariantDetails.py	(revision 60af9286f3186d421a48ebaf7a9de349ecdf4a3d)
+++ src/sas/qtgui/Perspectives/Invariant/InvariantDetails.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
Index: src/sas/qtgui/Perspectives/Invariant/InvariantPerspective.py
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/InvariantPerspective.py	(revision 6fd4e36d87aa2c634f1fe31123e473984cad066c)
+++ src/sas/qtgui/Perspectives/Invariant/InvariantPerspective.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -12,6 +12,5 @@
 from sas.sascalc.invariant import invariant
 from sas.sasgui.guiframe.dataFitting import Data1D
-#import GuiUtils
-import sas.qtgui.GuiUtils as GuiUtils
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
 
 # local
Index: src/sas/qtgui/Perspectives/Invariant/UI/InvariantDetailsUI.py
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/UI/InvariantDetailsUI.py	(revision 60af9286f3186d421a48ebaf7a9de349ecdf4a3d)
+++ src/sas/qtgui/Perspectives/Invariant/UI/InvariantDetailsUI.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
 
-# Form implementation generated from reading ui file 'InvariantDetailsUI.ui'
+# Form implementation generated from reading ui file '.\Perspectives\Invariant\UI\InvariantDetailsUI.ui'
 #
 # Created by: PyQt4 UI code generator 4.11.4
Index: src/sas/qtgui/Perspectives/Invariant/UI/TabbedInvariantUI.py
===================================================================
--- src/sas/qtgui/Perspectives/Invariant/UI/TabbedInvariantUI.py	(revision 469b4622e645f3163e4b64cfbeb2a49e591cc359)
+++ src/sas/qtgui/Perspectives/Invariant/UI/TabbedInvariantUI.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
 
-# Form implementation generated from reading ui file 'TabbedInvariantUI.ui'
+# Form implementation generated from reading ui file '.\Perspectives\Invariant\UI\TabbedInvariantUI.ui'
 #
 # Created by: PyQt4 UI code generator 4.11.4
Index: c/sas/qtgui/PlotHelper.py
===================================================================
--- src/sas/qtgui/PlotHelper.py	(revision 0268aed2269053d708f7e97fbea13db43e371ab4)
+++ 	(revision )
@@ -1,55 +1,0 @@
-"""
-`Singleton` plot helper module
-All its variables are bound to the module,
-which can not be instantiated repeatedly so IDs are session-specific.
-"""
-import sys
-
-this = sys.modules[__name__]
-
-this._plots = {}
-this._plot_id = 0
-
-def clear():
-    """
-    Reset the plot dictionary
-    """
-    this._plots = {}
-
-def addPlot(plot):
-    """
-    Adds a new plot to the current dictionary of plots
-    """
-    this._plot_id += 1
-    this._plots["Graph%s"%str(this._plot_id)] = plot
-
-def deletePlot(plot_id):
-    """
-    Deletes an existing plot from the dictionary
-    """
-    if plot_id in this._plots:
-        del this._plots[plot_id]
-
-def currentPlots():
-    """
-    Returns a list of IDs for all currently active plots
-    """
-    return this._plots.keys()
-
-def plotById(plot_id):
-    """
-    Returns the plot referenced by the ID
-    """
-    return this._plots[plot_id] if plot_id in this._plots else None
-
-def idOfPlot(plot):
-    """
-    Returns the ID of the plot
-    """
-    plot_id = None
-    for key in this._plots.keys():
-        if this._plots[key] == plot:
-            plot_id = key
-            break
-
-    return plot_id
Index: c/sas/qtgui/PlotProperties.py
===================================================================
--- src/sas/qtgui/PlotProperties.py	(revision 6fd4e36d87aa2c634f1fe31123e473984cad066c)
+++ 	(revision )
@@ -1,100 +1,0 @@
-from PyQt4 import QtGui
-
-from sas.qtgui.PlotUtilities import COLORS, SHAPES
-
-from sas.qtgui.UI.PlotPropertiesUI import Ui_PlotPropertiesUI
-
-class PlotProperties(QtGui.QDialog, Ui_PlotPropertiesUI):
-    """ Dialog for modification of single plot properties """
-    def __init__(self,
-                 parent=None,
-                 color=0,
-                 marker=0,
-                 marker_size=5,
-                 legend=""):
-        super(PlotProperties, self).__init__(parent)
-        self.setupUi(self)
-        self.setFixedSize(self.minimumSizeHint())
-
-        self._parent = parent
-        self._marker = marker if marker else 0
-        self._color = color if color else 0
-        self._legend = legend
-        self._markersize = marker_size if marker_size else 5
-        self.custom_color = False if isinstance(self._color, int) else True
-
-        # Fill out the color combobox
-        self.cbColor.addItems(COLORS.keys()[:-1])
-        # data1d.custom_color can now be a simple integer,
-        # specifying COLORS dict index or a string containing
-        # the hex RGB value, e.g. #00FF00
-        if isinstance(self._color, int):
-            self.cbColor.setCurrentIndex(self._color)
-        else:
-            # Need the Custom entry here. "Custom" is always last.
-            self.cbColor.addItems([COLORS.keys()[-1]])
-            self.cbColor.setCurrentIndex(COLORS.keys().index("Custom"))
-
-        # Fill out the marker combobox
-        self.cbShape.addItems(SHAPES.keys())
-        try:
-            self.cbShape.setCurrentIndex(self._marker)
-        except TypeError:
-            marker_index = self.cbShape.findText(self._marker)
-            self.cbShape.setCurrentIndex(marker_index)
-        if self._legend:
-            self.txtLegend.setText(self._legend)
-        self.sbSize.setValue(self._markersize)
-
-        # Connect slots
-        self.cmdCustom.clicked.connect(self.onColorChange)
-        self.cbColor.currentIndexChanged.connect(self.onColorIndexChange)
-
-    def legend(self):
-        ''' return current legend '''
-        return str(self.txtLegend.text())
-
-    def marker(self):
-        ''' return the current shape index in SHAPE '''
-        return self.cbShape.currentIndex()
-
-    def markersize(self):
-        ''' return marker size (int) '''
-        return self.sbSize.value()
-
-    def color(self):
-        ''' return current color: index in COLORS or a hex string '''
-        if self.custom_color:
-            return self._color
-        else:
-            return self.cbColor.currentIndex()
-
-    def onColorChange(self):
-        """
-        Pop up the standard Qt color change dialog
-        """
-        # Pick up the chosen color
-        proposed_color = QtGui.QColorDialog.getColor(parent=self)
-        # Update the text control
-        if proposed_color.isValid():
-            # Block currentIndexChanged
-            self.cbColor.blockSignals(True)
-            # Add Custom to the color combo box
-            self.cbColor.addItems(["Custom"])
-            self.cbColor.setCurrentIndex(COLORS.keys().index("Custom"))
-            # unblock currentIndexChanged
-            self.cbColor.blockSignals(False)
-            # Save the color as #RRGGBB
-            self.custom_color = True
-            self._color = str(proposed_color.name())
-   
-    def onColorIndexChange(self):
-        """
-        Dynamically add/remove "Custom" color index
-        """
-        # Changed index - assure Custom is deleted
-        custom_index = self.cbColor.findText("Custom")
-        self.custom_color = False
-        if custom_index > -1:
-            self.cbColor.removeItem(custom_index)
-        
Index: c/sas/qtgui/PlotUtilities.py
===================================================================
--- src/sas/qtgui/PlotUtilities.py	(revision 6fd4e36d87aa2c634f1fe31123e473984cad066c)
+++ 	(revision )
@@ -1,284 +1,0 @@
-import sys
-import numpy
-import string
-
-from collections import OrderedDict
-
-# MPL shapes dictionary with some extra styles rendered internally.
-# Ordered for consistent display in combo boxes
-SHAPES = OrderedDict([
-        ('Circle' , 'o'),
-        ('Point' , '.'),
-        ('Pixel' , ','),
-        ('Triangle Down' , 'v'),
-        ('Triangle Up' , '^'),
-        ('Triangle Left' , '<'),
-        ('Triangle Right' , '>'),
-        ('Octagon' , '8'),
-        ('Square' , 's'),
-        ('Pentagon' , 'p'),
-        ('Star' , '*'),
-        ('Hexagon1' , 'h'),
-        ('Hexagon2' , 'H'),
-        ('Cross +' , 'p'),
-        ('Cross X ' , 'x'),
-        ('Diamond' , 'D'),
-        ('Thin Diamond' , 'd'),
-        ('Line' , '-'),
-        ('Dash' , '--'),
-        ('Vline' , 'vline'),
-        ('Step' , 'step'),
-])
-
-# MPL Colors dictionary. Ordered for consistent display
-COLORS = OrderedDict([
-        ('Blue', 'b'),
-        ('Green', 'g'),
-        ('Red', 'r'),
-        ('Cyan', 'c'),
-        ('Magenta', 'm'),
-        ('Yellow', 'y'),
-        ('Black', 'k'),
-        ('Custom', 'x'),
-])
-
-def build_matrix(data, qx_data, qy_data):
-    """
-    Build a matrix for 2d plot from a vector
-    Returns a matrix (image) with ~ square binning
-    Requirement: need 1d array formats of
-    data, qx_data, and qy_data
-    where each one corresponds to z, x, or y axis values
-
-    """
-    # No qx or qy given in a vector format
-    if qx_data is None or qy_data is None \
-            or qx_data.ndim != 1 or qy_data.ndim != 1:
-        return data
-
-    # maximum # of loops to fillup_pixels
-    # otherwise, loop could never stop depending on data
-    max_loop = 1
-    # get the x and y_bin arrays.
-    x_bins, y_bins = get_bins(qx_data, qy_data)
-    # set zero to None
-
-    #Note: Can not use scipy.interpolate.Rbf:
-    # 'cause too many data points (>10000)<=JHC.
-    # 1d array to use for weighting the data point averaging
-    #when they fall into a same bin.
-    weights_data = numpy.ones([data.size])
-    # get histogram of ones w/len(data); this will provide
-    #the weights of data on each bins
-    weights, xedges, yedges = numpy.histogram2d(x=qy_data,
-                                                y=qx_data,
-                                                bins=[y_bins, x_bins],
-                                                weights=weights_data)
-    # get histogram of data, all points into a bin in a way of summing
-    image, xedges, yedges = numpy.histogram2d(x=qy_data,
-                                              y=qx_data,
-                                              bins=[y_bins, x_bins],
-                                              weights=data)
-    # Now, normalize the image by weights only for weights>1:
-    # If weight == 1, there is only one data point in the bin so
-    # that no normalization is required.
-    image[weights > 1] = image[weights > 1] / weights[weights > 1]
-    # Set image bins w/o a data point (weight==0) as None (was set to zero
-    # by histogram2d.)
-    image[weights == 0] = None
-
-    # Fill empty bins with 8 nearest neighbors only when at least
-    #one None point exists
-    loop = 0
-
-    # do while loop until all vacant bins are filled up up
-    #to loop = max_loop
-    while not(numpy.isfinite(image[weights == 0])).all():
-        if loop >= max_loop:  # this protects never-ending loop
-            break
-        image = fillupPixels(image=image, weights=weights)
-        loop += 1
-
-    return image
-
-def get_bins(qx_data, qy_data):
-    """
-    get bins
-    return x_bins and y_bins: 1d arrays of the index with
-    ~ square binning
-    Requirement: need 1d array formats of
-    qx_data, and qy_data
-    where each one corresponds to  x, or y axis values
-    """
-    # No qx or qy given in a vector format
-    if qx_data is None or qy_data is None \
-            or qx_data.ndim != 1 or qy_data.ndim != 1:
-        return data
-
-    # find max and min values of qx and qy
-    xmax = qx_data.max()
-    xmin = qx_data.min()
-    ymax = qy_data.max()
-    ymin = qy_data.min()
-
-    # calculate the range of qx and qy: this way, it is a little
-    # more independent
-    x_size = xmax - xmin
-    y_size = ymax - ymin
-
-    # estimate the # of pixels on each axes
-    npix_y = int(numpy.floor(numpy.sqrt(len(qy_data))))
-    npix_x = int(numpy.floor(len(qy_data) / npix_y))
-
-    # bin size: x- & y-directions
-    xstep = x_size / (npix_x - 1)
-    ystep = y_size / (npix_y - 1)
-
-    # max and min taking account of the bin sizes
-    xmax = xmax + xstep / 2.0
-    xmin = xmin - xstep / 2.0
-    ymax = ymax + ystep / 2.0
-    ymin = ymin - ystep / 2.0
-
-    # store x and y bin centers in q space
-    x_bins = numpy.linspace(xmin, xmax, npix_x)
-    y_bins = numpy.linspace(ymin, ymax, npix_y)
-
-    #set x_bins and y_bins
-    return x_bins, y_bins
-
-def fillupPixels(image=None, weights=None):
-    """
-    Fill z values of the empty cells of 2d image matrix
-    with the average over up-to next nearest neighbor points
-
-    :param image: (2d matrix with some zi = None)
-
-    :return: image (2d array )
-
-    :TODO: Find better way to do for-loop below
-
-    """
-    # No image matrix given
-    if image == None or numpy.ndim(image) != 2 \
-            or numpy.isfinite(image).all() \
-            or weights == None:
-        return image
-    # Get bin size in y and x directions
-    len_y = len(image)
-    len_x = len(image[1])
-    temp_image = numpy.zeros([len_y, len_x])
-    weit = numpy.zeros([len_y, len_x])
-    # do for-loop for all pixels
-    for n_y in range(len(image)):
-        for n_x in range(len(image[1])):
-            # find only null pixels
-            if weights[n_y][n_x] > 0 or numpy.isfinite(image[n_y][n_x]):
-                continue
-            else:
-                # find 4 nearest neighbors
-                # check where or not it is at the corner
-                if n_y != 0 and numpy.isfinite(image[n_y - 1][n_x]):
-                    temp_image[n_y][n_x] += image[n_y - 1][n_x]
-                    weit[n_y][n_x] += 1
-                if n_x != 0 and numpy.isfinite(image[n_y][n_x - 1]):
-                    temp_image[n_y][n_x] += image[n_y][n_x - 1]
-                    weit[n_y][n_x] += 1
-                if n_y != len_y - 1 and numpy.isfinite(image[n_y + 1][n_x]):
-                    temp_image[n_y][n_x] += image[n_y + 1][n_x]
-                    weit[n_y][n_x] += 1
-                if n_x != len_x - 1 and numpy.isfinite(image[n_y][n_x + 1]):
-                    temp_image[n_y][n_x] += image[n_y][n_x + 1]
-                    weit[n_y][n_x] += 1
-                # go 4 next nearest neighbors when no non-zero
-                # neighbor exists
-                if n_y != 0 and n_x != 0 and\
-                        numpy.isfinite(image[n_y - 1][n_x - 1]):
-                    temp_image[n_y][n_x] += image[n_y - 1][n_x - 1]
-                    weit[n_y][n_x] += 1
-                if n_y != len_y - 1 and n_x != 0 and \
-                    numpy.isfinite(image[n_y + 1][n_x - 1]):
-                    temp_image[n_y][n_x] += image[n_y + 1][n_x - 1]
-                    weit[n_y][n_x] += 1
-                if n_y != len_y and n_x != len_x - 1 and \
-                    numpy.isfinite(image[n_y - 1][n_x + 1]):
-                    temp_image[n_y][n_x] += image[n_y - 1][n_x + 1]
-                    weit[n_y][n_x] += 1
-                if n_y != len_y - 1 and n_x != len_x - 1 and \
-                    numpy.isfinite(image[n_y + 1][n_x + 1]):
-                    temp_image[n_y][n_x] += image[n_y + 1][n_x + 1]
-                    weit[n_y][n_x] += 1
-
-    # get it normalized
-    ind = (weit > 0)
-    image[ind] = temp_image[ind] / weit[ind]
-
-    return image
-
-def rescale(lo, hi, step, pt=None, bal=None, scale='linear'):
-    """
-    Rescale (lo,hi) by step, returning the new (lo,hi)
-    The scaling is centered on pt, with positive values of step
-    driving lo/hi away from pt and negative values pulling them in.
-    If bal is given instead of point, it is already in [0,1] coordinates.
-
-    This is a helper function for step-based zooming.
-    """
-    # Convert values into the correct scale for a linear transformation
-    # TODO: use proper scale transformers
-    loprev = lo
-    hiprev = hi
-    if scale == 'log':
-        assert lo > 0
-        if lo > 0:
-            lo = numpy.log10(lo)
-        if hi > 0:
-            hi = numpy.log10(hi)
-        if pt is not None:
-            pt = numpy.log10(pt)
-
-    # Compute delta from axis range * %, or 1-% if persent is negative
-    if step > 0:
-        delta = float(hi - lo) * step / 100
-    else:
-        delta = float(hi - lo) * step / (100 - step)
-
-    # Add scale factor proportionally to the lo and hi values,
-    # preserving the
-    # point under the mouse
-    if bal is None:
-        bal = float(pt - lo) / (hi - lo)
-    lo = lo - (bal * delta)
-    hi = hi + (1 - bal) * delta
-
-    # Convert transformed values back to the original scale
-    if scale == 'log':
-        if (lo <= -250) or (hi >= 250):
-            lo = loprev
-            hi = hiprev
-        else:
-            lo, hi = numpy.power(10., lo), numpy.power(10., hi)
-    return (lo, hi)
-
-def getValidColor(color):
-    '''
-    Returns a valid matplotlib color
-    '''
-
-    if color is None:
-        return color
-
-    # Check if it's an int
-    if isinstance(color, int):
-        # Check if it's within the range
-        if 0 <= color <=6:
-            color = COLORS.values()[color]
-    # Check if it's an RGB string
-    elif isinstance(color, str):
-        # Assure the correctnes of the string
-        assert(color[0]=="#" and len(color) == 7)
-        assert(all(c in string.hexdigits for c in color[1:]))
-    else:
-        raise AttributeError
-
-    return color
Index: c/sas/qtgui/Plotter.py
===================================================================
--- src/sas/qtgui/Plotter.py	(revision f182f93463e4e6fc08ca96b3539a3dfe42621d26)
+++ 	(revision )
@@ -1,708 +1,0 @@
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-import functools
-import copy
-
-import matplotlib.pyplot as plt
-from matplotlib.font_manager import FontProperties
-
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.qtgui.PlotterBase import PlotterBase
-import sas.qtgui.GuiUtils as GuiUtils
-from sas.qtgui.AddText import AddText
-from sas.qtgui.SetGraphRange import SetGraphRange
-from sas.qtgui.LinearFit import LinearFit
-from sas.qtgui.PlotProperties import PlotProperties
-import sas.qtgui.PlotUtilities as PlotUtilities
-
-class PlotterWidget(PlotterBase):
-    """
-    1D Plot widget for use with a QDialog
-    """
-    def __init__(self, parent=None, manager=None, quickplot=False):
-        super(PlotterWidget, self).__init__(parent, manager=manager, quickplot=quickplot)
-
-        self.parent = parent
-
-        # Dictionary of {plot_id:Data1d}
-        self.plot_dict = {}
-
-        # Window for text add
-        self.addText = AddText(self)
-
-        # Log-ness of the axes
-        self.xLogLabel = "log10(x)"
-        self.yLogLabel = "log10(y)"
-
-        # Data container for the linear fit
-        self.fit_result = Data1D(x=[], y=[], dy=None)
-        self.fit_result.symbol = 13
-        self.fit_result.name = "Fit"
-
-        # Add a slot for receiving update signal from LinearFit
-        # NEW style signals
-        #self.updatePlot = QtCore.pyqtSignal(tuple)
-        # self.updatePlot.connect(self.onFitDisplay)
-        # OLD style signals
-        QtCore.QObject.connect(self, QtCore.SIGNAL('updatePlot'), self.onFitDisplay)
-
-    @property
-    def data(self):
-        return self._data
-
-    @data.setter
-    def data(self, value):
-        """ data setter """
-        self._data = value
-        self.xLabel = "%s(%s)"%(value._xaxis, value._xunit)
-        self.yLabel = "%s(%s)"%(value._yaxis, value._yunit)
-        self.title(title=value.name)
-
-    def plot(self, data=None, color=None, marker=None, hide_error=False):
-        """
-        Add a new plot of self._data to the chart.
-        """
-        # Data1D
-        if isinstance(data, Data1D):
-            self.data = data
-        assert(self._data)
-
-        is_fit = (self.data.id=="fit")
-
-        # Transform data if required.
-        # TODO: it properly!
-        #if data.xtransform is not None or data.ytransform is not None:
-        #    a, b, c, d = GuiUtils.xyTransform(self.data, self.data.xtransform, self.data.ytransform)
-
-        # Shortcuts
-        ax = self.ax
-        x = self._data.view.x
-        y = self._data.view.y
-
-        # Marker symbol. Passed marker is one of matplotlib.markers characters
-        # Alternatively, picked up from Data1D as an int index of PlotUtilities.SHAPES dict
-        if marker is None:
-            marker = self.data.symbol
-            # Try name first
-            try:
-                marker = PlotUtilities.SHAPES[marker]
-            except KeyError:
-                marker = PlotUtilities.SHAPES.values()[marker]
-
-        assert marker is not None
-        # Plot name
-        if self.data.title:
-            self.title(title=self.data.title)
-        else:
-            self.title(title=self.data.name)
-
-        # Error marker toggle
-        if hide_error is None:
-            hide_error = self.data.hide_error
-
-        # Plot color
-        if color is None:
-            color = self.data.custom_color
-
-        color = PlotUtilities.getValidColor(color)
-
-        markersize = self._data.markersize
-
-        # Draw non-standard markers
-        l_width = markersize * 0.4
-        if marker == '-' or marker == '--':
-            line = self.ax.plot(x, y, color=color, lw=l_width, marker='',
-                             linestyle=marker, label=self._title, zorder=10)[0]
-
-        elif marker == 'vline':
-            y_min = min(y)*9.0/10.0 if min(y) < 0 else 0.0
-            line = self.ax.vlines(x=x, ymin=y_min, ymax=y, color=color,
-                            linestyle='-', label=self._title, lw=l_width, zorder=1)
-
-        elif marker == 'step':
-            line = self.ax.step(x, y, color=color, marker='', linestyle='-',
-                                label=self._title, lw=l_width, zorder=1)[0]
-
-        else:
-            # plot data with/without errorbars
-            if hide_error:
-                line = ax.plot(x, y, marker=marker, color=color, markersize=markersize,
-                        linestyle='', label=self._title, picker=True)
-            else:
-                line = ax.errorbar(x, y,
-                            yerr=self._data.view.dy, xerr=None,
-                            capsize=2, linestyle='',
-                            barsabove=False,
-                            color=color,
-                            marker=marker,
-                            markersize=markersize,
-                            lolims=False, uplims=False,
-                            xlolims=False, xuplims=False,
-                            label=self._title,
-                            picker=True)
-
-        # Update the list of data sets (plots) in chart
-        self.plot_dict[self._data.id] = self.data
-
-        # Now add the legend with some customizations.
-        self.legend = ax.legend(loc='upper right', shadow=True)
-        if self.legend:
-            self.legend.set_picker(True)
-
-        # Current labels for axes
-        if self.y_label and not is_fit:
-            ax.set_ylabel(self.y_label)
-        if self.x_label and not is_fit:
-            ax.set_xlabel(self.x_label)
-
-        # Include scaling (log vs. linear)
-        ax.set_xscale(self.xscale)
-        ax.set_yscale(self.yscale)
-
-        # define the ranges
-        self.setRange = SetGraphRange(parent=self,
-            x_range=self.ax.get_xlim(), y_range=self.ax.get_ylim())
-
-        # refresh canvas
-        self.canvas.draw()
-
-    def createContextMenu(self):
-        """
-        Define common context menu and associated actions for the MPL widget
-        """
-        self.defaultContextMenu()
-
-        # Separate plots
-        self.addPlotsToContextMenu()
-
-        # Additional menu items
-        self.contextMenu.addSeparator()
-        self.actionAddText = self.contextMenu.addAction("Add Text")
-        self.actionRemoveText = self.contextMenu.addAction("Remove Text")
-        self.contextMenu.addSeparator()
-        self.actionChangeScale = self.contextMenu.addAction("Change Scale")
-        self.contextMenu.addSeparator()
-        self.actionSetGraphRange = self.contextMenu.addAction("Set Graph Range")
-        self.actionResetGraphRange =\
-            self.contextMenu.addAction("Reset Graph Range")
-        # Add the title change for dialogs
-        #if self.parent:
-        self.contextMenu.addSeparator()
-        self.actionWindowTitle = self.contextMenu.addAction("Window Title")
-
-        # Define the callbacks
-        self.actionAddText.triggered.connect(self.onAddText)
-        self.actionRemoveText.triggered.connect(self.onRemoveText)
-        self.actionChangeScale.triggered.connect(self.onScaleChange)
-        self.actionSetGraphRange.triggered.connect(self.onSetGraphRange)
-        self.actionResetGraphRange.triggered.connect(self.onResetGraphRange)
-        self.actionWindowTitle.triggered.connect(self.onWindowsTitle)
-
-    def addPlotsToContextMenu(self):
-        """
-        Adds operations on all plotted sets of data to the context menu
-        """
-        for id in self.plot_dict.keys():
-            plot = self.plot_dict[id]
-
-            name = plot.name if plot.name else plot.title
-            plot_menu = self.contextMenu.addMenu('&%s' % name)
-
-            self.actionDataInfo = plot_menu.addAction("&DataInfo")
-            self.actionDataInfo.triggered.connect(
-                                functools.partial(self.onDataInfo, plot))
-
-            self.actionSavePointsAsFile = plot_menu.addAction("&Save Points as a File")
-            self.actionSavePointsAsFile.triggered.connect(
-                                functools.partial(self.onSavePoints, plot))
-            plot_menu.addSeparator()
-
-            if plot.id != 'fit':
-                self.actionLinearFit = plot_menu.addAction('&Linear Fit')
-                self.actionLinearFit.triggered.connect(
-                                functools.partial(self.onLinearFit, id))
-                plot_menu.addSeparator()
-
-            self.actionRemovePlot = plot_menu.addAction("Remove")
-            self.actionRemovePlot.triggered.connect(
-                                functools.partial(self.onRemovePlot, id))
-
-            if not plot.is_data:
-                self.actionFreeze = plot_menu.addAction('&Freeze')
-                self.actionFreeze.triggered.connect(
-                                functools.partial(self.onFreeze, id))
-            plot_menu.addSeparator()
-
-            if plot.is_data:
-                self.actionHideError = plot_menu.addAction("Hide Error Bar")
-                if plot.dy is not None and plot.dy != []:
-                    if plot.hide_error:
-                        self.actionHideError.setText('Show Error Bar')
-                else:
-                    self.actionHideError.setEnabled(False)
-                self.actionHideError.triggered.connect(
-                                functools.partial(self.onToggleHideError, id))
-                plot_menu.addSeparator()
-
-            self.actionModifyPlot = plot_menu.addAction('&Modify Plot Property')
-            self.actionModifyPlot.triggered.connect(
-                                functools.partial(self.onModifyPlot, id))
-
-    def createContextMenuQuick(self):
-        """
-        Define context menu and associated actions for the quickplot MPL widget
-        """
-        # Default actions
-        self.defaultContextMenu()
-
-        # Additional actions
-        self.actionToggleGrid = self.contextMenu.addAction("Toggle Grid On/Off")
-        self.contextMenu.addSeparator()
-        self.actionChangeScale = self.contextMenu.addAction("Change Scale")
-
-        # Define the callbacks
-        self.actionToggleGrid.triggered.connect(self.onGridToggle)
-        self.actionChangeScale.triggered.connect(self.onScaleChange)
-
-    def onScaleChange(self):
-        """
-        Show a dialog allowing axes rescaling
-        """
-        if self.properties.exec_() == QtGui.QDialog.Accepted:
-            self.xLogLabel, self.yLogLabel = self.properties.getValues()
-            self.xyTransform(self.xLogLabel, self.yLogLabel)
-
-    def onAddText(self):
-        """
-        Show a dialog allowing adding custom text to the chart
-        """
-        if self.addText.exec_() == QtGui.QDialog.Accepted:
-            # Retrieve the new text, its font and color
-            extra_text = self.addText.text()
-            extra_font = self.addText.font()
-            extra_color = self.addText.color()
-
-            # Place the text on the screen at (0,0)
-            pos_x = self.x_click
-            pos_y = self.y_click
-
-            # Map QFont onto MPL font
-            mpl_font = FontProperties()
-            mpl_font.set_size(int(extra_font.pointSize()))
-            mpl_font.set_family(str(extra_font.family()))
-            mpl_font.set_weight(int(extra_font.weight()))
-            # MPL style names
-            styles = ['normal', 'italic', 'oblique']
-            # QFont::Style maps directly onto the above
-            try:
-                mpl_font.set_style(styles[extra_font.style()])
-            except:
-                pass
-
-            if len(extra_text) > 0:
-                new_text = self.ax.text(str(pos_x),
-                                        str(pos_y),
-                                        extra_text,
-                                        color=extra_color,
-                                        fontproperties=mpl_font)
-                # Update the list of annotations
-                self.textList.append(new_text)
-                self.canvas.draw_idle()
-
-    def onRemoveText(self):
-        """
-        Remove the most recently added text
-        """
-        num_text = len(self.textList)
-        if num_text < 1:
-            return
-        txt = self.textList[num_text - 1]
-        text_remove = txt.get_text()
-        txt.remove()
-        self.textList.remove(txt)
-
-        self.canvas.draw_idle()
-
-    def onSetGraphRange(self):
-        """
-        Show a dialog allowing setting the chart ranges
-        """
-        # min and max of data
-        if self.setRange.exec_() == QtGui.QDialog.Accepted:
-            x_range = self.setRange.xrange()
-            y_range = self.setRange.yrange()
-            if x_range is not None and y_range is not None:
-                self.ax.set_xlim(x_range)
-                self.ax.set_ylim(y_range)
-                self.canvas.draw_idle()
-
-    def onResetGraphRange(self):
-        """
-        Resets the chart X and Y ranges to their original values
-        """
-        x_range = (self.data.x.min(), self.data.x.max())
-        y_range = (self.data.y.min(), self.data.y.max())
-        if x_range is not None and y_range is not None:
-            self.ax.set_xlim(x_range)
-            self.ax.set_ylim(y_range)
-            self.canvas.draw_idle()
-
-    def onLinearFit(self, id):
-        """
-        Creates and displays a simple linear fit for the selected plot
-        """
-        selected_plot = self.plot_dict[id]
-
-        maxrange = (min(selected_plot.x), max(selected_plot.x))
-        fitrange = self.ax.get_xlim()
-
-        fit_dialog = LinearFit(parent=self,
-                    data=selected_plot,
-                    max_range=maxrange,
-                    fit_range=fitrange,
-                    xlabel=self.xLogLabel,
-                    ylabel=self.yLogLabel)
-        if fit_dialog.exec_() == QtGui.QDialog.Accepted:
-            return
-
-    def replacePlot(self, id, new_plot):
-        """
-        Remove plot 'id' and add 'new_plot' to the chart.
-        This effectlvely refreshes the chart with changes to one of its plots
-        """
-        self.removePlot(id)
-        self.plot(data=new_plot)
-
-    def onRemovePlot(self, id):
-        """
-        Responds to the plot delete action
-        """
-        self.removePlot(id)
-
-        if len(self.plot_dict) == 0:
-            # last plot: graph is empty must be the panel must be destroyed
-                self.parent.close()
-
-    def removePlot(self, id):
-        """
-        Deletes the selected plot from the chart
-        """
-        if id not in self.plot_dict:
-            return
-
-        selected_plot = self.plot_dict[id]
-
-        plot_dict = copy.deepcopy(self.plot_dict)
-
-        # Labels might have been changed
-        xl = self.ax.xaxis.label.get_text()
-        yl = self.ax.yaxis.label.get_text()
-
-        self.plot_dict = {}
-
-        plt.cla()
-        self.ax.cla()
-
-        for ids in plot_dict:
-            if ids != id:
-                self.plot(data=plot_dict[ids], hide_error=plot_dict[ids].hide_error)
-
-        # Reset the labels
-        self.ax.set_xlabel(xl)
-        self.ax.set_ylabel(yl)
-        self.canvas.draw()
-
-    def onFreeze(self, id):
-        """
-        Freezes the selected plot to a separate chart
-        """
-        plot = self.plot_dict[id]
-        self.manager.add_data(data_list=[plot])
-
-    def onModifyPlot(self, id):
-        """
-        Allows for MPL modifications to the selected plot
-        """
-        selected_plot = self.plot_dict[id]
-
-        # Old style color - single integer for enum color
-        # New style color - #hhhhhh
-        color = selected_plot.custom_color
-        # marker symbol and size
-        marker = selected_plot.symbol
-        marker_size = selected_plot.markersize
-        # plot name
-        legend = selected_plot.title
-
-        plotPropertiesWidget = PlotProperties(self,
-                                color=color,
-                                marker=marker,
-                                marker_size=marker_size,
-                                legend=legend)
-        if plotPropertiesWidget.exec_() == QtGui.QDialog.Accepted:
-            # Update Data1d
-            selected_plot.markersize = plotPropertiesWidget.markersize()
-            selected_plot.custom_color = plotPropertiesWidget.color()
-            selected_plot.symbol = plotPropertiesWidget.marker()
-            selected_plot.title = plotPropertiesWidget.legend()
-
-            # Redraw the plot
-            self.replacePlot(id, selected_plot)
-
-    def onToggleHideError(self, id):
-        """
-        Toggles hide error/show error menu item
-        """
-        selected_plot = self.plot_dict[id]
-        current = selected_plot.hide_error
-
-        # Flip the flag
-        selected_plot.hide_error = not current
-
-        plot_dict = copy.deepcopy(self.plot_dict)
-        self.plot_dict = {}
-
-        # Clean the canvas
-        plt.cla()
-        self.ax.cla()
-
-        # Recreate the plots but reverse the error flag for the current
-        for ids in plot_dict:
-            if ids == id:
-                self.plot(data=plot_dict[ids], hide_error=(not current))
-            else:
-                self.plot(data=plot_dict[ids], hide_error=plot_dict[ids].hide_error)                
-
-    def xyTransform(self, xLabel="", yLabel=""):
-        """
-        Transforms x and y in View and set the scale
-        """
-        # Transform all the plots on the chart
-        for id in self.plot_dict.keys():
-            current_plot = self.plot_dict[id]
-            if current_plot.id == "fit":
-                self.removePlot(id)
-                continue
-
-            new_xlabel, new_ylabel, xscale, yscale =\
-                GuiUtils.xyTransform(current_plot, xLabel, yLabel)
-            self.xscale = xscale
-            self.yscale = yscale
-
-            # Plot the updated chart
-            self.removePlot(id)
-
-            # This assignment will wrap the label in Latex "$"
-            self.xLabel = new_xlabel
-            self.yLabel = new_ylabel
-            # Directly overwrite the data to avoid label reassignment
-            self._data = current_plot
-            self.plot()
-
-        pass # debug hook
-
-    def onFitDisplay(self, fit_data):
-        """
-        Add a linear fitting line to the chart
-        """
-        # Create new data structure with fitting result
-        tempx = fit_data[0]
-        tempy = fit_data[1]
-        self.fit_result.x = []
-        self.fit_result.y = []
-        self.fit_result.x = tempx
-        self.fit_result.y = tempy
-        self.fit_result.dx = None
-        self.fit_result.dy = None
-
-        #Remove another Fit, if exists
-        self.removePlot("fit")
-
-        self.fit_result.reset_view()
-        #self.offset_graph()
-
-        # Set plot properties
-        self.fit_result.id = 'fit'
-        self.fit_result.title = 'Fit'
-        self.fit_result.name = 'Fit'
-
-        # Plot the line
-        self.plot(data=self.fit_result, marker='-', hide_error=True)
-
-    def onMplMouseDown(self, event):
-        """
-        Left button down and ready to drag
-        """
-        # Check that the LEFT button was pressed
-        if event.button != 1:
-            return
-
-        self.leftdown = True
-        for text in self.textList:
-            if text.contains(event)[0]: # If user has clicked on text
-                self.selectedText = text
-                return
-        if event.inaxes is None:
-            return
-        try:
-            self.x_click = float(event.xdata)  # / size_x
-            self.y_click = float(event.ydata)  # / size_y
-        except:
-            self.position = None
-
-    def onMplMouseUp(self, event):
-        """
-        Set the data coordinates of the click
-        """
-        self.x_click = event.xdata
-        self.y_click = event.ydata
-
-        # Check that the LEFT button was released
-        if event.button == 1:
-            self.leftdown = False
-            self.selectedText = None
-
-        #release the legend
-        if self.gotLegend == 1:
-            self.gotLegend = 0
-
-    def onMplMouseMotion(self, event):
-        """
-        Check if the left button is press and the mouse in moving.
-        Compute delta for x and y coordinates and then perform the drag
-        """
-        if self.gotLegend == 1 and self.leftdown:
-            self.onLegendMotion(event)
-            return
-
-        #if self.leftdown and self.selectedText is not None:
-        if not self.leftdown or self.selectedText is None:
-            return
-        # User has clicked on text and is dragging
-        if event.inaxes is None:
-            # User has dragged outside of axes
-            self.selectedText = None
-        else:
-            # Only move text if mouse is within axes
-            self.selectedText.set_position((event.xdata, event.ydata))
-            self.canvas.draw_idle()
-        return
-
-    def onMplPick(self, event):
-        """
-        On pick legend
-        """
-        legend = self.legend
-        if event.artist != legend:
-            return
-        # Get the box of the legend.
-        bbox = self.legend.get_window_extent()
-        # Get mouse coordinates at time of pick.
-        self.mouse_x = event.mouseevent.x
-        self.mouse_y = event.mouseevent.y
-        # Get legend coordinates at time of pick.
-        self.legend_x = bbox.xmin
-        self.legend_y = bbox.ymin
-        # Indicate we picked up the legend.
-        self.gotLegend = 1
-
-        #self.legend.legendPatch.set_alpha(0.5)
-
-    def onLegendMotion(self, event):
-        """
-        On legend in motion
-        """
-        ax = event.inaxes
-        if ax == None:
-            return
-        # Event occurred inside a plotting area
-        lo_x, hi_x = ax.get_xlim()
-        lo_y, hi_y = ax.get_ylim()
-        # How much the mouse moved.
-        x = mouse_diff_x = self.mouse_x - event.x
-        y = mouse_diff_y = self.mouse_y - event.y
-        # Put back inside
-        if x < lo_x:
-            x = lo_x
-        if x > hi_x:
-            x = hi_x
-        if y < lo_y:
-            y = lo_y
-        if y > hi_y:
-            y = hi_y
-        # Move the legend from its previous location by that same amount
-        loc_in_canvas = self.legend_x - mouse_diff_x, \
-                        self.legend_y - mouse_diff_y
-        # Transform into legend coordinate system
-        trans_axes = self.legend.parent.transAxes.inverted()
-        loc_in_norm_axes = trans_axes.transform_point(loc_in_canvas)
-        self.legend_pos_loc = tuple(loc_in_norm_axes)
-        self.legend._loc = self.legend_pos_loc
-        # self.canvas.draw()
-        self.canvas.draw_idle()
-
-    def onMplWheel(self, event):
-        """
-        Process mouse wheel as zoom events
-        """
-        ax = event.inaxes
-        step = event.step
-
-        if ax != None:
-            # Event occurred inside a plotting area
-            lo, hi = ax.get_xlim()
-            lo, hi = PlotUtilities.rescale(lo, hi, step,
-                              pt=event.xdata, scale=ax.get_xscale())
-            if not self.xscale == 'log' or lo > 0:
-                self._scale_xlo = lo
-                self._scale_xhi = hi
-                ax.set_xlim((lo, hi))
-
-            lo, hi = ax.get_ylim()
-            lo, hi = PlotUtilities.rescale(lo, hi, step, pt=event.ydata,
-                              scale=ax.get_yscale())
-            if not self.yscale == 'log' or lo > 0:
-                self._scale_ylo = lo
-                self._scale_yhi = hi
-                ax.set_ylim((lo, hi))
-        else:
-            # Check if zoom happens in the axes
-            xdata, ydata = None, None
-            x, y = event.x, event.y
-
-            for ax in self.axes:
-                insidex, _ = ax.xaxis.contains(event)
-                if insidex:
-                    xdata, _ = ax.transAxes.inverted().transform_point((x, y))
-                insidey, _ = ax.yaxis.contains(event)
-                if insidey:
-                    _, ydata = ax.transAxes.inverted().transform_point((x, y))
-            if xdata is not None:
-                lo, hi = ax.get_xlim()
-                lo, hi = PlotUtilities.rescale(lo, hi, step,
-                                  bal=xdata, scale=ax.get_xscale())
-                if not self.xscale == 'log' or lo > 0:
-                    self._scale_xlo = lo
-                    self._scale_xhi = hi
-                    ax.set_xlim((lo, hi))
-            if ydata is not None:
-                lo, hi = ax.get_ylim()
-                lo, hi = PlotUtilities.rescale(lo, hi, step, bal=ydata,
-                                  scale=ax.get_yscale())
-                if not self.yscale == 'log' or lo > 0:
-                    self._scale_ylo = lo
-                    self._scale_yhi = hi
-                    ax.set_ylim((lo, hi))
-        self.canvas.draw_idle()
-
-
-class Plotter(QtGui.QDialog, PlotterWidget):
-    def __init__(self, parent=None, quickplot=False):
-
-        QtGui.QDialog.__init__(self)
-        PlotterWidget.__init__(self, parent=self, manager=parent, quickplot=quickplot)
-        icon = QtGui.QIcon()
-        icon.addPixmap(QtGui.QPixmap(":/res/ball.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
-        self.setWindowIcon(icon)
-
-
Index: c/sas/qtgui/Plotter2D.py
===================================================================
--- src/sas/qtgui/Plotter2D.py	(revision 116260af576567e73b38d3209bd4fbb3eb3dc267)
+++ 	(revision )
@@ -1,506 +1,0 @@
-import copy
-import numpy
-import pylab
-import functools
-
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-
-DEFAULT_CMAP = pylab.cm.jet
-from mpl_toolkits.mplot3d import Axes3D
-
-import sas.qtgui.PlotUtilities as PlotUtilities
-import sas.qtgui.GuiUtils as GuiUtils
-from sas.qtgui.PlotterBase import PlotterBase
-from sas.qtgui.ColorMap import ColorMap
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.dataFitting import Data2D
-from sas.sascalc.dataloader.manipulations import CircularAverage
-from sas.sasgui.guiframe.local_perspectives.plotting.binder import BindArtist
-from sas.qtgui.BoxSum import BoxSum
-from sas.qtgui.SlicerParameters import SlicerParameters
-from sas.sasgui.guiframe.local_perspectives.plotting.boxSlicer import BoxInteractorX
-from sas.sasgui.guiframe.local_perspectives.plotting.AnnulusSlicer import AnnulusInteractor
-from sas.sasgui.guiframe.local_perspectives.plotting.SectorSlicer import SectorInteractor
-from sas.sasgui.guiframe.local_perspectives.plotting.boxSum import BoxSumCalculator
-from sas.sasgui.guiframe.local_perspectives.plotting.boxSlicer import BoxInteractorY
-
-# Minimum value of Z for which we will present data.
-MIN_Z = -32
-
-class Plotter2DWidget(PlotterBase):
-    """
-    2D Plot widget for use with a QDialog
-    """
-    def __init__(self, parent=None, manager=None, quickplot=False, dimension=2):
-        self.dimension = dimension
-        super(Plotter2DWidget, self).__init__(parent, manager=manager, quickplot=quickplot)
-
-        self.cmap = DEFAULT_CMAP.name
-        # Default scale
-        self.scale = 'log_{10}'
-        # to set the order of lines drawn first.
-        self.slicer_z = 5
-        # Reference to the current slicer
-        self.slicer = None
-        self.slicer_widget = None
-        # Create Artist and bind it
-        self.connect = BindArtist(self.figure)
-        self.vmin = None
-        self.vmax = None
-
-        self.manager = manager
-
-    @property
-    def data(self):
-        return self._data
-
-    @data.setter
-    def data(self, data=None):
-        """ data setter """
-        self._data = data
-        self.qx_data = data.qx_data
-        self.qy_data = data.qy_data
-        self.xmin = data.xmin
-        self.xmax = data.xmax
-        self.ymin = data.ymin
-        self.ymax = data.ymax
-        self.zmin = data.zmin
-        self.zmax = data.zmax
-        self.label = data.name
-        self.xLabel = "%s(%s)"%(data._xaxis, data._xunit)
-        self.yLabel = "%s(%s)"%(data._yaxis, data._yunit)
-        self.title(title=data.title)
-
-    @property
-    def item(self):
-        ''' getter for this plot's QStandardItem '''
-        return self._item
-
-    @item.setter
-    def item(self, item=None):
-        ''' setter for this plot's QStandardItem '''
-        self._item = item
-
-    def plot(self, data=None, marker=None):
-        """
-        Plot 2D self._data
-        marker - unused
-        """
-        # Assing data
-        if isinstance(data, Data2D):
-            self.data = data
-
-        assert self._data
-
-        # Toggle the scale
-        zmin_2D_temp, zmax_2D_temp = self.calculateDepth()
-
-        # Prepare and show the plot
-        self.showPlot(data=self.data.data,
-                      qx_data=self.qx_data,
-                      qy_data=self.qy_data,
-                      xmin=self.xmin,
-                      xmax=self.xmax,
-                      ymin=self.ymin, ymax=self.ymax,
-                      cmap=self.cmap, zmin=zmin_2D_temp,
-                      zmax=zmax_2D_temp)
-
-    def calculateDepth(self):
-        """
-        Re-calculate the plot depth parameters depending on the scale
-        """
-        # Toggle the scale
-        zmin_temp = self.zmin
-        zmax_temp = self.zmax
-        # self.scale predefined in the baseclass
-        if self.scale == 'log_{10}':
-            if self.zmin is not None:
-                zmin_temp = numpy.power(10, self.zmin)
-            if self.zmax is not None:
-                zmax_temp = numpy.power(10, self.zmax)
-        else:
-            if self.zmin is not None:
-                # min log value: no log(negative)
-                zmin_temp = MIN_Z if self.zmin <= 0 else numpy.log10(self.zmin)
-            if self.zmax is not None:
-                zmax_temp = numpy.log10(self.zmax)
-
-        return (zmin_temp, zmax_temp)
-
-
-    def createContextMenu(self):
-        """
-        Define common context menu and associated actions for the MPL widget
-        """
-        self.defaultContextMenu()
-
-        self.contextMenu.addSeparator()
-        self.actionDataInfo = self.contextMenu.addAction("&DataInfo")
-        self.actionDataInfo.triggered.connect(
-             functools.partial(self.onDataInfo, self.data))
-
-        self.actionSavePointsAsFile = self.contextMenu.addAction("&Save Points as a File")
-        self.actionSavePointsAsFile.triggered.connect(
-             functools.partial(self.onSavePoints, self.data))
-        self.contextMenu.addSeparator()
-
-        self.actionCircularAverage = self.contextMenu.addAction("&Perform Circular Average")
-        self.actionCircularAverage.triggered.connect(self.onCircularAverage)
-
-        self.actionSectorView = self.contextMenu.addAction("&Sector [Q View]")
-        self.actionSectorView.triggered.connect(self.onSectorView)
-        self.actionAnnulusView = self.contextMenu.addAction("&Annulus [Phi View]")
-        self.actionAnnulusView.triggered.connect(self.onAnnulusView)
-        self.actionBoxSum = self.contextMenu.addAction("&Box Sum")
-        self.actionBoxSum.triggered.connect(self.onBoxSum)
-        self.actionBoxAveragingX = self.contextMenu.addAction("&Box Averaging in Qx")
-        self.actionBoxAveragingX.triggered.connect(self.onBoxAveragingX)
-        self.actionBoxAveragingY = self.contextMenu.addAction("&Box Averaging in Qy")
-        self.actionBoxAveragingY.triggered.connect(self.onBoxAveragingY)
-        # Additional items for slicer interaction
-        if self.slicer:
-            self.actionClearSlicer = self.contextMenu.addAction("&Clear Slicer")
-            self.actionClearSlicer.triggered.connect(self.onClearSlicer)
-            if self.slicer.__class__.__name__ != "BoxSumCalculator":
-                self.actionEditSlicer = self.contextMenu.addAction("&Edit Slicer Parameters")
-                self.actionEditSlicer.triggered.connect(self.onEditSlicer)
-        self.contextMenu.addSeparator()
-        self.actionColorMap = self.contextMenu.addAction("&2D Color Map")
-        self.actionColorMap.triggered.connect(self.onColorMap)
-        self.contextMenu.addSeparator()
-        self.actionChangeScale = self.contextMenu.addAction("Toggle Linear/Log Scale")
-        self.actionChangeScale.triggered.connect(self.onToggleScale)
-
-    def createContextMenuQuick(self):
-        """
-        Define context menu and associated actions for the quickplot MPL widget
-        """
-        self.defaultContextMenu()
-
-        if self.dimension == 2:
-            self.actionToggleGrid = self.contextMenu.addAction("Toggle Grid On/Off")
-            self.contextMenu.addSeparator()
-        self.actionChangeScale = self.contextMenu.addAction("Toggle Linear/Log Scale")
-
-        # Define the callbacks
-        self.actionChangeScale.triggered.connect(self.onToggleScale)
-        if self.dimension == 2:
-            self.actionToggleGrid.triggered.connect(self.onGridToggle)
-
-    def onToggleScale(self, event):
-        """
-        Toggle axis and replot image
-        """
-        # self.scale predefined in the baseclass
-        if self.scale == 'log_{10}':
-            self.scale = 'linear'
-        else:
-            self.scale = 'log_{10}'
-
-        self.plot()
-
-    def onClearSlicer(self):
-        """
-        Remove all sclicers from the chart
-        """
-        if self.slicer is None:
-            return
-
-        self.slicer.clear()
-        self.canvas.draw()
-        self.slicer = None
-
-    def onEditSlicer(self):
-        """
-        Present a small dialog for manipulating the current slicer
-        """
-        assert self.slicer
-        # Only show the dialog if not currently shown
-        if self.slicer_widget:
-            return
-        def slicer_closed():
-            # Need to disconnect the signal!!
-            self.slicer_widget.close_signal.disconnect()
-            # reset slicer_widget on "Edit Slicer Parameters" window close
-            self.slicer_widget = None
-
-        self.param_model = self.slicer.model()
-        # Pass the model to the Slicer Parameters widget
-        self.slicer_widget = SlicerParameters(model=self.param_model,
-                                              validate_method=self.slicer.validate)
-        self.slicer_widget.close_signal.connect(slicer_closed)
-        # Add the plot to the workspace
-        self.manager.parent.workspace().addWindow(self.slicer_widget)
-
-        self.slicer_widget.show()
-
-    def onCircularAverage(self):
-        """
-        Perform circular averaging on Data2D
-        """
-        # Find the best number of bins
-        npt = numpy.sqrt(len(self.data.data[numpy.isfinite(self.data.data)]))
-        npt = numpy.floor(npt)
-        # compute the maximum radius of data2D
-        self.qmax = max(numpy.fabs(self.data.xmax),
-                        numpy.fabs(self.data.xmin))
-        self.ymax = max(numpy.fabs(self.data.ymax),
-                        numpy.fabs(self.data.ymin))
-        self.radius = numpy.sqrt(numpy.power(self.qmax, 2) + numpy.power(self.ymax, 2))
-        #Compute beam width
-        bin_width = (self.qmax + self.qmax) / npt
-        # Create data1D circular average of data2D
-        circle = CircularAverage(r_min=0, r_max=self.radius, bin_width=bin_width)
-        circ = circle(self.data)
-        dxl = circ.dxl if hasattr(circ, "dxl") else None
-        dxw = circ.dxw if hasattr(circ, "dxw") else None
-
-        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
-        new_plot.dxl = dxl
-        new_plot.dxw = dxw
-        new_plot.name = new_plot.title = "Circ avg " + self.data.name
-        new_plot.source = self.data.source
-        new_plot.interactive = True
-        new_plot.detector = self.data.detector
-
-        # Define axes if not done yet.
-        new_plot.xaxis("\\rm{Q}", "A^{-1}")
-        if hasattr(self.data, "scale") and \
-                    self.data.scale == 'linear':
-            new_plot.ytransform = 'y'
-            new_plot.yaxis("\\rm{Residuals} ", "normalized")
-        else:
-            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
-
-        new_plot.group_id = "2daverage" + self.data.name
-        new_plot.id = "Circ avg " + self.data.name
-        new_plot.is_data = True
-        variant_plot = QtCore.QVariant(new_plot)
-        GuiUtils.updateModelItemWithPlot(self._item, variant_plot, new_plot.id)
-        self.manager.communicator.plotUpdateSignal.emit([new_plot])
-
-    def setSlicer(self, slicer):
-        """
-        Clear the previous slicer and create a new one.
-        slicer: slicer class to create
-        """
-        # Clear current slicer
-        if self.slicer is not None:
-            self.slicer.clear()
-        # Create a new slicer
-        self.slicer_z += 1
-        self.slicer = slicer(self, self.ax, item=self._item, zorder=self.slicer_z)
-        self.ax.set_ylim(self.data.ymin, self.data.ymax)
-        self.ax.set_xlim(self.data.xmin, self.data.xmax)
-        # Draw slicer
-        self.figure.canvas.draw()
-        self.slicer.update()
-
-        # Reset the model on the Edit slicer parameters widget
-        self.param_model = self.slicer.model()
-        if self.slicer_widget:
-            self.slicer_widget.setModel(self.param_model)
-
-    def onSectorView(self):
-        """
-        Perform sector averaging on Q and draw sector slicer
-        """
-        self.setSlicer(slicer=SectorInteractor)
-
-    def onAnnulusView(self):
-        """
-        Perform sector averaging on Phi and draw annulus slicer
-        """
-        self.setSlicer(slicer=AnnulusInteractor)
-
-    def onBoxSum(self):
-        """
-        Perform 2D Data averaging Qx and Qy.
-        Display box slicer details.
-        """
-        self.onClearSlicer()
-        self.slicer_z += 1
-        self.slicer = BoxSumCalculator(self, self.ax, zorder=self.slicer_z)
-
-        self.ax.set_ylim(self.data.ymin, self.data.ymax)
-        self.ax.set_xlim(self.data.xmin, self.data.xmax)
-        self.figure.canvas.draw()
-        self.slicer.update()
-
-        # Get the BoxSumCalculator model.
-        self.box_sum_model = self.slicer.model()
-        # Pass the BoxSumCalculator model to the BoxSum widget
-        self.boxwidget = BoxSum(self, model=self.box_sum_model)
-        # Add the plot to the workspace
-        self.manager.parent.workspace().addWindow(self.boxwidget)
-        self.boxwidget.show()
-
-    def onBoxAveragingX(self):
-        """
-        Perform 2D data averaging on Qx
-        Create a new slicer.
-        """
-        self.setSlicer(slicer=BoxInteractorX)
-
-    def onBoxAveragingY(self):
-        """
-        Perform 2D data averaging on Qy
-        Create a new slicer .
-        """
-        self.setSlicer(slicer=BoxInteractorY)
-
-    def onColorMap(self):
-        """
-        Display the color map dialog and modify the plot's map accordingly
-        """
-        color_map_dialog = ColorMap(self, cmap=self.cmap,
-                                    vmin=self.vmin,
-                                    vmax=self.vmax,
-                                    data=self.data)
-
-        color_map_dialog.apply_signal.connect(self.onApplyMap)
-
-        if color_map_dialog.exec_() == QtGui.QDialog.Accepted:
-            self.onApplyMap(color_map_dialog.norm(), color_map_dialog.cmap())
-
-    def onApplyMap(self, v_values, cmap):
-        """
-        Update the chart color map based on data passed from the widget
-        """
-        self.cmap = str(cmap)
-        self.vmin, self.vmax = v_values
-        # Redraw the chart with new cmap
-        self.plot()
-
-    def showPlot(self, data, qx_data, qy_data, xmin, xmax, ymin, ymax,
-                 zmin, zmax, label='data2D', cmap=DEFAULT_CMAP):
-        """
-        Render and show the current data
-        """
-        self.qx_data = qx_data
-        self.qy_data = qy_data
-        self.xmin = xmin
-        self.xmax = xmax
-        self.ymin = ymin
-        self.ymax = ymax
-        self.zmin = zmin
-        self.zmax = zmax
-        # If we don't have any data, skip.
-        if data is None:
-            return
-        if data.ndim == 1:
-            output = PlotUtilities.build_matrix(data, self.qx_data, self.qy_data)
-        else:
-            output = copy.deepcopy(data)
-
-        zmin_temp = self.zmin
-        # check scale
-        if self.scale == 'log_{10}':
-            try:
-                if  self.zmin <= 0  and len(output[output > 0]) > 0:
-                    zmin_temp = self.zmin
-                    output[output > 0] = numpy.log10(output[output > 0])
-                elif self.zmin <= 0:
-                    zmin_temp = self.zmin
-                    output[output > 0] = numpy.zeros(len(output))
-                    output[output <= 0] = MIN_Z
-                else:
-                    zmin_temp = self.zmin
-                    output[output > 0] = numpy.log10(output[output > 0])
-            except:
-                #Too many problems in 2D plot with scale
-                output[output > 0] = numpy.log10(output[output > 0])
-                pass
-
-        self.cmap = cmap
-        if self.dimension != 3:
-            #Re-adjust colorbar
-            self.figure.subplots_adjust(left=0.2, right=.8, bottom=.2)
-
-            zmax_temp = self.zmax
-            if self.vmin is not None:
-                zmin_temp = self.vmin
-                zmax_temp = self.vmax
-
-            im = self.ax.imshow(output, interpolation='nearest',
-                                origin='lower',
-                                vmin=zmin_temp, vmax=zmax_temp,
-                                cmap=self.cmap,
-                                extent=(self.xmin, self.xmax,
-                                        self.ymin, self.ymax))
-
-            cbax = self.figure.add_axes([0.84, 0.2, 0.02, 0.7])
-
-            # Current labels for axes
-            self.ax.set_ylabel(self.y_label)
-            self.ax.set_xlabel(self.x_label)
-
-            # Title only for regular charts
-            if not self.quickplot:
-                self.ax.set_title(label=self._title)
-
-            if cbax is None:
-                ax.set_frame_on(False)
-                cb = self.figure.colorbar(im, shrink=0.8, aspect=20)
-            else:
-                cb = self.figure.colorbar(im, cax=cbax)
-
-            cb.update_bruteforce(im)
-            cb.set_label('$' + self.scale + '$')
-
-            self.vmin = cb.vmin
-            self.vmax = cb.vmax
-
-        else:
-            # clear the previous 2D from memory
-            self.figure.clear()
-
-            self.figure.subplots_adjust(left=0.1, right=.8, bottom=.1)
-
-            data_x, data_y = numpy.meshgrid(self._data.x_bins[0:-1],
-                                            self._data.y_bins[0:-1])
-
-            ax = Axes3D(self.figure)
-
-            # Disable rotation for large sets.
-            # TODO: Define "large" for a dataset
-            SET_TOO_LARGE = 500
-            if len(data_x) > SET_TOO_LARGE:
-                ax.disable_mouse_rotation()
-
-            self.figure.canvas.resizing = False
-            im = ax.plot_surface(data_x, data_y, output, rstride=1,
-                                 cstride=1, cmap=cmap,
-                                 linewidth=0, antialiased=False)
-            self.ax.set_axis_off()
-
-        if self.dimension != 3:
-            self.figure.canvas.draw_idle()
-        else:
-            self.figure.canvas.draw()
-
-    def update(self):
-        self.figure.canvas.draw()
-
-    def draw(self):
-        self.figure.canvas.draw()
-
-    def replacePlot(self, id, new_plot):
-        """
-        Replace data in current chart.
-        This effectlvely refreshes the chart with changes to one of its plots
-        """
-        self.plot(data=new_plot)
-
-
-class Plotter2D(QtGui.QDialog, Plotter2DWidget):
-    """
-    Plotter widget implementation
-    """
-    def __init__(self, parent=None, quickplot=False, dimension=2):
-        QtGui.QDialog.__init__(self)
-        Plotter2DWidget.__init__(self, manager=parent, quickplot=quickplot, dimension=dimension)
-        icon = QtGui.QIcon()
-        icon.addPixmap(QtGui.QPixmap(":/res/ball.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
-        self.setWindowIcon(icon)
Index: c/sas/qtgui/PlotterBase.py
===================================================================
--- src/sas/qtgui/PlotterBase.py	(revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ 	(revision )
@@ -1,377 +1,0 @@
-import pylab
-import numpy
-
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-
-# TODO: Replace the qt4agg calls below with qt5 equivalent.
-# Requires some code modifications.
-# https://www.boxcontrol.net/embedding-matplotlib-plot-on-pyqt5-gui.html
-#
-from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
-from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
-
-import matplotlib.pyplot as plt
-
-DEFAULT_CMAP = pylab.cm.jet
-from sas.sasgui.plottools.binder import BindArtist
-
-import sas.qtgui.GuiUtils as GuiUtils
-from sas.sasgui.guiframe.dataFitting import Data1D, Data2D
-from sas.qtgui.ScaleProperties import ScaleProperties
-from sas.qtgui.WindowTitle import WindowTitle
-import sas.qtgui.PlotHelper as PlotHelper
-import sas.qtgui.PlotUtilities as PlotUtilities
-
-class PlotterBase(QtGui.QWidget):
-    def __init__(self, parent=None, manager=None, quickplot=False):
-        super(PlotterBase, self).__init__(parent)
-
-        # Required for the communicator
-        self.manager = manager
-        self.quickplot = quickplot
-
-        # a figure instance to plot on
-        self.figure = plt.figure()
-
-        # Define canvas for the figure to be placed on
-        self.canvas = FigureCanvas(self.figure)
-
-        # ... and the toolbar with all the default MPL buttons
-        self.toolbar = NavigationToolbar(self.canvas, self)
-
-        # Simple window for data display
-        self.txt_widget = QtGui.QTextEdit(None)
-
-        # Set the layout and place the canvas widget in it.
-        layout = QtGui.QVBoxLayout()
-        layout.setMargin(0)
-        layout.addWidget(self.canvas)
-
-        # 1D plotter defaults
-        self.current_plot = 111
-        self._data = [] # Original 1D/2D object
-        self._xscale = 'log'
-        self._yscale = 'log'
-        self.qx_data = []
-        self.qy_data = []
-        self.color = 0
-        self.symbol = 0
-        self.grid_on = False
-        self.scale = 'linear'
-        self.x_label = "log10(x)"
-        self.y_label = "log10(y)"
-
-        # Mouse click related
-        self._scale_xlo = None
-        self._scale_xhi = None
-        self._scale_ylo = None
-        self._scale_yhi = None
-        self.x_click = None
-        self.y_click = None
-        self.event_pos = None
-        self.leftdown = False
-        self.gotLegend = 0
-
-        # Annotations
-        self.selectedText = None
-        self.textList = []
-
-        # Pre-define the Scale properties dialog
-        self.properties = ScaleProperties(self,
-                                init_scale_x=self.x_label,
-                                init_scale_y=self.y_label)
-
-        # default color map
-        self.cmap = DEFAULT_CMAP
-
-        # Add the axes object -> subplot
-        # TODO: self.ax will have to be tracked and exposed
-        # to enable subplot specific operations
-        self.ax = self.figure.add_subplot(self.current_plot)
-
-        # Remove this, DAMMIT
-        self.axes = [self.ax]
-
-        # Set the background color to white
-        self.canvas.figure.set_facecolor('#FFFFFF')
-
-        # Canvas event handlers
-        self.canvas.mpl_connect('button_release_event', self.onMplMouseUp)
-        self.canvas.mpl_connect('button_press_event', self.onMplMouseDown)
-        self.canvas.mpl_connect('motion_notify_event', self.onMplMouseMotion)
-        self.canvas.mpl_connect('pick_event', self.onMplPick)
-        self.canvas.mpl_connect('scroll_event', self.onMplWheel)
-
-        self.contextMenu = QtGui.QMenu(self)
-
-        if not quickplot:
-            # Add the toolbar
-            layout.addWidget(self.toolbar)
-            # Notify PlotHelper about the new plot
-            self.upatePlotHelper()
-
-        self.setLayout(layout)
-
-    @property
-    def data(self):
-        """ data getter """
-        return self._data
-
-    @data.setter
-    def data(self, data=None):
-        """ Pure virtual data setter """
-        raise NotImplementedError("Data setter must be implemented in derived class.")
-
-    def title(self, title=""):
-        """ title setter """
-        self._title = title
-
-    @property
-    def xLabel(self, xlabel=""):
-        """ x-label setter """
-        return self.x_label
-
-    @xLabel.setter
-    def xLabel(self, xlabel=""):
-        """ x-label setter """
-        self.x_label = r'$%s$'% xlabel
-
-    @property
-    def yLabel(self, ylabel=""):
-        """ y-label setter """
-        return self.y_label
-
-    @yLabel.setter
-    def yLabel(self, ylabel=""):
-        """ y-label setter """
-        self.y_label = r'$%s$'% ylabel
-
-    @property
-    def yscale(self):
-        """ Y-axis scale getter """
-        return self._yscale
-
-    @yscale.setter
-    def yscale(self, scale='linear'):
-        """ Y-axis scale setter """
-        self.ax.set_yscale(scale, nonposy='clip')
-        self._yscale = scale
-
-    @property
-    def xscale(self):
-        """ X-axis scale getter """
-        return self._xscale
-
-    @xscale.setter
-    def xscale(self, scale='linear'):
-        """ X-axis scale setter """
-        self.ax.set_xscale(scale)
-        self._xscale = scale
-
-    def upatePlotHelper(self):
-        """
-        Notify the plot helper about the new plot
-        """
-        # Notify the helper
-        PlotHelper.addPlot(self)
-        # Notify the listeners about a new graph
-        self.manager.communicator.activeGraphsSignal.emit(PlotHelper.currentPlots())
-
-    def defaultContextMenu(self):
-        """
-        Content of the dialog-universal context menu:
-        Save, Print and Copy
-        """
-        # Actions
-        self.contextMenu.clear()
-        self.actionSaveImage = self.contextMenu.addAction("Save Image")
-        self.actionPrintImage = self.contextMenu.addAction("Print Image")
-        self.actionCopyToClipboard = self.contextMenu.addAction("Copy to Clipboard")
-        self.contextMenu.addSeparator()
-
-        # Define the callbacks
-        self.actionSaveImage.triggered.connect(self.onImageSave)
-        self.actionPrintImage.triggered.connect(self.onImagePrint)
-        self.actionCopyToClipboard.triggered.connect(self.onClipboardCopy)
-
-    def createContextMenu(self):
-        """
-        Define common context menu and associated actions for the MPL widget
-        """
-        raise NotImplementedError("Context menu method must be implemented in derived class.")
-
-    def createContextMenuQuick(self):
-        """
-        Define context menu and associated actions for the quickplot MPL widget
-        """
-        raise NotImplementedError("Context menu method must be implemented in derived class.")
-
-    def contextMenuEvent(self, event):
-        """
-        Display the context menu
-        """
-        if not self.quickplot:
-            self.createContextMenu()
-        else:
-            self.createContextMenuQuick()
-
-        event_pos = event.pos()
-        self.contextMenu.exec_(self.canvas.mapToGlobal(event_pos))
-
-    def onMplMouseUp(self, event):
-        """
-        Mouse button up callback
-        """
-        pass
-
-    def onMplMouseDown(self, event):
-        """
-        Mouse button down callback
-        """
-        pass
-
-    def onMplMouseMotion(self, event):
-        """
-        Mouse motion callback
-        """
-        pass
-
-    def onMplPick(self, event):
-        """
-        Mouse pick callback
-        """
-        pass
-
-    def onMplWheel(self, event):
-        """
-        Mouse wheel scroll callback
-        """
-        pass
-
-    def clean(self):
-        """
-        Redraw the graph
-        """
-        self.figure.delaxes(self.ax)
-        self.ax = self.figure.add_subplot(self.current_plot)
-
-    def plot(self, marker=None, linestyle=None):
-        """
-        PURE VIRTUAL
-        Plot the content of self._data
-        """
-        raise NotImplementedError("Plot method must be implemented in derived class.")
-
-    def closeEvent(self, event):
-        """
-        Overwrite the close event adding helper notification
-        """
-        # Please remove me from your database.
-        PlotHelper.deletePlot(PlotHelper.idOfPlot(self))
-        # Notify the listeners
-        self.manager.communicator.activeGraphsSignal.emit(PlotHelper.currentPlots())
-        event.accept()
-
-    def onImageSave(self):
-        """
-        Use the internal MPL method for saving to file
-        """
-        self.toolbar.save_figure()
-
-    def onImagePrint(self):
-        """
-        Display printer dialog and print the MPL widget area
-        """
-        # Define the printer
-        printer = QtGui.QPrinter()
-
-        # Display the print dialog
-        dialog = QtGui.QPrintDialog(printer)
-        dialog.setModal(True)
-        dialog.setWindowTitle("Print")
-        if dialog.exec_() != QtGui.QDialog.Accepted:
-            return
-
-        painter = QtGui.QPainter(printer)
-        # Grab the widget screenshot
-        pmap = QtGui.QPixmap.grabWidget(self)
-        # Create a label with pixmap drawn
-        printLabel = QtGui.QLabel()
-        printLabel.setPixmap(pmap)
-
-        # Print the label
-        printLabel.render(painter)
-        painter.end()
-
-    def onClipboardCopy(self):
-        """
-        Copy MPL widget area to buffer
-        """
-        bmp = QtGui.QApplication.clipboard()
-        pixmap = QtGui.QPixmap.grabWidget(self.canvas)
-        bmp.setPixmap(pixmap)
-
-    def onGridToggle(self):
-        """
-        Add/remove grid lines from MPL plot
-        """
-        self.grid_on = (not self.grid_on)
-        self.ax.grid(self.grid_on)
-        self.canvas.draw_idle()
-
-    def onWindowsTitle(self):
-        """
-        Show a dialog allowing chart title customisation
-        """
-        current_title = self.windowTitle()
-        titleWidget = WindowTitle(self, new_title=current_title)
-        result = titleWidget.exec_()
-        if result != QtGui.QDialog.Accepted:
-            return
-
-        title = titleWidget.title()
-        self.setWindowTitle(title)
-        # Notify the listeners about a new graph title
-        self.manager.communicator.activeGraphName.emit((current_title, title))
-
-    def offset_graph(self):
-        """
-        Zoom and offset the graph to the last known settings
-        """
-        for ax in self.axes:
-            if self._scale_xhi is not None and self._scale_xlo is not None:
-                ax.set_xlim(self._scale_xlo, self._scale_xhi)
-            if self._scale_yhi is not None and self._scale_ylo is not None:
-                ax.set_ylim(self._scale_ylo, self._scale_yhi)
-
-    def onDataInfo(self, plot_data):
-        """
-        Displays data info text window for the selected plot
-        """
-        if isinstance(plot_data, Data1D):
-            text_to_show = GuiUtils.retrieveData1d(plot_data)
-        else:
-            text_to_show = GuiUtils.retrieveData2d(plot_data)
-        # Hardcoded sizes to enable full width rendering with default font
-        self.txt_widget.resize(420,600)
-
-        self.txt_widget.setReadOnly(True)
-        self.txt_widget.setWindowFlags(QtCore.Qt.Window)
-        self.txt_widget.setWindowIcon(QtGui.QIcon(":/res/ball.ico"))
-        self.txt_widget.setWindowTitle("Data Info: %s" % plot_data.filename)
-        self.txt_widget.insertPlainText(text_to_show)
-
-        self.txt_widget.show()
-        # Move the slider all the way up, if present
-        vertical_scroll_bar = self.txt_widget.verticalScrollBar()
-        vertical_scroll_bar.triggerAction(QtGui.QScrollBar.SliderToMinimum)
-
-    def onSavePoints(self, plot_data):
-        """
-        Saves plot data to a file
-        """
-        if isinstance(plot_data, Data1D):
-            GuiUtils.saveData1D(plot_data)
-        else:
-            GuiUtils.saveData2D(plot_data)
Index: src/sas/qtgui/Plotting/AddText.py
===================================================================
--- src/sas/qtgui/Plotting/AddText.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/AddText.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,47 @@
+from PyQt4 import QtGui
+
+import sas.sasview
+
+from sas.qtgui.Plotting.UI.AddTextUI import Ui_AddText
+
+class AddText(QtGui.QDialog, Ui_AddText):
+    """ Simple GUI for a single line text query """
+    def __init__(self, parent=None):
+        super(AddText, self).__init__(parent)
+        self.setupUi(self)
+
+        self._font = QtGui.QFont()
+        self._color = "black"
+        self.btnFont.clicked.connect(self.onFontChange)
+        self.btnColor.clicked.connect(self.onColorChange)
+
+    def text(self):
+        return self.textEdit.toPlainText()
+
+    def font(self):
+        return self._font
+
+    def color(self):
+        return self._color
+
+    def onFontChange(self, event):
+        """
+        Pop up the standard Qt Font change dialog
+        """
+        self._font, ok = QtGui.QFontDialog.getFont(parent=self)
+        if ok:
+            self.textEdit.setFont(self._font)
+
+    def onColorChange(self, event):
+        """
+        Pop up the standard Qt color change dialog
+        """
+        # Pick up the chosen color
+        self._color = QtGui.QColorDialog.getColor(parent=self)
+        # Update the text control
+        palette = QtGui.QPalette()
+        palette.setColor(QtGui.QPalette.Text, self._color)
+        self.textEdit.setPalette(palette)
+
+        # Save the color as #RRGGBB
+        self._color = str(self._color.name())
Index: src/sas/qtgui/Plotting/BoxSum.py
===================================================================
--- src/sas/qtgui/Plotting/BoxSum.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/BoxSum.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,42 @@
+"""
+Allows users to modify the box slicer parameters.
+"""
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+
+# Local UI
+from sas.qtgui.Plotting.UI.BoxSumUI import Ui_BoxSumUI
+
+class BoxSum(QtGui.QDialog, Ui_BoxSumUI):
+    apply_signal = QtCore.pyqtSignal(tuple, str)
+    def __init__(self, parent=None, model=None):
+        super(BoxSum, self).__init__()
+
+        self.setupUi(self)
+        assert isinstance(model, QtGui.QStandardItemModel)
+
+        self.txtBoxHeight.setValidator(QtGui.QDoubleValidator())
+        self.txtBoxWidth.setValidator(QtGui.QDoubleValidator())
+        self.txtCenterX.setValidator(QtGui.QDoubleValidator())
+        self.txtCenterY.setValidator(QtGui.QDoubleValidator())
+
+        self.model = model
+        self.mapper = QtGui.QDataWidgetMapper()
+        self.mapper.setModel(self.model)
+
+        # Map model items onto widget controls
+        self.mapper.addMapping(self.txtBoxHeight, 0)
+        self.mapper.addMapping(self.txtBoxWidth, 1)
+        self.mapper.addMapping(self.txtCenterX, 2)
+        self.mapper.addMapping(self.txtCenterY, 3)
+        self.mapper.addMapping(self.lblAvg, 4, "text")
+        self.mapper.addMapping(self.lblAvgErr, 5, "text")
+        self.mapper.addMapping(self.lblSum, 6, "text")
+        self.mapper.addMapping(self.lblSumErr, 7, "text")
+        self.mapper.addMapping(self.lblNumPoints, 8, "text")
+
+        # Populate the widgets with data from the first column
+        self.mapper.toFirst()
+
+        self.setFixedSize(self.minimumSizeHint())
+
Index: src/sas/qtgui/Plotting/ColorMap.py
===================================================================
--- src/sas/qtgui/Plotting/ColorMap.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/ColorMap.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,267 @@
+"""
+Allows users to change the range of the current graph
+"""
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+import sas.qtgui.path_prepare
+
+import matplotlib as mpl
+from matplotlib import pylab
+import numpy
+
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
+from sas.sasgui.guiframe.dataFitting import Data2D
+from sas.qtgui.Utilities.GuiUtils import formatNumber
+from rangeSlider import RangeSlider
+
+DEFAULT_MAP = 'jet'
+
+# Local UI
+from sas.qtgui.Plotting.UI.ColorMapUI import Ui_ColorMapUI
+
+class ColorMap(QtGui.QDialog, Ui_ColorMapUI):
+    apply_signal = QtCore.pyqtSignal(tuple, str)
+    def __init__(self, parent=None, cmap=None, vmin=0.0, vmax=100.0, data=None):
+        super(ColorMap, self).__init__()
+
+        self.setupUi(self)
+        assert(isinstance(data, Data2D))
+
+        self.data = data
+        self._cmap_orig = self._cmap = cmap if cmap is not None else DEFAULT_MAP
+        self.all_maps = [m for m in pylab.cm.datad]
+        self.maps = sorted(m for m in self.all_maps if not m.endswith("_r"))
+        self.rmaps = sorted(set(self.all_maps) - set(self.maps))
+
+        self.vmin = self.vmin_orig = vmin
+        self.vmax = self.vmax_orig = vmax
+
+        # Initialize detector labels
+        self.initDetectorData()
+
+        # Initialize the combo box
+        self.initMapCombobox()
+
+        self.initRangeSlider()
+
+        # Add the color map component
+        self.initColorMap()
+
+        # Initialize validators on amplitude textboxes
+        validator_min = QtGui.QDoubleValidator(self.txtMinAmplitude)
+        validator_min.setNotation(0)
+        self.txtMinAmplitude.setValidator(validator_min)
+        validator_max = QtGui.QDoubleValidator(self.txtMaxAmplitude)
+        validator_max.setNotation(0)
+        self.txtMaxAmplitude.setValidator(validator_max)
+
+        # Set the initial amplitudes
+        self.txtMinAmplitude.setText(formatNumber(self.vmin))
+        self.txtMaxAmplitude.setText(formatNumber(self.vmax))
+
+        # Enforce constant size on the widget
+        self.setFixedSize(self.minimumSizeHint())
+
+        # Handle combobox changes
+        self.cbColorMap.currentIndexChanged.connect(self.onMapIndexChange)
+
+        # Handle checkbox changes
+        self.chkReverse.stateChanged.connect(self.onColorMapReversed)
+
+        # Handle the Reset button click
+        self.buttonBox.button(QtGui.QDialogButtonBox.Reset).clicked.connect(self.onReset)
+
+        # Handle the Apply button click
+        self.buttonBox.button(QtGui.QDialogButtonBox.Apply).clicked.connect(self.onApply)
+
+        # Handle the amplitude setup
+        self.txtMinAmplitude.editingFinished.connect(self.onAmplitudeChange)
+        self.txtMaxAmplitude.editingFinished.connect(self.onAmplitudeChange)
+
+    def cmap(self):
+        """
+        Getter for the color map
+        """
+        return self._cmap
+
+    def norm(self):
+        """
+        Getter for the color map norm
+        """
+        return (self._norm.vmin, self._norm.vmax)
+
+    def onReset(self):
+        """
+        Respond to the Reset button click
+        """
+        # Go back to original settings
+        self._cmap = self._cmap_orig
+        self.vmin = self.vmin_orig
+        self.vmax = self.vmax_orig
+        self._norm = mpl.colors.Normalize(vmin=self.vmin, vmax=self.vmax)
+        self.txtMinAmplitude.setText(formatNumber(self.vmin))
+        self.txtMaxAmplitude.setText(formatNumber(self.vmax))
+        self.initMapCombobox()
+        self.slider.setMinimum(self.vmin)
+        self.slider.setMaximum(self.vmax)
+        self.slider.setLowValue(self.vmin)
+        self.slider.setHighValue(self.vmax)
+        # Redraw the widget
+        self.redrawColorBar()
+        self.canvas.draw()
+
+    def onApply(self):
+        """
+        Respond to the Apply button click.
+        Send a signal to the plotter with vmin/vmax/cmap for chart update
+        """
+        self.apply_signal.emit(self.norm(), self.cmap())
+
+    def initDetectorData(self):
+        """
+        Fill out the Detector labels
+        """
+        xnpts = len(self.data.x_bins)
+        ynpts = len(self.data.y_bins)
+        self.lblWidth.setText(formatNumber(xnpts))
+        self.lblHeight.setText(formatNumber(ynpts))
+        xmax = max(self.data.xmin, self.data.xmax)
+        ymax = max(self.data.ymin, self.data.ymax)
+        qmax = numpy.sqrt(numpy.power(xmax, 2) + numpy.power(ymax, 2))
+        self.lblQmax.setText(formatNumber(qmax))
+        self.lblStopRadius.setText(formatNumber(self.data.xmin))
+
+    def initMapCombobox(self):
+        """
+        Fill out the combo box with all available color maps
+        """
+        if self._cmap in self.rmaps:
+            maps = self.rmaps
+            # Assure correct state of the checkbox
+            self.chkReverse.setChecked(True)
+        else:
+            maps = self.maps
+            # Assure correct state of the checkbox
+            self.chkReverse.setChecked(False)
+
+        self.cbColorMap.addItems(maps)
+        # Set the default/passed map
+        self.cbColorMap.setCurrentIndex(self.cbColorMap.findText(self._cmap))
+
+    def initRangeSlider(self):
+        """
+        Create and display the double slider for data range mapping.
+        """
+        self.slider = RangeSlider()
+        self.slider.setMinimum(self.vmin)
+        self.slider.setMaximum(self.vmax)
+        self.slider.setLowValue(self.vmin)
+        self.slider.setHighValue(self.vmax)
+        self.slider.setOrientation(QtCore.Qt.Horizontal)
+
+        self.slider_label = QtGui.QLabel()
+        self.slider_label.setText("Drag the sliders to adjust color range.")
+
+        def set_vmin(value):
+            self.vmin = value
+            self.txtMinAmplitude.setText(str(value))
+            self.updateMap()
+        def set_vmax(value):
+            self.vmax = value
+            self.txtMaxAmplitude.setText(str(value))
+            self.updateMap()
+
+        self.slider.lowValueChanged.connect(set_vmin)
+        self.slider.highValueChanged.connect(set_vmin)
+
+    def updateMap(self):
+        self._norm = mpl.colors.Normalize(vmin=self.vmin, vmax=self.vmax)
+        self.redrawColorBar()
+        self.canvas.draw()
+
+    def initColorMap(self):
+        """
+        Prepare and display the color map
+        """
+        self.fig = mpl.figure.Figure(figsize=(4, 1))
+        self.ax1 = self.fig.add_axes([0.05, 0.65, 0.9, 0.15])
+
+        self._norm = mpl.colors.Normalize(vmin=self.vmin, vmax=self.vmax)
+        self.redrawColorBar()
+        self.canvas = FigureCanvas(self.fig)
+
+        layout = QtGui.QVBoxLayout()
+        layout.addWidget(self.slider_label)
+        layout.addWidget(self.slider)
+        layout.addWidget(self.canvas)
+
+        self.widget.setLayout(layout)
+
+    def onMapIndexChange(self, index):
+        """
+        Respond to the color map change event
+        """
+        new_map = str(self.cbColorMap.itemText(index))
+        self._cmap = new_map
+        self.redrawColorBar()
+        self.canvas.draw()
+
+    def redrawColorBar(self):
+        """
+        Call ColorbarBase with current values, effectively redrawing the widget
+        """
+        self.cb = mpl.colorbar.ColorbarBase(self.ax1, cmap=self._cmap,
+                                            norm=self._norm,
+                                            orientation='horizontal')
+        self.cb.set_label('Color map range')
+
+    def onColorMapReversed(self, isChecked):
+        """
+        Respond to ticking/unticking the color map reverse checkbox
+        """
+        current_map = str(self.cbColorMap.currentText())
+        if isChecked:
+            # Add "_r" to map name for the reversed version
+            new_map = current_map + "_r"
+            maps = self.rmaps
+            # Assure the reversed map exists.
+            if new_map not in maps:
+                new_map = maps[0]
+        else:
+            new_map = current_map[:-2] # "_r" = last two chars
+            maps = self.maps
+            # Base map for the reversed map should ALWAYS exist,
+            # but let's be paranoid here
+            if new_map not in maps:
+                new_map = maps[0]
+
+        self._cmap = new_map
+        # Clear the content of the combobox.
+        # Needs signal blocking, or else onMapIndexChange() spoils it all
+        self.cbColorMap.blockSignals(True)
+        self.cbColorMap.clear()
+        # Add the new set of maps
+        self.cbColorMap.addItems(maps)
+        # Remove the signal block before the proper index set
+        self.cbColorMap.blockSignals(False)
+        self.cbColorMap.setCurrentIndex(self.cbColorMap.findText(new_map))
+
+    def onAmplitudeChange(self):
+        """
+        Respond to editing the amplitude fields
+        """
+        min_amp = self.vmin
+        max_amp = self.vmax
+
+        try:
+            min_amp = float(self.txtMinAmplitude.text())
+        except ValueError:
+            pass
+        try:
+            max_amp = float(self.txtMaxAmplitude.text())
+        except ValueError:
+            pass
+
+        self._norm = mpl.colors.Normalize(vmin=min_amp, vmax=max_amp)
+        self.redrawColorBar()
+        self.canvas.draw()
Index: src/sas/qtgui/Plotting/LinearFit.py
===================================================================
--- src/sas/qtgui/Plotting/LinearFit.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/LinearFit.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,255 @@
+"""
+Adds a linear fit plot to the chart
+"""
+import re
+import numpy
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+
+#from sas.sasgui.transform import 
+from sas.qtgui.Utilities.GuiUtils import formatNumber
+from sas.sasgui.plottools import fittings
+from sas.sasgui.plottools import transform
+
+from sas.sasgui.plottools.LineModel import LineModel
+
+# Local UI
+from sas.qtgui.Plotting.UI.LinearFitUI import Ui_LinearFitUI
+
+class LinearFit(QtGui.QDialog, Ui_LinearFitUI):
+    def __init__(self, parent=None,
+                 data=None,
+                 max_range=(0.0, 0.0),
+                 fit_range=(0.0, 0.0),
+                 xlabel="",
+                 ylabel=""):
+        super(LinearFit, self).__init__()
+
+        self.setupUi(self)
+        assert(isinstance(max_range, tuple))
+        assert(isinstance(fit_range, tuple))
+
+        self.data = data
+        self.parent = parent
+
+        self.max_range = max_range
+        self.fit_range = fit_range
+        self.xLabel = xlabel
+        self.yLabel = ylabel
+
+        self.x_is_log = self.xLabel == "log10(x)"
+        self.y_is_log = self.yLabel == "log10(y)"
+
+        self.txtFitRangeMin.setValidator(QtGui.QDoubleValidator())
+        self.txtFitRangeMax.setValidator(QtGui.QDoubleValidator())
+
+        # Default values in the line edits
+        self.txtA.setText("1")
+        self.txtB.setText("1")
+        self.txtAerr.setText("0")
+        self.txtBerr.setText("0")
+        self.txtChi2.setText("0")
+
+        # Initial ranges
+        self.txtRangeMin.setText(str(max_range[0]))
+        self.txtRangeMax.setText(str(max_range[1]))
+        self.txtFitRangeMin.setText(str(fit_range[0]))
+        self.txtFitRangeMax.setText(str(fit_range[1]))
+
+        # cast xLabel into html
+        label = re.sub(r'\^\((.)\)(.*)', r'<span style=" vertical-align:super;">\1</span>\2',
+                      str(self.xLabel).rstrip())
+        self.lblRange.setText('Fit range of ' + label)
+
+        self.model = LineModel()
+        # Display the fittings values
+        self.default_A = self.model.getParam('A')
+        self.default_B = self.model.getParam('B')
+        self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
+        self.cstB = fittings.Parameter(self.model, 'B', self.default_B)
+        self.transform = transform
+
+        self.setFixedSize(self.minimumSizeHint())
+
+        # connect Fit button
+        self.cmdFit.clicked.connect(self.fit)
+
+    def setRangeLabel(self, label=""):
+        """
+        Overwrite default fit range label to correspond to actual unit
+        """
+        assert(isinstance(label, basestring))
+        self.lblRange.setText(label)
+
+    def range(self):
+        return (float(self.txtFitRangeMin.text()), float(self.txtFitRangeMax.text()))
+
+    def fit(self, event):
+        """
+        Performs the fit. Receive an event when clicking on
+        the button Fit.Computes chisqr ,
+        A and B parameters of the best linear fit y=Ax +B
+        Push a plottable to the caller
+        """
+        tempx = []
+        tempy = []
+        tempdy = []
+
+        # Checks to assure data correctness
+        if len(self.data.view.x) < 2:
+            return
+        if not self.checkFitValues(self.txtFitRangeMin):
+            return
+
+        self.xminFit, self.xmaxFit = self.range()
+
+        xmin = self.xminFit
+        xmax = self.xmaxFit
+        xminView = xmin
+        xmaxView = xmax
+
+        # Set the qmin and qmax in the panel that matches the
+        # transformed min and max
+        #value_xmin = X_VAL_DICT[self.xLabel].floatTransform(xmin)
+        #value_xmax = X_VAL_DICT[self.xLabel].floatTransform(xmax)
+
+        value_xmin = self.floatInvTransform(xmin)
+        value_xmax = self.floatInvTransform(xmax)
+        self.txtRangeMin.setText(formatNumber(value_xmin))
+        self.txtRangeMax.setText(formatNumber(value_xmax))
+
+        tempx, tempy, tempdy = self.origData()
+
+        # Find the fitting parameters
+        self.cstA = fittings.Parameter(self.model, 'A', self.default_A)
+        self.cstB = fittings.Parameter(self.model, 'B', self.default_B)
+        tempdy = numpy.asarray(tempdy)
+        tempdy[tempdy == 0] = 1
+
+        if self.x_is_log:
+            xmin = numpy.log10(xmin)
+            xmax = numpy.log10(xmax)
+
+        chisqr, out, cov = fittings.sasfit(self.model,
+                                           [self.cstA, self.cstB],
+                                           tempx, tempy, tempdy,
+                                           xmin, xmax)
+        # Use chi2/dof
+        if len(tempx) > 0:
+            chisqr = chisqr / len(tempx)
+
+        # Check that cov and out are iterable before displaying them
+        errA = numpy.sqrt(cov[0][0]) if cov is not None else 0
+        errB = numpy.sqrt(cov[1][1]) if cov is not None else 0
+        cstA = out[0] if out is not None else 0.0
+        cstB = out[1] if out is not None else 0.0
+
+        # Reset model with the right values of A and B
+        self.model.setParam('A', float(cstA))
+        self.model.setParam('B', float(cstB))
+
+        tempx = []
+        tempy = []
+        y_model = 0.0
+
+        # load tempy with the minimum transformation
+        y_model = self.model.run(xmin)
+        tempx.append(xminView)
+        tempy.append(numpy.power(10, y_model) if self.y_is_log else y_model)
+
+        # load tempy with the maximum transformation
+        y_model = self.model.run(xmax)
+        tempx.append(xmaxView)
+        tempy.append(numpy.power(10, y_model) if self.y_is_log else y_model)
+
+        # Set the fit parameter display when  FitDialog is opened again
+        self.Avalue = cstA
+        self.Bvalue = cstB
+        self.ErrAvalue = errA
+        self.ErrBvalue = errB
+        self.Chivalue = chisqr
+
+        # Update the widget
+        self.txtA.setText(formatNumber(self.Avalue))
+        self.txtAerr.setText(formatNumber(self.ErrAvalue))
+        self.txtB.setText(formatNumber(self.Bvalue))
+        self.txtBerr.setText(formatNumber(self.ErrBvalue))
+        self.txtChi2.setText(formatNumber(self.Chivalue))
+
+        #self.parent.updatePlot.emit((tempx, tempy))
+        self.parent.emit(QtCore.SIGNAL('updatePlot'), (tempx, tempy))
+
+    def origData(self):
+        # Store the transformed values of view x, y and dy before the fit
+        xmin_check = numpy.log10(self.xminFit)
+        # Local shortcuts
+        x = self.data.view.x
+        y = self.data.view.y
+        dy = self.data.view.dy
+
+        if self.y_is_log:
+            if self.x_is_log:
+                tempy  = [numpy.log10(y[i])
+                         for i in range(len(x)) if x[i] >= xmin_check]
+                tempdy = [transform.errToLogX(y[i], 0, dy[i], 0)
+                         for i in range(len(x)) if x[i] >= xmin_check]
+            else:
+                tempy = map(numpy.log10, y)
+                tempdy = map(lambda t1,t2:transform.errToLogX(t1,0,t2,0),y,dy)
+        else:
+            tempy = y
+            tempdy = dy
+
+        if self.x_is_log:
+            tempx = [numpy.log10(x) for x in self.data.view.x if x > xmin_check]
+        else:
+            tempx = x
+
+        return tempx, tempy, tempdy
+
+    def checkFitValues(self, item):
+        """
+        Check the validity of input values
+        """
+        flag = True
+        value = item.text()
+        p_white = item.palette()
+        p_white.setColor(item.backgroundRole(), QtCore.Qt.white)
+        p_pink = item.palette()
+        p_pink.setColor(item.backgroundRole(), QtGui.QColor(255, 128, 128))
+        item.setAutoFillBackground(True)
+        # Check for possible values entered
+        if self.x_is_log:
+            if float(value) > 0:
+                item.setPalette(p_white)
+            else:
+                flag = False
+                item.setPalette(p_pink)
+        return flag
+
+    def floatInvTransform(self, x):
+        """
+        transform a float.It is used to determine the x.View min and x.View
+        max for values not in x.  Also used to properly calculate RgQmin,
+        RgQmax and to update qmin and qmax in the linear range boxes on the
+        panel.
+
+        """
+        # TODO: refactor this. This is just a hack to make the
+        # functionality work without rewritting the whole code
+        # with good design (which really should be done...).
+        if self.xLabel == "x":
+            return x
+        elif self.xLabel == "x^(2)":
+            return numpy.sqrt(x)
+        elif self.xLabel == "x^(4)":
+            return numpy.sqrt(numpy.sqrt(x))
+        elif self.xLabel == "log10(x)":
+            return numpy.power(10, x)
+        elif self.xLabel == "ln(x)":
+            return numpy.exp(x)
+        elif self.xLabel == "log10(x^(4))":
+            return numpy.sqrt(numpy.sqrt(numpy.power(10, x)))
+        return x
+
+
Index: src/sas/qtgui/Plotting/MaskEditor.py
===================================================================
--- src/sas/qtgui/Plotting/MaskEditor.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/MaskEditor.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,30 @@
+from PyQt4 import QtGui
+
+from sas.sasgui.guiframe.dataFitting import Data2D
+
+# Local UI
+from sas.qtgui.Plotting.UI.MaskEditorUI import Ui_MaskEditorUI
+from sas.qtgui.Plotting.Plotter2D import Plotter2DWidget
+
+class MaskEditor(QtGui.QDialog, Ui_MaskEditorUI):
+    def __init__(self, parent=None, data=None):
+        super(MaskEditor, self).__init__()
+
+        assert(isinstance(data, Data2D))
+
+        self.setupUi(self)
+
+        self.data = data
+        filename = data.name
+        self.setWindowTitle("Mask Editor for %s" % filename)
+
+        self.plotter = Plotter2DWidget(self, manager=parent, quickplot=True)
+        self.plotter.data = self.data
+
+        layout = QtGui.QHBoxLayout()
+        layout.setContentsMargins(0, 0, 0, 0)
+        self.frame.setLayout(layout)
+        layout.addWidget(self.plotter)
+
+        self.plotter.plot()
+
Index: src/sas/qtgui/Plotting/PlotHelper.py
===================================================================
--- src/sas/qtgui/Plotting/PlotHelper.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/PlotHelper.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,55 @@
+"""
+`Singleton` plot helper module
+All its variables are bound to the module,
+which can not be instantiated repeatedly so IDs are session-specific.
+"""
+import sys
+
+this = sys.modules[__name__]
+
+this._plots = {}
+this._plot_id = 0
+
+def clear():
+    """
+    Reset the plot dictionary
+    """
+    this._plots = {}
+
+def addPlot(plot):
+    """
+    Adds a new plot to the current dictionary of plots
+    """
+    this._plot_id += 1
+    this._plots["Graph%s"%str(this._plot_id)] = plot
+
+def deletePlot(plot_id):
+    """
+    Deletes an existing plot from the dictionary
+    """
+    if plot_id in this._plots:
+        del this._plots[plot_id]
+
+def currentPlots():
+    """
+    Returns a list of IDs for all currently active plots
+    """
+    return this._plots.keys()
+
+def plotById(plot_id):
+    """
+    Returns the plot referenced by the ID
+    """
+    return this._plots[plot_id] if plot_id in this._plots else None
+
+def idOfPlot(plot):
+    """
+    Returns the ID of the plot
+    """
+    plot_id = None
+    for key in this._plots.keys():
+        if this._plots[key] == plot:
+            plot_id = key
+            break
+
+    return plot_id
Index: src/sas/qtgui/Plotting/PlotProperties.py
===================================================================
--- src/sas/qtgui/Plotting/PlotProperties.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/PlotProperties.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,100 @@
+from PyQt4 import QtGui
+
+from sas.qtgui.Plotting.PlotUtilities import COLORS, SHAPES
+
+from sas.qtgui.Plotting.UI.PlotPropertiesUI import Ui_PlotPropertiesUI
+
+class PlotProperties(QtGui.QDialog, Ui_PlotPropertiesUI):
+    """ Dialog for modification of single plot properties """
+    def __init__(self,
+                 parent=None,
+                 color=0,
+                 marker=0,
+                 marker_size=5,
+                 legend=""):
+        super(PlotProperties, self).__init__(parent)
+        self.setupUi(self)
+        self.setFixedSize(self.minimumSizeHint())
+
+        self._parent = parent
+        self._marker = marker if marker else 0
+        self._color = color if color else 0
+        self._legend = legend
+        self._markersize = marker_size if marker_size else 5
+        self.custom_color = False if isinstance(self._color, int) else True
+
+        # Fill out the color combobox
+        self.cbColor.addItems(COLORS.keys()[:-1])
+        # data1d.custom_color can now be a simple integer,
+        # specifying COLORS dict index or a string containing
+        # the hex RGB value, e.g. #00FF00
+        if isinstance(self._color, int):
+            self.cbColor.setCurrentIndex(self._color)
+        else:
+            # Need the Custom entry here. "Custom" is always last.
+            self.cbColor.addItems([COLORS.keys()[-1]])
+            self.cbColor.setCurrentIndex(COLORS.keys().index("Custom"))
+
+        # Fill out the marker combobox
+        self.cbShape.addItems(SHAPES.keys())
+        try:
+            self.cbShape.setCurrentIndex(self._marker)
+        except TypeError:
+            marker_index = self.cbShape.findText(self._marker)
+            self.cbShape.setCurrentIndex(marker_index)
+        if self._legend:
+            self.txtLegend.setText(self._legend)
+        self.sbSize.setValue(self._markersize)
+
+        # Connect slots
+        self.cmdCustom.clicked.connect(self.onColorChange)
+        self.cbColor.currentIndexChanged.connect(self.onColorIndexChange)
+
+    def legend(self):
+        ''' return current legend '''
+        return str(self.txtLegend.text())
+
+    def marker(self):
+        ''' return the current shape index in SHAPE '''
+        return self.cbShape.currentIndex()
+
+    def markersize(self):
+        ''' return marker size (int) '''
+        return self.sbSize.value()
+
+    def color(self):
+        ''' return current color: index in COLORS or a hex string '''
+        if self.custom_color:
+            return self._color
+        else:
+            return self.cbColor.currentIndex()
+
+    def onColorChange(self):
+        """
+        Pop up the standard Qt color change dialog
+        """
+        # Pick up the chosen color
+        proposed_color = QtGui.QColorDialog.getColor(parent=self)
+        # Update the text control
+        if proposed_color.isValid():
+            # Block currentIndexChanged
+            self.cbColor.blockSignals(True)
+            # Add Custom to the color combo box
+            self.cbColor.addItems(["Custom"])
+            self.cbColor.setCurrentIndex(COLORS.keys().index("Custom"))
+            # unblock currentIndexChanged
+            self.cbColor.blockSignals(False)
+            # Save the color as #RRGGBB
+            self.custom_color = True
+            self._color = str(proposed_color.name())
+   
+    def onColorIndexChange(self):
+        """
+        Dynamically add/remove "Custom" color index
+        """
+        # Changed index - assure Custom is deleted
+        custom_index = self.cbColor.findText("Custom")
+        self.custom_color = False
+        if custom_index > -1:
+            self.cbColor.removeItem(custom_index)
+        
Index: src/sas/qtgui/Plotting/PlotUtilities.py
===================================================================
--- src/sas/qtgui/Plotting/PlotUtilities.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/PlotUtilities.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,284 @@
+import sys
+import numpy
+import string
+
+from collections import OrderedDict
+
+# MPL shapes dictionary with some extra styles rendered internally.
+# Ordered for consistent display in combo boxes
+SHAPES = OrderedDict([
+        ('Circle' , 'o'),
+        ('Point' , '.'),
+        ('Pixel' , ','),
+        ('Triangle Down' , 'v'),
+        ('Triangle Up' , '^'),
+        ('Triangle Left' , '<'),
+        ('Triangle Right' , '>'),
+        ('Octagon' , '8'),
+        ('Square' , 's'),
+        ('Pentagon' , 'p'),
+        ('Star' , '*'),
+        ('Hexagon1' , 'h'),
+        ('Hexagon2' , 'H'),
+        ('Cross +' , 'p'),
+        ('Cross X ' , 'x'),
+        ('Diamond' , 'D'),
+        ('Thin Diamond' , 'd'),
+        ('Line' , '-'),
+        ('Dash' , '--'),
+        ('Vline' , 'vline'),
+        ('Step' , 'step'),
+])
+
+# MPL Colors dictionary. Ordered for consistent display
+COLORS = OrderedDict([
+        ('Blue', 'b'),
+        ('Green', 'g'),
+        ('Red', 'r'),
+        ('Cyan', 'c'),
+        ('Magenta', 'm'),
+        ('Yellow', 'y'),
+        ('Black', 'k'),
+        ('Custom', 'x'),
+])
+
+def build_matrix(data, qx_data, qy_data):
+    """
+    Build a matrix for 2d plot from a vector
+    Returns a matrix (image) with ~ square binning
+    Requirement: need 1d array formats of
+    data, qx_data, and qy_data
+    where each one corresponds to z, x, or y axis values
+
+    """
+    # No qx or qy given in a vector format
+    if qx_data is None or qy_data is None \
+            or qx_data.ndim != 1 or qy_data.ndim != 1:
+        return data
+
+    # maximum # of loops to fillup_pixels
+    # otherwise, loop could never stop depending on data
+    max_loop = 1
+    # get the x and y_bin arrays.
+    x_bins, y_bins = get_bins(qx_data, qy_data)
+    # set zero to None
+
+    #Note: Can not use scipy.interpolate.Rbf:
+    # 'cause too many data points (>10000)<=JHC.
+    # 1d array to use for weighting the data point averaging
+    #when they fall into a same bin.
+    weights_data = numpy.ones([data.size])
+    # get histogram of ones w/len(data); this will provide
+    #the weights of data on each bins
+    weights, xedges, yedges = numpy.histogram2d(x=qy_data,
+                                                y=qx_data,
+                                                bins=[y_bins, x_bins],
+                                                weights=weights_data)
+    # get histogram of data, all points into a bin in a way of summing
+    image, xedges, yedges = numpy.histogram2d(x=qy_data,
+                                              y=qx_data,
+                                              bins=[y_bins, x_bins],
+                                              weights=data)
+    # Now, normalize the image by weights only for weights>1:
+    # If weight == 1, there is only one data point in the bin so
+    # that no normalization is required.
+    image[weights > 1] = image[weights > 1] / weights[weights > 1]
+    # Set image bins w/o a data point (weight==0) as None (was set to zero
+    # by histogram2d.)
+    image[weights == 0] = None
+
+    # Fill empty bins with 8 nearest neighbors only when at least
+    #one None point exists
+    loop = 0
+
+    # do while loop until all vacant bins are filled up up
+    #to loop = max_loop
+    while not(numpy.isfinite(image[weights == 0])).all():
+        if loop >= max_loop:  # this protects never-ending loop
+            break
+        image = fillupPixels(image=image, weights=weights)
+        loop += 1
+
+    return image
+
+def get_bins(qx_data, qy_data):
+    """
+    get bins
+    return x_bins and y_bins: 1d arrays of the index with
+    ~ square binning
+    Requirement: need 1d array formats of
+    qx_data, and qy_data
+    where each one corresponds to  x, or y axis values
+    """
+    # No qx or qy given in a vector format
+    if qx_data is None or qy_data is None \
+            or qx_data.ndim != 1 or qy_data.ndim != 1:
+        return data
+
+    # find max and min values of qx and qy
+    xmax = qx_data.max()
+    xmin = qx_data.min()
+    ymax = qy_data.max()
+    ymin = qy_data.min()
+
+    # calculate the range of qx and qy: this way, it is a little
+    # more independent
+    x_size = xmax - xmin
+    y_size = ymax - ymin
+
+    # estimate the # of pixels on each axes
+    npix_y = int(numpy.floor(numpy.sqrt(len(qy_data))))
+    npix_x = int(numpy.floor(len(qy_data) / npix_y))
+
+    # bin size: x- & y-directions
+    xstep = x_size / (npix_x - 1)
+    ystep = y_size / (npix_y - 1)
+
+    # max and min taking account of the bin sizes
+    xmax = xmax + xstep / 2.0
+    xmin = xmin - xstep / 2.0
+    ymax = ymax + ystep / 2.0
+    ymin = ymin - ystep / 2.0
+
+    # store x and y bin centers in q space
+    x_bins = numpy.linspace(xmin, xmax, npix_x)
+    y_bins = numpy.linspace(ymin, ymax, npix_y)
+
+    #set x_bins and y_bins
+    return x_bins, y_bins
+
+def fillupPixels(image=None, weights=None):
+    """
+    Fill z values of the empty cells of 2d image matrix
+    with the average over up-to next nearest neighbor points
+
+    :param image: (2d matrix with some zi = None)
+
+    :return: image (2d array )
+
+    :TODO: Find better way to do for-loop below
+
+    """
+    # No image matrix given
+    if image == None or numpy.ndim(image) != 2 \
+            or numpy.isfinite(image).all() \
+            or weights == None:
+        return image
+    # Get bin size in y and x directions
+    len_y = len(image)
+    len_x = len(image[1])
+    temp_image = numpy.zeros([len_y, len_x])
+    weit = numpy.zeros([len_y, len_x])
+    # do for-loop for all pixels
+    for n_y in range(len(image)):
+        for n_x in range(len(image[1])):
+            # find only null pixels
+            if weights[n_y][n_x] > 0 or numpy.isfinite(image[n_y][n_x]):
+                continue
+            else:
+                # find 4 nearest neighbors
+                # check where or not it is at the corner
+                if n_y != 0 and numpy.isfinite(image[n_y - 1][n_x]):
+                    temp_image[n_y][n_x] += image[n_y - 1][n_x]
+                    weit[n_y][n_x] += 1
+                if n_x != 0 and numpy.isfinite(image[n_y][n_x - 1]):
+                    temp_image[n_y][n_x] += image[n_y][n_x - 1]
+                    weit[n_y][n_x] += 1
+                if n_y != len_y - 1 and numpy.isfinite(image[n_y + 1][n_x]):
+                    temp_image[n_y][n_x] += image[n_y + 1][n_x]
+                    weit[n_y][n_x] += 1
+                if n_x != len_x - 1 and numpy.isfinite(image[n_y][n_x + 1]):
+                    temp_image[n_y][n_x] += image[n_y][n_x + 1]
+                    weit[n_y][n_x] += 1
+                # go 4 next nearest neighbors when no non-zero
+                # neighbor exists
+                if n_y != 0 and n_x != 0 and\
+                        numpy.isfinite(image[n_y - 1][n_x - 1]):
+                    temp_image[n_y][n_x] += image[n_y - 1][n_x - 1]
+                    weit[n_y][n_x] += 1
+                if n_y != len_y - 1 and n_x != 0 and \
+                    numpy.isfinite(image[n_y + 1][n_x - 1]):
+                    temp_image[n_y][n_x] += image[n_y + 1][n_x - 1]
+                    weit[n_y][n_x] += 1
+                if n_y != len_y and n_x != len_x - 1 and \
+                    numpy.isfinite(image[n_y - 1][n_x + 1]):
+                    temp_image[n_y][n_x] += image[n_y - 1][n_x + 1]
+                    weit[n_y][n_x] += 1
+                if n_y != len_y - 1 and n_x != len_x - 1 and \
+                    numpy.isfinite(image[n_y + 1][n_x + 1]):
+                    temp_image[n_y][n_x] += image[n_y + 1][n_x + 1]
+                    weit[n_y][n_x] += 1
+
+    # get it normalized
+    ind = (weit > 0)
+    image[ind] = temp_image[ind] / weit[ind]
+
+    return image
+
+def rescale(lo, hi, step, pt=None, bal=None, scale='linear'):
+    """
+    Rescale (lo,hi) by step, returning the new (lo,hi)
+    The scaling is centered on pt, with positive values of step
+    driving lo/hi away from pt and negative values pulling them in.
+    If bal is given instead of point, it is already in [0,1] coordinates.
+
+    This is a helper function for step-based zooming.
+    """
+    # Convert values into the correct scale for a linear transformation
+    # TODO: use proper scale transformers
+    loprev = lo
+    hiprev = hi
+    if scale == 'log':
+        assert lo > 0
+        if lo > 0:
+            lo = numpy.log10(lo)
+        if hi > 0:
+            hi = numpy.log10(hi)
+        if pt is not None:
+            pt = numpy.log10(pt)
+
+    # Compute delta from axis range * %, or 1-% if persent is negative
+    if step > 0:
+        delta = float(hi - lo) * step / 100
+    else:
+        delta = float(hi - lo) * step / (100 - step)
+
+    # Add scale factor proportionally to the lo and hi values,
+    # preserving the
+    # point under the mouse
+    if bal is None:
+        bal = float(pt - lo) / (hi - lo)
+    lo = lo - (bal * delta)
+    hi = hi + (1 - bal) * delta
+
+    # Convert transformed values back to the original scale
+    if scale == 'log':
+        if (lo <= -250) or (hi >= 250):
+            lo = loprev
+            hi = hiprev
+        else:
+            lo, hi = numpy.power(10., lo), numpy.power(10., hi)
+    return (lo, hi)
+
+def getValidColor(color):
+    '''
+    Returns a valid matplotlib color
+    '''
+
+    if color is None:
+        return color
+
+    # Check if it's an int
+    if isinstance(color, int):
+        # Check if it's within the range
+        if 0 <= color <=6:
+            color = COLORS.values()[color]
+    # Check if it's an RGB string
+    elif isinstance(color, str):
+        # Assure the correctnes of the string
+        assert(color[0]=="#" and len(color) == 7)
+        assert(all(c in string.hexdigits for c in color[1:]))
+    else:
+        raise AttributeError
+
+    return color
Index: src/sas/qtgui/Plotting/Plotter.py
===================================================================
--- src/sas/qtgui/Plotting/Plotter.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/Plotter.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,708 @@
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+import functools
+import copy
+
+import matplotlib.pyplot as plt
+from matplotlib.font_manager import FontProperties
+
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.qtgui.Plotting.PlotterBase import PlotterBase
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+from sas.qtgui.Plotting.AddText import AddText
+from sas.qtgui.Plotting.SetGraphRange import SetGraphRange
+from sas.qtgui.Plotting.LinearFit import LinearFit
+from sas.qtgui.Plotting.PlotProperties import PlotProperties
+import sas.qtgui.Plotting.PlotUtilities as PlotUtilities
+
+class PlotterWidget(PlotterBase):
+    """
+    1D Plot widget for use with a QDialog
+    """
+    def __init__(self, parent=None, manager=None, quickplot=False):
+        super(PlotterWidget, self).__init__(parent, manager=manager, quickplot=quickplot)
+
+        self.parent = parent
+
+        # Dictionary of {plot_id:Data1d}
+        self.plot_dict = {}
+
+        # Window for text add
+        self.addText = AddText(self)
+
+        # Log-ness of the axes
+        self.xLogLabel = "log10(x)"
+        self.yLogLabel = "log10(y)"
+
+        # Data container for the linear fit
+        self.fit_result = Data1D(x=[], y=[], dy=None)
+        self.fit_result.symbol = 13
+        self.fit_result.name = "Fit"
+
+        # Add a slot for receiving update signal from LinearFit
+        # NEW style signals
+        #self.updatePlot = QtCore.pyqtSignal(tuple)
+        # self.updatePlot.connect(self.onFitDisplay)
+        # OLD style signals
+        QtCore.QObject.connect(self, QtCore.SIGNAL('updatePlot'), self.onFitDisplay)
+
+    @property
+    def data(self):
+        return self._data
+
+    @data.setter
+    def data(self, value):
+        """ data setter """
+        self._data = value
+        self.xLabel = "%s(%s)"%(value._xaxis, value._xunit)
+        self.yLabel = "%s(%s)"%(value._yaxis, value._yunit)
+        self.title(title=value.name)
+
+    def plot(self, data=None, color=None, marker=None, hide_error=False):
+        """
+        Add a new plot of self._data to the chart.
+        """
+        # Data1D
+        if isinstance(data, Data1D):
+            self.data = data
+        assert(self._data)
+
+        is_fit = (self.data.id=="fit")
+
+        # Transform data if required.
+        # TODO: it properly!
+        #if data.xtransform is not None or data.ytransform is not None:
+        #    a, b, c, d = GuiUtils.xyTransform(self.data, self.data.xtransform, self.data.ytransform)
+
+        # Shortcuts
+        ax = self.ax
+        x = self._data.view.x
+        y = self._data.view.y
+
+        # Marker symbol. Passed marker is one of matplotlib.markers characters
+        # Alternatively, picked up from Data1D as an int index of PlotUtilities.SHAPES dict
+        if marker is None:
+            marker = self.data.symbol
+            # Try name first
+            try:
+                marker = PlotUtilities.SHAPES[marker]
+            except KeyError:
+                marker = PlotUtilities.SHAPES.values()[marker]
+
+        assert marker is not None
+        # Plot name
+        if self.data.title:
+            self.title(title=self.data.title)
+        else:
+            self.title(title=self.data.name)
+
+        # Error marker toggle
+        if hide_error is None:
+            hide_error = self.data.hide_error
+
+        # Plot color
+        if color is None:
+            color = self.data.custom_color
+
+        color = PlotUtilities.getValidColor(color)
+
+        markersize = self._data.markersize
+
+        # Draw non-standard markers
+        l_width = markersize * 0.4
+        if marker == '-' or marker == '--':
+            line = self.ax.plot(x, y, color=color, lw=l_width, marker='',
+                             linestyle=marker, label=self._title, zorder=10)[0]
+
+        elif marker == 'vline':
+            y_min = min(y)*9.0/10.0 if min(y) < 0 else 0.0
+            line = self.ax.vlines(x=x, ymin=y_min, ymax=y, color=color,
+                            linestyle='-', label=self._title, lw=l_width, zorder=1)
+
+        elif marker == 'step':
+            line = self.ax.step(x, y, color=color, marker='', linestyle='-',
+                                label=self._title, lw=l_width, zorder=1)[0]
+
+        else:
+            # plot data with/without errorbars
+            if hide_error:
+                line = ax.plot(x, y, marker=marker, color=color, markersize=markersize,
+                        linestyle='', label=self._title, picker=True)
+            else:
+                line = ax.errorbar(x, y,
+                            yerr=self._data.view.dy, xerr=None,
+                            capsize=2, linestyle='',
+                            barsabove=False,
+                            color=color,
+                            marker=marker,
+                            markersize=markersize,
+                            lolims=False, uplims=False,
+                            xlolims=False, xuplims=False,
+                            label=self._title,
+                            picker=True)
+
+        # Update the list of data sets (plots) in chart
+        self.plot_dict[self._data.id] = self.data
+
+        # Now add the legend with some customizations.
+        self.legend = ax.legend(loc='upper right', shadow=True)
+        if self.legend:
+            self.legend.set_picker(True)
+
+        # Current labels for axes
+        if self.y_label and not is_fit:
+            ax.set_ylabel(self.y_label)
+        if self.x_label and not is_fit:
+            ax.set_xlabel(self.x_label)
+
+        # Include scaling (log vs. linear)
+        ax.set_xscale(self.xscale)
+        ax.set_yscale(self.yscale)
+
+        # define the ranges
+        self.setRange = SetGraphRange(parent=self,
+            x_range=self.ax.get_xlim(), y_range=self.ax.get_ylim())
+
+        # refresh canvas
+        self.canvas.draw()
+
+    def createContextMenu(self):
+        """
+        Define common context menu and associated actions for the MPL widget
+        """
+        self.defaultContextMenu()
+
+        # Separate plots
+        self.addPlotsToContextMenu()
+
+        # Additional menu items
+        self.contextMenu.addSeparator()
+        self.actionAddText = self.contextMenu.addAction("Add Text")
+        self.actionRemoveText = self.contextMenu.addAction("Remove Text")
+        self.contextMenu.addSeparator()
+        self.actionChangeScale = self.contextMenu.addAction("Change Scale")
+        self.contextMenu.addSeparator()
+        self.actionSetGraphRange = self.contextMenu.addAction("Set Graph Range")
+        self.actionResetGraphRange =\
+            self.contextMenu.addAction("Reset Graph Range")
+        # Add the title change for dialogs
+        #if self.parent:
+        self.contextMenu.addSeparator()
+        self.actionWindowTitle = self.contextMenu.addAction("Window Title")
+
+        # Define the callbacks
+        self.actionAddText.triggered.connect(self.onAddText)
+        self.actionRemoveText.triggered.connect(self.onRemoveText)
+        self.actionChangeScale.triggered.connect(self.onScaleChange)
+        self.actionSetGraphRange.triggered.connect(self.onSetGraphRange)
+        self.actionResetGraphRange.triggered.connect(self.onResetGraphRange)
+        self.actionWindowTitle.triggered.connect(self.onWindowsTitle)
+
+    def addPlotsToContextMenu(self):
+        """
+        Adds operations on all plotted sets of data to the context menu
+        """
+        for id in self.plot_dict.keys():
+            plot = self.plot_dict[id]
+
+            name = plot.name if plot.name else plot.title
+            plot_menu = self.contextMenu.addMenu('&%s' % name)
+
+            self.actionDataInfo = plot_menu.addAction("&DataInfo")
+            self.actionDataInfo.triggered.connect(
+                                functools.partial(self.onDataInfo, plot))
+
+            self.actionSavePointsAsFile = plot_menu.addAction("&Save Points as a File")
+            self.actionSavePointsAsFile.triggered.connect(
+                                functools.partial(self.onSavePoints, plot))
+            plot_menu.addSeparator()
+
+            if plot.id != 'fit':
+                self.actionLinearFit = plot_menu.addAction('&Linear Fit')
+                self.actionLinearFit.triggered.connect(
+                                functools.partial(self.onLinearFit, id))
+                plot_menu.addSeparator()
+
+            self.actionRemovePlot = plot_menu.addAction("Remove")
+            self.actionRemovePlot.triggered.connect(
+                                functools.partial(self.onRemovePlot, id))
+
+            if not plot.is_data:
+                self.actionFreeze = plot_menu.addAction('&Freeze')
+                self.actionFreeze.triggered.connect(
+                                functools.partial(self.onFreeze, id))
+            plot_menu.addSeparator()
+
+            if plot.is_data:
+                self.actionHideError = plot_menu.addAction("Hide Error Bar")
+                if plot.dy is not None and plot.dy != []:
+                    if plot.hide_error:
+                        self.actionHideError.setText('Show Error Bar')
+                else:
+                    self.actionHideError.setEnabled(False)
+                self.actionHideError.triggered.connect(
+                                functools.partial(self.onToggleHideError, id))
+                plot_menu.addSeparator()
+
+            self.actionModifyPlot = plot_menu.addAction('&Modify Plot Property')
+            self.actionModifyPlot.triggered.connect(
+                                functools.partial(self.onModifyPlot, id))
+
+    def createContextMenuQuick(self):
+        """
+        Define context menu and associated actions for the quickplot MPL widget
+        """
+        # Default actions
+        self.defaultContextMenu()
+
+        # Additional actions
+        self.actionToggleGrid = self.contextMenu.addAction("Toggle Grid On/Off")
+        self.contextMenu.addSeparator()
+        self.actionChangeScale = self.contextMenu.addAction("Change Scale")
+
+        # Define the callbacks
+        self.actionToggleGrid.triggered.connect(self.onGridToggle)
+        self.actionChangeScale.triggered.connect(self.onScaleChange)
+
+    def onScaleChange(self):
+        """
+        Show a dialog allowing axes rescaling
+        """
+        if self.properties.exec_() == QtGui.QDialog.Accepted:
+            self.xLogLabel, self.yLogLabel = self.properties.getValues()
+            self.xyTransform(self.xLogLabel, self.yLogLabel)
+
+    def onAddText(self):
+        """
+        Show a dialog allowing adding custom text to the chart
+        """
+        if self.addText.exec_() == QtGui.QDialog.Accepted:
+            # Retrieve the new text, its font and color
+            extra_text = self.addText.text()
+            extra_font = self.addText.font()
+            extra_color = self.addText.color()
+
+            # Place the text on the screen at (0,0)
+            pos_x = self.x_click
+            pos_y = self.y_click
+
+            # Map QFont onto MPL font
+            mpl_font = FontProperties()
+            mpl_font.set_size(int(extra_font.pointSize()))
+            mpl_font.set_family(str(extra_font.family()))
+            mpl_font.set_weight(int(extra_font.weight()))
+            # MPL style names
+            styles = ['normal', 'italic', 'oblique']
+            # QFont::Style maps directly onto the above
+            try:
+                mpl_font.set_style(styles[extra_font.style()])
+            except:
+                pass
+
+            if len(extra_text) > 0:
+                new_text = self.ax.text(str(pos_x),
+                                        str(pos_y),
+                                        extra_text,
+                                        color=extra_color,
+                                        fontproperties=mpl_font)
+                # Update the list of annotations
+                self.textList.append(new_text)
+                self.canvas.draw_idle()
+
+    def onRemoveText(self):
+        """
+        Remove the most recently added text
+        """
+        num_text = len(self.textList)
+        if num_text < 1:
+            return
+        txt = self.textList[num_text - 1]
+        text_remove = txt.get_text()
+        txt.remove()
+        self.textList.remove(txt)
+
+        self.canvas.draw_idle()
+
+    def onSetGraphRange(self):
+        """
+        Show a dialog allowing setting the chart ranges
+        """
+        # min and max of data
+        if self.setRange.exec_() == QtGui.QDialog.Accepted:
+            x_range = self.setRange.xrange()
+            y_range = self.setRange.yrange()
+            if x_range is not None and y_range is not None:
+                self.ax.set_xlim(x_range)
+                self.ax.set_ylim(y_range)
+                self.canvas.draw_idle()
+
+    def onResetGraphRange(self):
+        """
+        Resets the chart X and Y ranges to their original values
+        """
+        x_range = (self.data.x.min(), self.data.x.max())
+        y_range = (self.data.y.min(), self.data.y.max())
+        if x_range is not None and y_range is not None:
+            self.ax.set_xlim(x_range)
+            self.ax.set_ylim(y_range)
+            self.canvas.draw_idle()
+
+    def onLinearFit(self, id):
+        """
+        Creates and displays a simple linear fit for the selected plot
+        """
+        selected_plot = self.plot_dict[id]
+
+        maxrange = (min(selected_plot.x), max(selected_plot.x))
+        fitrange = self.ax.get_xlim()
+
+        fit_dialog = LinearFit(parent=self,
+                    data=selected_plot,
+                    max_range=maxrange,
+                    fit_range=fitrange,
+                    xlabel=self.xLogLabel,
+                    ylabel=self.yLogLabel)
+        if fit_dialog.exec_() == QtGui.QDialog.Accepted:
+            return
+
+    def replacePlot(self, id, new_plot):
+        """
+        Remove plot 'id' and add 'new_plot' to the chart.
+        This effectlvely refreshes the chart with changes to one of its plots
+        """
+        self.removePlot(id)
+        self.plot(data=new_plot)
+
+    def onRemovePlot(self, id):
+        """
+        Responds to the plot delete action
+        """
+        self.removePlot(id)
+
+        if len(self.plot_dict) == 0:
+            # last plot: graph is empty must be the panel must be destroyed
+                self.parent.close()
+
+    def removePlot(self, id):
+        """
+        Deletes the selected plot from the chart
+        """
+        if id not in self.plot_dict:
+            return
+
+        selected_plot = self.plot_dict[id]
+
+        plot_dict = copy.deepcopy(self.plot_dict)
+
+        # Labels might have been changed
+        xl = self.ax.xaxis.label.get_text()
+        yl = self.ax.yaxis.label.get_text()
+
+        self.plot_dict = {}
+
+        plt.cla()
+        self.ax.cla()
+
+        for ids in plot_dict:
+            if ids != id:
+                self.plot(data=plot_dict[ids], hide_error=plot_dict[ids].hide_error)
+
+        # Reset the labels
+        self.ax.set_xlabel(xl)
+        self.ax.set_ylabel(yl)
+        self.canvas.draw()
+
+    def onFreeze(self, id):
+        """
+        Freezes the selected plot to a separate chart
+        """
+        plot = self.plot_dict[id]
+        self.manager.add_data(data_list=[plot])
+
+    def onModifyPlot(self, id):
+        """
+        Allows for MPL modifications to the selected plot
+        """
+        selected_plot = self.plot_dict[id]
+
+        # Old style color - single integer for enum color
+        # New style color - #hhhhhh
+        color = selected_plot.custom_color
+        # marker symbol and size
+        marker = selected_plot.symbol
+        marker_size = selected_plot.markersize
+        # plot name
+        legend = selected_plot.title
+
+        plotPropertiesWidget = PlotProperties(self,
+                                color=color,
+                                marker=marker,
+                                marker_size=marker_size,
+                                legend=legend)
+        if plotPropertiesWidget.exec_() == QtGui.QDialog.Accepted:
+            # Update Data1d
+            selected_plot.markersize = plotPropertiesWidget.markersize()
+            selected_plot.custom_color = plotPropertiesWidget.color()
+            selected_plot.symbol = plotPropertiesWidget.marker()
+            selected_plot.title = plotPropertiesWidget.legend()
+
+            # Redraw the plot
+            self.replacePlot(id, selected_plot)
+
+    def onToggleHideError(self, id):
+        """
+        Toggles hide error/show error menu item
+        """
+        selected_plot = self.plot_dict[id]
+        current = selected_plot.hide_error
+
+        # Flip the flag
+        selected_plot.hide_error = not current
+
+        plot_dict = copy.deepcopy(self.plot_dict)
+        self.plot_dict = {}
+
+        # Clean the canvas
+        plt.cla()
+        self.ax.cla()
+
+        # Recreate the plots but reverse the error flag for the current
+        for ids in plot_dict:
+            if ids == id:
+                self.plot(data=plot_dict[ids], hide_error=(not current))
+            else:
+                self.plot(data=plot_dict[ids], hide_error=plot_dict[ids].hide_error)                
+
+    def xyTransform(self, xLabel="", yLabel=""):
+        """
+        Transforms x and y in View and set the scale
+        """
+        # Transform all the plots on the chart
+        for id in self.plot_dict.keys():
+            current_plot = self.plot_dict[id]
+            if current_plot.id == "fit":
+                self.removePlot(id)
+                continue
+
+            new_xlabel, new_ylabel, xscale, yscale =\
+                GuiUtils.xyTransform(current_plot, xLabel, yLabel)
+            self.xscale = xscale
+            self.yscale = yscale
+
+            # Plot the updated chart
+            self.removePlot(id)
+
+            # This assignment will wrap the label in Latex "$"
+            self.xLabel = new_xlabel
+            self.yLabel = new_ylabel
+            # Directly overwrite the data to avoid label reassignment
+            self._data = current_plot
+            self.plot()
+
+        pass # debug hook
+
+    def onFitDisplay(self, fit_data):
+        """
+        Add a linear fitting line to the chart
+        """
+        # Create new data structure with fitting result
+        tempx = fit_data[0]
+        tempy = fit_data[1]
+        self.fit_result.x = []
+        self.fit_result.y = []
+        self.fit_result.x = tempx
+        self.fit_result.y = tempy
+        self.fit_result.dx = None
+        self.fit_result.dy = None
+
+        #Remove another Fit, if exists
+        self.removePlot("fit")
+
+        self.fit_result.reset_view()
+        #self.offset_graph()
+
+        # Set plot properties
+        self.fit_result.id = 'fit'
+        self.fit_result.title = 'Fit'
+        self.fit_result.name = 'Fit'
+
+        # Plot the line
+        self.plot(data=self.fit_result, marker='-', hide_error=True)
+
+    def onMplMouseDown(self, event):
+        """
+        Left button down and ready to drag
+        """
+        # Check that the LEFT button was pressed
+        if event.button != 1:
+            return
+
+        self.leftdown = True
+        for text in self.textList:
+            if text.contains(event)[0]: # If user has clicked on text
+                self.selectedText = text
+                return
+        if event.inaxes is None:
+            return
+        try:
+            self.x_click = float(event.xdata)  # / size_x
+            self.y_click = float(event.ydata)  # / size_y
+        except:
+            self.position = None
+
+    def onMplMouseUp(self, event):
+        """
+        Set the data coordinates of the click
+        """
+        self.x_click = event.xdata
+        self.y_click = event.ydata
+
+        # Check that the LEFT button was released
+        if event.button == 1:
+            self.leftdown = False
+            self.selectedText = None
+
+        #release the legend
+        if self.gotLegend == 1:
+            self.gotLegend = 0
+
+    def onMplMouseMotion(self, event):
+        """
+        Check if the left button is press and the mouse in moving.
+        Compute delta for x and y coordinates and then perform the drag
+        """
+        if self.gotLegend == 1 and self.leftdown:
+            self.onLegendMotion(event)
+            return
+
+        #if self.leftdown and self.selectedText is not None:
+        if not self.leftdown or self.selectedText is None:
+            return
+        # User has clicked on text and is dragging
+        if event.inaxes is None:
+            # User has dragged outside of axes
+            self.selectedText = None
+        else:
+            # Only move text if mouse is within axes
+            self.selectedText.set_position((event.xdata, event.ydata))
+            self.canvas.draw_idle()
+        return
+
+    def onMplPick(self, event):
+        """
+        On pick legend
+        """
+        legend = self.legend
+        if event.artist != legend:
+            return
+        # Get the box of the legend.
+        bbox = self.legend.get_window_extent()
+        # Get mouse coordinates at time of pick.
+        self.mouse_x = event.mouseevent.x
+        self.mouse_y = event.mouseevent.y
+        # Get legend coordinates at time of pick.
+        self.legend_x = bbox.xmin
+        self.legend_y = bbox.ymin
+        # Indicate we picked up the legend.
+        self.gotLegend = 1
+
+        #self.legend.legendPatch.set_alpha(0.5)
+
+    def onLegendMotion(self, event):
+        """
+        On legend in motion
+        """
+        ax = event.inaxes
+        if ax == None:
+            return
+        # Event occurred inside a plotting area
+        lo_x, hi_x = ax.get_xlim()
+        lo_y, hi_y = ax.get_ylim()
+        # How much the mouse moved.
+        x = mouse_diff_x = self.mouse_x - event.x
+        y = mouse_diff_y = self.mouse_y - event.y
+        # Put back inside
+        if x < lo_x:
+            x = lo_x
+        if x > hi_x:
+            x = hi_x
+        if y < lo_y:
+            y = lo_y
+        if y > hi_y:
+            y = hi_y
+        # Move the legend from its previous location by that same amount
+        loc_in_canvas = self.legend_x - mouse_diff_x, \
+                        self.legend_y - mouse_diff_y
+        # Transform into legend coordinate system
+        trans_axes = self.legend.parent.transAxes.inverted()
+        loc_in_norm_axes = trans_axes.transform_point(loc_in_canvas)
+        self.legend_pos_loc = tuple(loc_in_norm_axes)
+        self.legend._loc = self.legend_pos_loc
+        # self.canvas.draw()
+        self.canvas.draw_idle()
+
+    def onMplWheel(self, event):
+        """
+        Process mouse wheel as zoom events
+        """
+        ax = event.inaxes
+        step = event.step
+
+        if ax != None:
+            # Event occurred inside a plotting area
+            lo, hi = ax.get_xlim()
+            lo, hi = PlotUtilities.rescale(lo, hi, step,
+                              pt=event.xdata, scale=ax.get_xscale())
+            if not self.xscale == 'log' or lo > 0:
+                self._scale_xlo = lo
+                self._scale_xhi = hi
+                ax.set_xlim((lo, hi))
+
+            lo, hi = ax.get_ylim()
+            lo, hi = PlotUtilities.rescale(lo, hi, step, pt=event.ydata,
+                              scale=ax.get_yscale())
+            if not self.yscale == 'log' or lo > 0:
+                self._scale_ylo = lo
+                self._scale_yhi = hi
+                ax.set_ylim((lo, hi))
+        else:
+            # Check if zoom happens in the axes
+            xdata, ydata = None, None
+            x, y = event.x, event.y
+
+            for ax in self.axes:
+                insidex, _ = ax.xaxis.contains(event)
+                if insidex:
+                    xdata, _ = ax.transAxes.inverted().transform_point((x, y))
+                insidey, _ = ax.yaxis.contains(event)
+                if insidey:
+                    _, ydata = ax.transAxes.inverted().transform_point((x, y))
+            if xdata is not None:
+                lo, hi = ax.get_xlim()
+                lo, hi = PlotUtilities.rescale(lo, hi, step,
+                                  bal=xdata, scale=ax.get_xscale())
+                if not self.xscale == 'log' or lo > 0:
+                    self._scale_xlo = lo
+                    self._scale_xhi = hi
+                    ax.set_xlim((lo, hi))
+            if ydata is not None:
+                lo, hi = ax.get_ylim()
+                lo, hi = PlotUtilities.rescale(lo, hi, step, bal=ydata,
+                                  scale=ax.get_yscale())
+                if not self.yscale == 'log' or lo > 0:
+                    self._scale_ylo = lo
+                    self._scale_yhi = hi
+                    ax.set_ylim((lo, hi))
+        self.canvas.draw_idle()
+
+
+class Plotter(QtGui.QDialog, PlotterWidget):
+    def __init__(self, parent=None, quickplot=False):
+
+        QtGui.QDialog.__init__(self)
+        PlotterWidget.__init__(self, parent=self, manager=parent, quickplot=quickplot)
+        icon = QtGui.QIcon()
+        icon.addPixmap(QtGui.QPixmap(":/res/ball.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        self.setWindowIcon(icon)
+
+
Index: src/sas/qtgui/Plotting/Plotter2D.py
===================================================================
--- src/sas/qtgui/Plotting/Plotter2D.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/Plotter2D.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,506 @@
+import copy
+import numpy
+import pylab
+import functools
+
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+
+DEFAULT_CMAP = pylab.cm.jet
+from mpl_toolkits.mplot3d import Axes3D
+
+import sas.qtgui.Plotting.PlotUtilities as PlotUtilities
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+from sas.qtgui.Plotting.PlotterBase import PlotterBase
+from sas.qtgui.Plotting.ColorMap import ColorMap
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+from sas.sascalc.dataloader.manipulations import CircularAverage
+from sas.sasgui.guiframe.local_perspectives.plotting.binder import BindArtist
+from sas.qtgui.Plotting.BoxSum import BoxSum
+from sas.qtgui.Plotting.SlicerParameters import SlicerParameters
+from sas.sasgui.guiframe.local_perspectives.plotting.boxSlicer import BoxInteractorX
+from sas.sasgui.guiframe.local_perspectives.plotting.AnnulusSlicer import AnnulusInteractor
+from sas.sasgui.guiframe.local_perspectives.plotting.SectorSlicer import SectorInteractor
+from sas.sasgui.guiframe.local_perspectives.plotting.boxSum import BoxSumCalculator
+from sas.sasgui.guiframe.local_perspectives.plotting.boxSlicer import BoxInteractorY
+
+# Minimum value of Z for which we will present data.
+MIN_Z = -32
+
+class Plotter2DWidget(PlotterBase):
+    """
+    2D Plot widget for use with a QDialog
+    """
+    def __init__(self, parent=None, manager=None, quickplot=False, dimension=2):
+        self.dimension = dimension
+        super(Plotter2DWidget, self).__init__(parent, manager=manager, quickplot=quickplot)
+
+        self.cmap = DEFAULT_CMAP.name
+        # Default scale
+        self.scale = 'log_{10}'
+        # to set the order of lines drawn first.
+        self.slicer_z = 5
+        # Reference to the current slicer
+        self.slicer = None
+        self.slicer_widget = None
+        # Create Artist and bind it
+        self.connect = BindArtist(self.figure)
+        self.vmin = None
+        self.vmax = None
+
+        self.manager = manager
+
+    @property
+    def data(self):
+        return self._data
+
+    @data.setter
+    def data(self, data=None):
+        """ data setter """
+        self._data = data
+        self.qx_data = data.qx_data
+        self.qy_data = data.qy_data
+        self.xmin = data.xmin
+        self.xmax = data.xmax
+        self.ymin = data.ymin
+        self.ymax = data.ymax
+        self.zmin = data.zmin
+        self.zmax = data.zmax
+        self.label = data.name
+        self.xLabel = "%s(%s)"%(data._xaxis, data._xunit)
+        self.yLabel = "%s(%s)"%(data._yaxis, data._yunit)
+        self.title(title=data.title)
+
+    @property
+    def item(self):
+        ''' getter for this plot's QStandardItem '''
+        return self._item
+
+    @item.setter
+    def item(self, item=None):
+        ''' setter for this plot's QStandardItem '''
+        self._item = item
+
+    def plot(self, data=None, marker=None):
+        """
+        Plot 2D self._data
+        marker - unused
+        """
+        # Assing data
+        if isinstance(data, Data2D):
+            self.data = data
+
+        assert self._data
+
+        # Toggle the scale
+        zmin_2D_temp, zmax_2D_temp = self.calculateDepth()
+
+        # Prepare and show the plot
+        self.showPlot(data=self.data.data,
+                      qx_data=self.qx_data,
+                      qy_data=self.qy_data,
+                      xmin=self.xmin,
+                      xmax=self.xmax,
+                      ymin=self.ymin, ymax=self.ymax,
+                      cmap=self.cmap, zmin=zmin_2D_temp,
+                      zmax=zmax_2D_temp)
+
+    def calculateDepth(self):
+        """
+        Re-calculate the plot depth parameters depending on the scale
+        """
+        # Toggle the scale
+        zmin_temp = self.zmin
+        zmax_temp = self.zmax
+        # self.scale predefined in the baseclass
+        if self.scale == 'log_{10}':
+            if self.zmin is not None:
+                zmin_temp = numpy.power(10, self.zmin)
+            if self.zmax is not None:
+                zmax_temp = numpy.power(10, self.zmax)
+        else:
+            if self.zmin is not None:
+                # min log value: no log(negative)
+                zmin_temp = MIN_Z if self.zmin <= 0 else numpy.log10(self.zmin)
+            if self.zmax is not None:
+                zmax_temp = numpy.log10(self.zmax)
+
+        return (zmin_temp, zmax_temp)
+
+
+    def createContextMenu(self):
+        """
+        Define common context menu and associated actions for the MPL widget
+        """
+        self.defaultContextMenu()
+
+        self.contextMenu.addSeparator()
+        self.actionDataInfo = self.contextMenu.addAction("&DataInfo")
+        self.actionDataInfo.triggered.connect(
+             functools.partial(self.onDataInfo, self.data))
+
+        self.actionSavePointsAsFile = self.contextMenu.addAction("&Save Points as a File")
+        self.actionSavePointsAsFile.triggered.connect(
+             functools.partial(self.onSavePoints, self.data))
+        self.contextMenu.addSeparator()
+
+        self.actionCircularAverage = self.contextMenu.addAction("&Perform Circular Average")
+        self.actionCircularAverage.triggered.connect(self.onCircularAverage)
+
+        self.actionSectorView = self.contextMenu.addAction("&Sector [Q View]")
+        self.actionSectorView.triggered.connect(self.onSectorView)
+        self.actionAnnulusView = self.contextMenu.addAction("&Annulus [Phi View]")
+        self.actionAnnulusView.triggered.connect(self.onAnnulusView)
+        self.actionBoxSum = self.contextMenu.addAction("&Box Sum")
+        self.actionBoxSum.triggered.connect(self.onBoxSum)
+        self.actionBoxAveragingX = self.contextMenu.addAction("&Box Averaging in Qx")
+        self.actionBoxAveragingX.triggered.connect(self.onBoxAveragingX)
+        self.actionBoxAveragingY = self.contextMenu.addAction("&Box Averaging in Qy")
+        self.actionBoxAveragingY.triggered.connect(self.onBoxAveragingY)
+        # Additional items for slicer interaction
+        if self.slicer:
+            self.actionClearSlicer = self.contextMenu.addAction("&Clear Slicer")
+            self.actionClearSlicer.triggered.connect(self.onClearSlicer)
+            if self.slicer.__class__.__name__ != "BoxSumCalculator":
+                self.actionEditSlicer = self.contextMenu.addAction("&Edit Slicer Parameters")
+                self.actionEditSlicer.triggered.connect(self.onEditSlicer)
+        self.contextMenu.addSeparator()
+        self.actionColorMap = self.contextMenu.addAction("&2D Color Map")
+        self.actionColorMap.triggered.connect(self.onColorMap)
+        self.contextMenu.addSeparator()
+        self.actionChangeScale = self.contextMenu.addAction("Toggle Linear/Log Scale")
+        self.actionChangeScale.triggered.connect(self.onToggleScale)
+
+    def createContextMenuQuick(self):
+        """
+        Define context menu and associated actions for the quickplot MPL widget
+        """
+        self.defaultContextMenu()
+
+        if self.dimension == 2:
+            self.actionToggleGrid = self.contextMenu.addAction("Toggle Grid On/Off")
+            self.contextMenu.addSeparator()
+        self.actionChangeScale = self.contextMenu.addAction("Toggle Linear/Log Scale")
+
+        # Define the callbacks
+        self.actionChangeScale.triggered.connect(self.onToggleScale)
+        if self.dimension == 2:
+            self.actionToggleGrid.triggered.connect(self.onGridToggle)
+
+    def onToggleScale(self, event):
+        """
+        Toggle axis and replot image
+        """
+        # self.scale predefined in the baseclass
+        if self.scale == 'log_{10}':
+            self.scale = 'linear'
+        else:
+            self.scale = 'log_{10}'
+
+        self.plot()
+
+    def onClearSlicer(self):
+        """
+        Remove all sclicers from the chart
+        """
+        if self.slicer is None:
+            return
+
+        self.slicer.clear()
+        self.canvas.draw()
+        self.slicer = None
+
+    def onEditSlicer(self):
+        """
+        Present a small dialog for manipulating the current slicer
+        """
+        assert self.slicer
+        # Only show the dialog if not currently shown
+        if self.slicer_widget:
+            return
+        def slicer_closed():
+            # Need to disconnect the signal!!
+            self.slicer_widget.close_signal.disconnect()
+            # reset slicer_widget on "Edit Slicer Parameters" window close
+            self.slicer_widget = None
+
+        self.param_model = self.slicer.model()
+        # Pass the model to the Slicer Parameters widget
+        self.slicer_widget = SlicerParameters(model=self.param_model,
+                                              validate_method=self.slicer.validate)
+        self.slicer_widget.close_signal.connect(slicer_closed)
+        # Add the plot to the workspace
+        self.manager.parent.workspace().addWindow(self.slicer_widget)
+
+        self.slicer_widget.show()
+
+    def onCircularAverage(self):
+        """
+        Perform circular averaging on Data2D
+        """
+        # Find the best number of bins
+        npt = numpy.sqrt(len(self.data.data[numpy.isfinite(self.data.data)]))
+        npt = numpy.floor(npt)
+        # compute the maximum radius of data2D
+        self.qmax = max(numpy.fabs(self.data.xmax),
+                        numpy.fabs(self.data.xmin))
+        self.ymax = max(numpy.fabs(self.data.ymax),
+                        numpy.fabs(self.data.ymin))
+        self.radius = numpy.sqrt(numpy.power(self.qmax, 2) + numpy.power(self.ymax, 2))
+        #Compute beam width
+        bin_width = (self.qmax + self.qmax) / npt
+        # Create data1D circular average of data2D
+        circle = CircularAverage(r_min=0, r_max=self.radius, bin_width=bin_width)
+        circ = circle(self.data)
+        dxl = circ.dxl if hasattr(circ, "dxl") else None
+        dxw = circ.dxw if hasattr(circ, "dxw") else None
+
+        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
+        new_plot.dxl = dxl
+        new_plot.dxw = dxw
+        new_plot.name = new_plot.title = "Circ avg " + self.data.name
+        new_plot.source = self.data.source
+        new_plot.interactive = True
+        new_plot.detector = self.data.detector
+
+        # Define axes if not done yet.
+        new_plot.xaxis("\\rm{Q}", "A^{-1}")
+        if hasattr(self.data, "scale") and \
+                    self.data.scale == 'linear':
+            new_plot.ytransform = 'y'
+            new_plot.yaxis("\\rm{Residuals} ", "normalized")
+        else:
+            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
+
+        new_plot.group_id = "2daverage" + self.data.name
+        new_plot.id = "Circ avg " + self.data.name
+        new_plot.is_data = True
+        variant_plot = QtCore.QVariant(new_plot)
+        GuiUtils.updateModelItemWithPlot(self._item, variant_plot, new_plot.id)
+        self.manager.communicator.plotUpdateSignal.emit([new_plot])
+
+    def setSlicer(self, slicer):
+        """
+        Clear the previous slicer and create a new one.
+        slicer: slicer class to create
+        """
+        # Clear current slicer
+        if self.slicer is not None:
+            self.slicer.clear()
+        # Create a new slicer
+        self.slicer_z += 1
+        self.slicer = slicer(self, self.ax, item=self._item, zorder=self.slicer_z)
+        self.ax.set_ylim(self.data.ymin, self.data.ymax)
+        self.ax.set_xlim(self.data.xmin, self.data.xmax)
+        # Draw slicer
+        self.figure.canvas.draw()
+        self.slicer.update()
+
+        # Reset the model on the Edit slicer parameters widget
+        self.param_model = self.slicer.model()
+        if self.slicer_widget:
+            self.slicer_widget.setModel(self.param_model)
+
+    def onSectorView(self):
+        """
+        Perform sector averaging on Q and draw sector slicer
+        """
+        self.setSlicer(slicer=SectorInteractor)
+
+    def onAnnulusView(self):
+        """
+        Perform sector averaging on Phi and draw annulus slicer
+        """
+        self.setSlicer(slicer=AnnulusInteractor)
+
+    def onBoxSum(self):
+        """
+        Perform 2D Data averaging Qx and Qy.
+        Display box slicer details.
+        """
+        self.onClearSlicer()
+        self.slicer_z += 1
+        self.slicer = BoxSumCalculator(self, self.ax, zorder=self.slicer_z)
+
+        self.ax.set_ylim(self.data.ymin, self.data.ymax)
+        self.ax.set_xlim(self.data.xmin, self.data.xmax)
+        self.figure.canvas.draw()
+        self.slicer.update()
+
+        # Get the BoxSumCalculator model.
+        self.box_sum_model = self.slicer.model()
+        # Pass the BoxSumCalculator model to the BoxSum widget
+        self.boxwidget = BoxSum(self, model=self.box_sum_model)
+        # Add the plot to the workspace
+        self.manager.parent.workspace().addWindow(self.boxwidget)
+        self.boxwidget.show()
+
+    def onBoxAveragingX(self):
+        """
+        Perform 2D data averaging on Qx
+        Create a new slicer.
+        """
+        self.setSlicer(slicer=BoxInteractorX)
+
+    def onBoxAveragingY(self):
+        """
+        Perform 2D data averaging on Qy
+        Create a new slicer .
+        """
+        self.setSlicer(slicer=BoxInteractorY)
+
+    def onColorMap(self):
+        """
+        Display the color map dialog and modify the plot's map accordingly
+        """
+        color_map_dialog = ColorMap(self, cmap=self.cmap,
+                                    vmin=self.vmin,
+                                    vmax=self.vmax,
+                                    data=self.data)
+
+        color_map_dialog.apply_signal.connect(self.onApplyMap)
+
+        if color_map_dialog.exec_() == QtGui.QDialog.Accepted:
+            self.onApplyMap(color_map_dialog.norm(), color_map_dialog.cmap())
+
+    def onApplyMap(self, v_values, cmap):
+        """
+        Update the chart color map based on data passed from the widget
+        """
+        self.cmap = str(cmap)
+        self.vmin, self.vmax = v_values
+        # Redraw the chart with new cmap
+        self.plot()
+
+    def showPlot(self, data, qx_data, qy_data, xmin, xmax, ymin, ymax,
+                 zmin, zmax, label='data2D', cmap=DEFAULT_CMAP):
+        """
+        Render and show the current data
+        """
+        self.qx_data = qx_data
+        self.qy_data = qy_data
+        self.xmin = xmin
+        self.xmax = xmax
+        self.ymin = ymin
+        self.ymax = ymax
+        self.zmin = zmin
+        self.zmax = zmax
+        # If we don't have any data, skip.
+        if data is None:
+            return
+        if data.ndim == 1:
+            output = PlotUtilities.build_matrix(data, self.qx_data, self.qy_data)
+        else:
+            output = copy.deepcopy(data)
+
+        zmin_temp = self.zmin
+        # check scale
+        if self.scale == 'log_{10}':
+            try:
+                if  self.zmin <= 0  and len(output[output > 0]) > 0:
+                    zmin_temp = self.zmin
+                    output[output > 0] = numpy.log10(output[output > 0])
+                elif self.zmin <= 0:
+                    zmin_temp = self.zmin
+                    output[output > 0] = numpy.zeros(len(output))
+                    output[output <= 0] = MIN_Z
+                else:
+                    zmin_temp = self.zmin
+                    output[output > 0] = numpy.log10(output[output > 0])
+            except:
+                #Too many problems in 2D plot with scale
+                output[output > 0] = numpy.log10(output[output > 0])
+                pass
+
+        self.cmap = cmap
+        if self.dimension != 3:
+            #Re-adjust colorbar
+            self.figure.subplots_adjust(left=0.2, right=.8, bottom=.2)
+
+            zmax_temp = self.zmax
+            if self.vmin is not None:
+                zmin_temp = self.vmin
+                zmax_temp = self.vmax
+
+            im = self.ax.imshow(output, interpolation='nearest',
+                                origin='lower',
+                                vmin=zmin_temp, vmax=zmax_temp,
+                                cmap=self.cmap,
+                                extent=(self.xmin, self.xmax,
+                                        self.ymin, self.ymax))
+
+            cbax = self.figure.add_axes([0.84, 0.2, 0.02, 0.7])
+
+            # Current labels for axes
+            self.ax.set_ylabel(self.y_label)
+            self.ax.set_xlabel(self.x_label)
+
+            # Title only for regular charts
+            if not self.quickplot:
+                self.ax.set_title(label=self._title)
+
+            if cbax is None:
+                ax.set_frame_on(False)
+                cb = self.figure.colorbar(im, shrink=0.8, aspect=20)
+            else:
+                cb = self.figure.colorbar(im, cax=cbax)
+
+            cb.update_bruteforce(im)
+            cb.set_label('$' + self.scale + '$')
+
+            self.vmin = cb.vmin
+            self.vmax = cb.vmax
+
+        else:
+            # clear the previous 2D from memory
+            self.figure.clear()
+
+            self.figure.subplots_adjust(left=0.1, right=.8, bottom=.1)
+
+            data_x, data_y = numpy.meshgrid(self._data.x_bins[0:-1],
+                                            self._data.y_bins[0:-1])
+
+            ax = Axes3D(self.figure)
+
+            # Disable rotation for large sets.
+            # TODO: Define "large" for a dataset
+            SET_TOO_LARGE = 500
+            if len(data_x) > SET_TOO_LARGE:
+                ax.disable_mouse_rotation()
+
+            self.figure.canvas.resizing = False
+            im = ax.plot_surface(data_x, data_y, output, rstride=1,
+                                 cstride=1, cmap=cmap,
+                                 linewidth=0, antialiased=False)
+            self.ax.set_axis_off()
+
+        if self.dimension != 3:
+            self.figure.canvas.draw_idle()
+        else:
+            self.figure.canvas.draw()
+
+    def update(self):
+        self.figure.canvas.draw()
+
+    def draw(self):
+        self.figure.canvas.draw()
+
+    def replacePlot(self, id, new_plot):
+        """
+        Replace data in current chart.
+        This effectlvely refreshes the chart with changes to one of its plots
+        """
+        self.plot(data=new_plot)
+
+
+class Plotter2D(QtGui.QDialog, Plotter2DWidget):
+    """
+    Plotter widget implementation
+    """
+    def __init__(self, parent=None, quickplot=False, dimension=2):
+        QtGui.QDialog.__init__(self)
+        Plotter2DWidget.__init__(self, manager=parent, quickplot=quickplot, dimension=dimension)
+        icon = QtGui.QIcon()
+        icon.addPixmap(QtGui.QPixmap(":/res/ball.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        self.setWindowIcon(icon)
Index: src/sas/qtgui/Plotting/PlotterBase.py
===================================================================
--- src/sas/qtgui/Plotting/PlotterBase.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/PlotterBase.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,377 @@
+import pylab
+import numpy
+
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+
+# TODO: Replace the qt4agg calls below with qt5 equivalent.
+# Requires some code modifications.
+# https://www.boxcontrol.net/embedding-matplotlib-plot-on-pyqt5-gui.html
+#
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
+from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
+
+import matplotlib.pyplot as plt
+
+DEFAULT_CMAP = pylab.cm.jet
+from sas.sasgui.plottools.binder import BindArtist
+
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+from sas.sasgui.guiframe.dataFitting import Data1D, Data2D
+from sas.qtgui.Plotting.ScaleProperties import ScaleProperties
+from sas.qtgui.Plotting.WindowTitle import WindowTitle
+import sas.qtgui.Plotting.PlotHelper as PlotHelper
+import sas.qtgui.Plotting.PlotUtilities as PlotUtilities
+
+class PlotterBase(QtGui.QWidget):
+    def __init__(self, parent=None, manager=None, quickplot=False):
+        super(PlotterBase, self).__init__(parent)
+
+        # Required for the communicator
+        self.manager = manager
+        self.quickplot = quickplot
+
+        # a figure instance to plot on
+        self.figure = plt.figure()
+
+        # Define canvas for the figure to be placed on
+        self.canvas = FigureCanvas(self.figure)
+
+        # ... and the toolbar with all the default MPL buttons
+        self.toolbar = NavigationToolbar(self.canvas, self)
+
+        # Simple window for data display
+        self.txt_widget = QtGui.QTextEdit(None)
+
+        # Set the layout and place the canvas widget in it.
+        layout = QtGui.QVBoxLayout()
+        layout.setMargin(0)
+        layout.addWidget(self.canvas)
+
+        # 1D plotter defaults
+        self.current_plot = 111
+        self._data = [] # Original 1D/2D object
+        self._xscale = 'log'
+        self._yscale = 'log'
+        self.qx_data = []
+        self.qy_data = []
+        self.color = 0
+        self.symbol = 0
+        self.grid_on = False
+        self.scale = 'linear'
+        self.x_label = "log10(x)"
+        self.y_label = "log10(y)"
+
+        # Mouse click related
+        self._scale_xlo = None
+        self._scale_xhi = None
+        self._scale_ylo = None
+        self._scale_yhi = None
+        self.x_click = None
+        self.y_click = None
+        self.event_pos = None
+        self.leftdown = False
+        self.gotLegend = 0
+
+        # Annotations
+        self.selectedText = None
+        self.textList = []
+
+        # Pre-define the Scale properties dialog
+        self.properties = ScaleProperties(self,
+                                init_scale_x=self.x_label,
+                                init_scale_y=self.y_label)
+
+        # default color map
+        self.cmap = DEFAULT_CMAP
+
+        # Add the axes object -> subplot
+        # TODO: self.ax will have to be tracked and exposed
+        # to enable subplot specific operations
+        self.ax = self.figure.add_subplot(self.current_plot)
+
+        # Remove this, DAMMIT
+        self.axes = [self.ax]
+
+        # Set the background color to white
+        self.canvas.figure.set_facecolor('#FFFFFF')
+
+        # Canvas event handlers
+        self.canvas.mpl_connect('button_release_event', self.onMplMouseUp)
+        self.canvas.mpl_connect('button_press_event', self.onMplMouseDown)
+        self.canvas.mpl_connect('motion_notify_event', self.onMplMouseMotion)
+        self.canvas.mpl_connect('pick_event', self.onMplPick)
+        self.canvas.mpl_connect('scroll_event', self.onMplWheel)
+
+        self.contextMenu = QtGui.QMenu(self)
+
+        if not quickplot:
+            # Add the toolbar
+            layout.addWidget(self.toolbar)
+            # Notify PlotHelper about the new plot
+            self.upatePlotHelper()
+
+        self.setLayout(layout)
+
+    @property
+    def data(self):
+        """ data getter """
+        return self._data
+
+    @data.setter
+    def data(self, data=None):
+        """ Pure virtual data setter """
+        raise NotImplementedError("Data setter must be implemented in derived class.")
+
+    def title(self, title=""):
+        """ title setter """
+        self._title = title
+
+    @property
+    def xLabel(self, xlabel=""):
+        """ x-label setter """
+        return self.x_label
+
+    @xLabel.setter
+    def xLabel(self, xlabel=""):
+        """ x-label setter """
+        self.x_label = r'$%s$'% xlabel
+
+    @property
+    def yLabel(self, ylabel=""):
+        """ y-label setter """
+        return self.y_label
+
+    @yLabel.setter
+    def yLabel(self, ylabel=""):
+        """ y-label setter """
+        self.y_label = r'$%s$'% ylabel
+
+    @property
+    def yscale(self):
+        """ Y-axis scale getter """
+        return self._yscale
+
+    @yscale.setter
+    def yscale(self, scale='linear'):
+        """ Y-axis scale setter """
+        self.ax.set_yscale(scale, nonposy='clip')
+        self._yscale = scale
+
+    @property
+    def xscale(self):
+        """ X-axis scale getter """
+        return self._xscale
+
+    @xscale.setter
+    def xscale(self, scale='linear'):
+        """ X-axis scale setter """
+        self.ax.set_xscale(scale)
+        self._xscale = scale
+
+    def upatePlotHelper(self):
+        """
+        Notify the plot helper about the new plot
+        """
+        # Notify the helper
+        PlotHelper.addPlot(self)
+        # Notify the listeners about a new graph
+        self.manager.communicator.activeGraphsSignal.emit(PlotHelper.currentPlots())
+
+    def defaultContextMenu(self):
+        """
+        Content of the dialog-universal context menu:
+        Save, Print and Copy
+        """
+        # Actions
+        self.contextMenu.clear()
+        self.actionSaveImage = self.contextMenu.addAction("Save Image")
+        self.actionPrintImage = self.contextMenu.addAction("Print Image")
+        self.actionCopyToClipboard = self.contextMenu.addAction("Copy to Clipboard")
+        self.contextMenu.addSeparator()
+
+        # Define the callbacks
+        self.actionSaveImage.triggered.connect(self.onImageSave)
+        self.actionPrintImage.triggered.connect(self.onImagePrint)
+        self.actionCopyToClipboard.triggered.connect(self.onClipboardCopy)
+
+    def createContextMenu(self):
+        """
+        Define common context menu and associated actions for the MPL widget
+        """
+        raise NotImplementedError("Context menu method must be implemented in derived class.")
+
+    def createContextMenuQuick(self):
+        """
+        Define context menu and associated actions for the quickplot MPL widget
+        """
+        raise NotImplementedError("Context menu method must be implemented in derived class.")
+
+    def contextMenuEvent(self, event):
+        """
+        Display the context menu
+        """
+        if not self.quickplot:
+            self.createContextMenu()
+        else:
+            self.createContextMenuQuick()
+
+        event_pos = event.pos()
+        self.contextMenu.exec_(self.canvas.mapToGlobal(event_pos))
+
+    def onMplMouseUp(self, event):
+        """
+        Mouse button up callback
+        """
+        pass
+
+    def onMplMouseDown(self, event):
+        """
+        Mouse button down callback
+        """
+        pass
+
+    def onMplMouseMotion(self, event):
+        """
+        Mouse motion callback
+        """
+        pass
+
+    def onMplPick(self, event):
+        """
+        Mouse pick callback
+        """
+        pass
+
+    def onMplWheel(self, event):
+        """
+        Mouse wheel scroll callback
+        """
+        pass
+
+    def clean(self):
+        """
+        Redraw the graph
+        """
+        self.figure.delaxes(self.ax)
+        self.ax = self.figure.add_subplot(self.current_plot)
+
+    def plot(self, marker=None, linestyle=None):
+        """
+        PURE VIRTUAL
+        Plot the content of self._data
+        """
+        raise NotImplementedError("Plot method must be implemented in derived class.")
+
+    def closeEvent(self, event):
+        """
+        Overwrite the close event adding helper notification
+        """
+        # Please remove me from your database.
+        PlotHelper.deletePlot(PlotHelper.idOfPlot(self))
+        # Notify the listeners
+        self.manager.communicator.activeGraphsSignal.emit(PlotHelper.currentPlots())
+        event.accept()
+
+    def onImageSave(self):
+        """
+        Use the internal MPL method for saving to file
+        """
+        self.toolbar.save_figure()
+
+    def onImagePrint(self):
+        """
+        Display printer dialog and print the MPL widget area
+        """
+        # Define the printer
+        printer = QtGui.QPrinter()
+
+        # Display the print dialog
+        dialog = QtGui.QPrintDialog(printer)
+        dialog.setModal(True)
+        dialog.setWindowTitle("Print")
+        if dialog.exec_() != QtGui.QDialog.Accepted:
+            return
+
+        painter = QtGui.QPainter(printer)
+        # Grab the widget screenshot
+        pmap = QtGui.QPixmap.grabWidget(self)
+        # Create a label with pixmap drawn
+        printLabel = QtGui.QLabel()
+        printLabel.setPixmap(pmap)
+
+        # Print the label
+        printLabel.render(painter)
+        painter.end()
+
+    def onClipboardCopy(self):
+        """
+        Copy MPL widget area to buffer
+        """
+        bmp = QtGui.QApplication.clipboard()
+        pixmap = QtGui.QPixmap.grabWidget(self.canvas)
+        bmp.setPixmap(pixmap)
+
+    def onGridToggle(self):
+        """
+        Add/remove grid lines from MPL plot
+        """
+        self.grid_on = (not self.grid_on)
+        self.ax.grid(self.grid_on)
+        self.canvas.draw_idle()
+
+    def onWindowsTitle(self):
+        """
+        Show a dialog allowing chart title customisation
+        """
+        current_title = self.windowTitle()
+        titleWidget = WindowTitle(self, new_title=current_title)
+        result = titleWidget.exec_()
+        if result != QtGui.QDialog.Accepted:
+            return
+
+        title = titleWidget.title()
+        self.setWindowTitle(title)
+        # Notify the listeners about a new graph title
+        self.manager.communicator.activeGraphName.emit((current_title, title))
+
+    def offset_graph(self):
+        """
+        Zoom and offset the graph to the last known settings
+        """
+        for ax in self.axes:
+            if self._scale_xhi is not None and self._scale_xlo is not None:
+                ax.set_xlim(self._scale_xlo, self._scale_xhi)
+            if self._scale_yhi is not None and self._scale_ylo is not None:
+                ax.set_ylim(self._scale_ylo, self._scale_yhi)
+
+    def onDataInfo(self, plot_data):
+        """
+        Displays data info text window for the selected plot
+        """
+        if isinstance(plot_data, Data1D):
+            text_to_show = GuiUtils.retrieveData1d(plot_data)
+        else:
+            text_to_show = GuiUtils.retrieveData2d(plot_data)
+        # Hardcoded sizes to enable full width rendering with default font
+        self.txt_widget.resize(420,600)
+
+        self.txt_widget.setReadOnly(True)
+        self.txt_widget.setWindowFlags(QtCore.Qt.Window)
+        self.txt_widget.setWindowIcon(QtGui.QIcon(":/res/ball.ico"))
+        self.txt_widget.setWindowTitle("Data Info: %s" % plot_data.filename)
+        self.txt_widget.insertPlainText(text_to_show)
+
+        self.txt_widget.show()
+        # Move the slider all the way up, if present
+        vertical_scroll_bar = self.txt_widget.verticalScrollBar()
+        vertical_scroll_bar.triggerAction(QtGui.QScrollBar.SliderToMinimum)
+
+    def onSavePoints(self, plot_data):
+        """
+        Saves plot data to a file
+        """
+        if isinstance(plot_data, Data1D):
+            GuiUtils.saveData1D(plot_data)
+        else:
+            GuiUtils.saveData2D(plot_data)
Index: src/sas/qtgui/Plotting/ScaleProperties.py
===================================================================
--- src/sas/qtgui/Plotting/ScaleProperties.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/ScaleProperties.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,70 @@
+from PyQt4 import QtGui
+
+import sas.sasview
+
+from sas.qtgui.Plotting.UI.ScalePropertiesUI import Ui_scalePropertiesUI
+
+x_values = ["x", "x^(2)", "x^(4)", "ln(x)", "log10(x)", "log10(x^(4))"]
+y_values = ["y", "1/y", "ln(y)", "y^(2)", "y*x^(2)", "y*x^(4)", "1/sqrt(y)",
+            "log10(y)", "ln(y*x)", "ln(y*x^(2))", "ln(y*x^(4))", "log10(y*x^(4))"]
+view_values = ["--", "Linear y vs x", "Guinier lny vs x^(2)",
+            "XS Guinier ln(y*x) vs x^(2)", "Porod y*x^(4) vs x^(4)", "Kratky y*x^(2) vs x"]
+view_to_xy = {
+    view_values[0]: [None, None], # custom
+    view_values[1]: [0, 0], # linear
+    view_values[2]: [1, 2], # Guinier
+    view_values[3]: [1, 8], # XS Guinier
+    view_values[4]: [2, 5], # Porod
+    view_values[5]: [0, 4], # Kratky
+}
+class ScaleProperties(QtGui.QDialog, Ui_scalePropertiesUI):
+    def __init__(self, parent=None, init_scale_x='x', init_scale_y='y'):
+        super(ScaleProperties, self).__init__(parent)
+        self.setupUi(self)
+
+        # Set up comboboxes
+        self.cbX.addItems(x_values)
+        self.cbY.addItems(y_values)
+        self.cbView.addItems(view_values)
+        # Resize the dialog only AFTER the boxes are populated
+        self.setFixedSize(self.minimumSizeHint())
+
+        # Set up the initial values for x and y.
+        # This avoids keeping a QModel instance here.
+        if init_scale_x in x_values and init_scale_y in y_values:
+            self.cbX.setCurrentIndex(x_values.index(init_scale_x))
+            self.cbY.setCurrentIndex(y_values.index(init_scale_y))
+
+        # Connect combobox index change to a custom method
+        self.cbView.currentIndexChanged.connect(self.viewIndexChanged)
+        self.cbX.currentIndexChanged.connect(self.xyIndexChanged)
+        self.cbY.currentIndexChanged.connect(self.xyIndexChanged)
+
+    def getValues(self):
+        """
+        Return current values from comboboxes
+        """
+        return str(self.cbX.currentText()), str(self.cbY.currentText())
+
+    def viewIndexChanged(self, index):
+        """
+        Update X and Y labels based on the "View" index
+        """
+        if index > 0:
+            # Disable signals so xyIndexChanged() doesn't get called
+            self.cbX.blockSignals(True)
+            self.cbY.blockSignals(True)
+
+            # Update the sub-controls
+            self.cbX.setCurrentIndex(view_to_xy[view_values[index]][0])
+            self.cbY.setCurrentIndex(view_to_xy[view_values[index]][1])
+            # Re-enable the signals
+
+            self.cbX.blockSignals(False)
+            self.cbY.blockSignals(False)
+
+    def xyIndexChanged(self, index):
+        """
+        Update View label based on the "X" and "Y" index
+        """
+        self.cbView.setCurrentIndex(0)
Index: src/sas/qtgui/Plotting/SetGraphRange.py
===================================================================
--- src/sas/qtgui/Plotting/SetGraphRange.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/SetGraphRange.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,39 @@
+"""
+Allows users to change the range of the current graph
+"""
+from PyQt4 import QtGui
+
+# Local UI
+from sas.qtgui.Plotting.UI.SetGraphRangeUI import Ui_setGraphRangeUI
+
+class SetGraphRange(QtGui.QDialog, Ui_setGraphRangeUI):
+    def __init__(self, parent=None, x_range=(0.0, 0.0), y_range=(0.0, 0.0)):
+        super(SetGraphRange, self).__init__()
+
+        self.setupUi(self)
+        assert(isinstance(x_range, tuple))
+        assert(isinstance(y_range, tuple))
+
+        self.txtXmin.setValidator(QtGui.QDoubleValidator())
+        self.txtXmax.setValidator(QtGui.QDoubleValidator())
+        self.txtYmin.setValidator(QtGui.QDoubleValidator())
+        self.txtYmax.setValidator(QtGui.QDoubleValidator())
+
+        self.txtXmin.setText(str(x_range[0]))
+        self.txtXmax.setText(str(x_range[1]))
+        self.txtYmin.setText(str(y_range[0]))
+        self.txtYmax.setText(str(y_range[1]))
+
+    def xrange(self):
+        """
+        Return a tuple with line edit content of (xmin, xmax)
+        """
+        return (float(self.txtXmin.text()),
+                float(self.txtXmax.text()))
+
+    def yrange(self):
+        """
+        Return a tuple with line edit content of (ymin, ymax)
+        """
+        return (float(self.txtYmin.text()),
+                float(self.txtYmax.text()))
Index: src/sas/qtgui/Plotting/SlicerModel.py
===================================================================
--- src/sas/qtgui/Plotting/SlicerModel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/SlicerModel.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,57 @@
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+
+class SlicerModel(object):
+    def __init__(self):
+        # Model representation of local parameters
+        self._model = QtGui.QStandardItemModel()
+
+        self.update_model = True
+        self._model.itemChanged.connect(self.setParamsFromModel)
+
+    def setModelFromParams(self):
+        """
+        Set up the Qt model for data handling between controls
+        """
+        parameters = self.getParams()
+        self._model.removeRows( 0, self._model.rowCount() )
+        # Crete/overwrite model items
+        for parameter in parameters.keys():
+            item1 = QtGui.QStandardItem(parameter)
+            item2 = QtGui.QStandardItem(GuiUtils.formatNumber(parameters[parameter]))
+            self._model.appendRow([item1, item2])
+        self._model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant("Parameter"))
+        self._model.setHeaderData(1, QtCore.Qt.Horizontal, QtCore.QVariant("Value"))
+
+    def setParamsFromModel(self, item):
+        """
+        Set up the params dictionary based on the model content.
+        """
+        params = self.getParams()
+        index = self._model.indexFromItem(item)
+        row_index = index.row()
+        param_name = str(self._model.item(row_index, 0).text())
+        params[param_name] = float(self._model.item(row_index, 1).text())
+
+        self.update_model = False
+        self.setParams(params)
+        self.update_model = True
+
+    def model(self):
+        '''getter for the model'''
+        return self._model
+
+    def getParams(self):
+        ''' pure virtual '''
+        raise NotImplementedError("Parameter getter must be implemented in derived class.")
+
+    def setParams(self):
+        ''' pure virtual '''
+        raise NotImplementedError("Parameter setter must be implemented in derived class.")
+
+    def validate(self):
+        ''' pure virtual '''
+        raise NotImplementedError("Validator must be implemented in derived class.")
+
Index: src/sas/qtgui/Plotting/SlicerParameters.py
===================================================================
--- src/sas/qtgui/Plotting/SlicerParameters.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/SlicerParameters.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,175 @@
+"""
+Allows users to modify the box slicer parameters.
+"""
+import numpy
+import functools
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+from PyQt4 import QtWebKit
+
+# Local UI
+from sas.qtgui.Plotting.UI.SlicerParametersUI import Ui_SlicerParametersUI
+
+class SlicerParameters(QtGui.QDialog, Ui_SlicerParametersUI):
+    """
+    Interaction between the QTableView and the underlying model,
+    passed from a slicer instance.
+    """
+    close_signal = QtCore.pyqtSignal()
+    def __init__(self, model=None, validate_method=None):
+        super(SlicerParameters, self).__init__()
+
+        self.setupUi(self)
+
+        assert isinstance(model, QtGui.QStandardItemModel)
+
+        self.model = model
+        self.validate_method = validate_method
+
+        # Define a proxy model so cell enablement can be finegrained.
+        self.proxy = ProxyModel(self)
+        self.proxy.setSourceModel(self.model)
+
+        # Set the proxy model for display in the Table View.
+        self.lstParams.setModel(self.proxy)
+
+        # Disallow edit of the parameter name column.
+        self.lstParams.model().setColumnReadOnly(0, True)
+
+        # Specify the validator on the parameter value column.
+        self.delegate = EditDelegate(self, validate_method=self.validate_method)
+        self.lstParams.setItemDelegate(self.delegate)
+        self.delegate.refocus_signal.connect(self.onFocus)
+
+        # Display Help on clicking the button
+        self.buttonBox.button(QtGui.QDialogButtonBox.Help).clicked.connect(self.onHelp)
+
+        # Close doesn't trigger closeEvent automatically, so force it
+        self.buttonBox.button(QtGui.QDialogButtonBox.Close).clicked.connect(functools.partial(self.closeEvent, None))
+
+        # Disable row number display
+        self.lstParams.verticalHeader().setVisible(False)
+        self.lstParams.setAlternatingRowColors(True)
+        self.lstParams.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)
+
+        # Header properties for nicer display
+        header = self.lstParams.horizontalHeader()
+        header.setResizeMode(QtGui.QHeaderView.Stretch)
+        header.setStretchLastSection(True)
+
+    def onFocus(self, row, column):
+        """ Set the focus on the cell (row, column) """
+        selection_model = self.lstParams.selectionModel()
+        selection_model.select(self.model.index(row, column), QtGui.QItemSelectionModel.Select)
+        self.lstParams.setSelectionModel(selection_model)
+        self.lstParams.setCurrentIndex(self.model.index(row, column))
+
+    def setModel(self, model):
+        """ Model setter """
+        self.model = model
+        self.proxy.setSourceModel(self.model)
+
+    def closeEvent(self, event):
+        """
+        Overwritten close widget method in order to send the close
+        signal to the parent.
+        """
+        self.close_signal.emit()
+        if event:
+            event.accept()
+
+    def onHelp(self):
+        """
+        Display generic data averaging help
+        """
+        location = "docs/sphinx-docs/build/html" + \
+            "/user/sasgui/guiframe/graph_help.html#d-data-averaging"
+        self.helpView = QtWebKit.QWebView()
+        self.helpView.load(QtCore.QUrl(location))
+        self.helpView.show()
+
+
+class ProxyModel(QtGui.QIdentityProxyModel):
+    """
+    Trivial proxy model with custom column edit flag
+    """
+    def __init__(self, parent=None):
+        super(ProxyModel, self).__init__(parent)
+        self._columns = set()
+
+    def columnReadOnly(self, column):
+        '''Returns True if column is read only, false otherwise'''
+        return column in self._columns
+
+    def setColumnReadOnly(self, column, readonly=True):
+        '''Add/removes a column from the readonly list'''
+        if readonly:
+            self._columns.add(column)
+        else:
+            self._columns.discard(column)
+
+    def flags(self, index):
+        '''Sets column flags'''
+        flags = super(ProxyModel, self).flags(index)
+        if self.columnReadOnly(index.column()):
+            flags &= ~QtCore.Qt.ItemIsEditable
+        return flags
+
+class PositiveDoubleEditor(QtGui.QLineEdit):
+    # a signal to tell the delegate when we have finished editing
+    editingFinished = QtCore.Signal()
+
+    def __init__(self, parent=None):
+            # Initialize the editor object
+            super(PositiveDoubleEditor, self).__init__(parent)
+            self.setAutoFillBackground(True)
+            validator = QtGui.QDoubleValidator()
+            # Don't use the scientific notation, cause 'e'.
+            validator.setNotation(QtGui.QDoubleValidator.StandardNotation)
+
+            self.setValidator(validator)
+
+    def focusOutEvent(self, event):
+            # Once focus is lost, tell the delegate we're done editing
+            self.editingFinished.emit()
+
+
+class EditDelegate(QtGui.QStyledItemDelegate):
+    refocus_signal = QtCore.pyqtSignal(int, int)
+    def __init__(self, parent=None, validate_method=None):
+        super(EditDelegate, self).__init__(parent)
+        self.editor = None
+        self.index = None
+        self.validate_method = validate_method
+
+    def createEditor(self, parent, option, index):
+        # Creates and returns the custom editor object we will use to edit the cell
+        if not index.isValid():
+            return 0
+
+        result = index.column()
+        if result==1:
+                self.editor = PositiveDoubleEditor(parent)
+                self.index = index
+                return self.editor
+        else:
+                return QtGui.QStyledItemDelegate.createEditor(self, parent, option, index)
+
+    def setModelData(self, editor, model, index):
+        """
+        Custom version of the model update, rejecting bad values
+        """
+        self.index = index
+
+        # Find out the changed parameter name and proposed value
+        new_value = self.editor.text().toFloat()[0]
+        param_name = str(model.sourceModel().item(index.row(),0).text())
+
+        validated = True
+        if self.validate_method:
+            # Validate the proposed value in the slicer
+            value_accepted = self.validate_method(param_name, new_value)
+
+        if value_accepted:
+            # Update the model only if value accepted
+            return super(EditDelegate, self).setModelData(editor, model, index)          
Index: src/sas/qtgui/Plotting/UI/AddTextUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/AddTextUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/AddTextUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AddText</class>
+ <widget class="QDialog" name="AddText">
+  <property name="windowModality">
+   <enum>Qt::ApplicationModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>432</width>
+    <height>324</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Add Text</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Custom Text </string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="0">
+       <widget class="QTextEdit" name="textEdit">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </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>44</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QPushButton" name="btnFont">
+       <property name="text">
+        <string>Font...</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="btnColor">
+       <property name="text">
+        <string>Color...</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="QDialogButtonBox" name="buttonBox">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="standardButtons">
+        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>AddText</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>AddText</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Plotting/UI/BoxSumUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/BoxSumUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/BoxSumUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,452 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BoxSumUI</class>
+ <widget class="QDialog" name="BoxSumUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>322</width>
+    <height>313</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Box Sum</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_4">
+   <item row="0" column="0" colspan="2">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Box dimensions</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_3">
+      <item row="0" column="0">
+       <widget class="QGroupBox" name="groupBox_4">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="title">
+         <string>Box size</string>
+        </property>
+        <layout class="QGridLayout" name="gridLayout">
+         <item row="0" column="0">
+          <widget class="QLabel" name="label">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="text">
+            <string>Height</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QLineEdit" name="txtBoxHeight">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>70</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>70</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="2">
+          <widget class="QLabel" name="label_10">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
+         </item>
+         <item row="1" column="0">
+          <widget class="QLabel" name="label_2">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="text">
+            <string>Width</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QLineEdit" name="txtBoxWidth">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>70</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>70</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="2">
+          <widget class="QLabel" name="label_11">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QGroupBox" name="groupBox_2">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="title">
+         <string>Box center</string>
+        </property>
+        <layout class="QGridLayout" name="gridLayout_2">
+         <item row="0" column="0">
+          <widget class="QLabel" name="label_3">
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;X coordinate of the center of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="text">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;X&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QLineEdit" name="txtCenterX">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>70</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>70</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;X coordinate of the center of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="2">
+          <widget class="QLabel" name="label_13">
+           <property name="text">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
+         </item>
+         <item row="1" column="0">
+          <widget class="QLabel" name="label_4">
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Y coordinate of the center of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="text">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;Y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QLineEdit" name="txtCenterY">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>70</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="maximumSize">
+            <size>
+             <width>70</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="toolTip">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Y coordinate of the center of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="text">
+            <string/>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="2">
+          <widget class="QLabel" name="label_12">
+           <property name="text">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="1" column="0" colspan="2">
+    <widget class="QGroupBox" name="groupBox_3">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Box parameters</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_5">
+      <item row="0" column="0">
+       <layout class="QFormLayout" name="formLayout">
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_5">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Average point count in selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Avg:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QLabel" name="lblAvg">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Average point count in selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_6">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error of average point count in selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Avg error:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QLabel" name="lblAvgErr">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error of average point count in selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="label_7">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Total number of points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Num. of points:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1">
+         <widget class="QLabel" name="lblNumPoints">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Total number of points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="label_8">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sum of point intensities for all points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Sum:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="1">
+         <widget class="QLabel" name="lblSum">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sum of point intensities for all points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="0">
+         <widget class="QLabel" name="label_9">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error of point intensity sum for all points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Sum error:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="1">
+         <widget class="QLabel" name="lblSumErr">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error of point intensity sum for all points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>18</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="3" column="1">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>BoxSumUI</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>BoxSumUI</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Plotting/UI/ColorMapUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/ColorMapUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/ColorMapUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ColorMapUI</class>
+ <widget class="QDialog" name="ColorMapUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>450</width>
+    <height>329</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Color Map</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_5">
+   <item row="1" column="1">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>62</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="3" column="0" colspan="3">
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <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="QDialogButtonBox" name="buttonBox">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="standardButtons">
+        <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="0" column="0" colspan="2">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Color map</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="0">
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <widget class="QLabel" name="label">
+          <property name="text">
+           <string>Select color map</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="cbColorMap">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select color map from the list.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item row="1" column="0">
+       <layout class="QGridLayout" name="gridLayout">
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_2">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter value for minimum color map amplitude.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Min amplitude for color map</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QLineEdit" name="txtMinAmplitude">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter value for minimum color map amplitude.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_3">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter value for maximum color map amplitude.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Max amplitude for color map</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QLineEdit" name="txtMaxAmplitude">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter value for maximum color map amplitude.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item row="2" column="0">
+       <widget class="QCheckBox" name="chkReverse">
+        <property name="toolTip">
+         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use the color-reversed map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+        </property>
+        <property name="text">
+         <string>Reverse map</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="0" column="2">
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="title">
+      <string>Detector</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_4">
+      <item row="0" column="0">
+       <layout class="QGridLayout" name="gridLayout_3">
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_4">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Detector width.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Width in pixels</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QLabel" name="lblWidth">
+          <property name="text">
+           <string>0</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_5">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Detector height.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Height in pixels</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QLabel" name="lblHeight">
+          <property name="text">
+           <string>0</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="label_6">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum absolute Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;x,y&lt;/span&gt; value.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;max&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1">
+         <widget class="QLabel" name="lblQmax">
+          <property name="text">
+           <string>0</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="label_7">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Minimum value of Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;x&lt;/span&gt; in units of Q.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="text">
+           <string>Beam stop radius</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="1">
+         <widget class="QLabel" name="lblStopRadius">
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="3">
+    <widget class="QWidget" name="widget" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+  </layout>
+  <zorder>groupBox</zorder>
+  <zorder>widget</zorder>
+  <zorder>groupBox_2</zorder>
+  <zorder>verticalSpacer</zorder>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>ColorMapUI</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>ColorMapUI</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Plotting/UI/LinearFitUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/LinearFitUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/LinearFitUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LinearFitUI</class>
+ <widget class="QDialog" name="LinearFitUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>439</width>
+    <height>324</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Linear Fit</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_4">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Perform fit for &lt;span style=&quot; font-weight:600; font-style:italic;&quot;&gt;y(x) = ax + b&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0" colspan="2">
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="title">
+      <string>Fit ranges</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_3">
+      <item row="0" column="0">
+       <layout class="QGridLayout" name="gridLayout_2">
+        <item row="0" column="1">
+         <widget class="QLabel" name="label_9">
+          <property name="text">
+           <string>Min</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="2">
+         <widget class="QLabel" name="label_10">
+          <property name="text">
+           <string>Max</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_8">
+          <property name="text">
+           <string>Range (linear scale)</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QLineEdit" name="txtRangeMin">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Minimum value on the x-axis for the plotted data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="autoFillBackground">
+           <bool>true</bool>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="2">
+         <widget class="QLineEdit" name="txtRangeMax">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum value on the x-axis for the plotted data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="autoFillBackground">
+           <bool>true</bool>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="lblRange">
+          <property name="text">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit range&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1">
+         <widget class="QLineEdit" name="txtFitRangeMin">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter the minimum value on the x-axis to be included in the fit.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="2">
+         <widget class="QLineEdit" name="txtFitRangeMax">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter the maximum value on the x-axis to be included in the fit.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="2">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Fit parameters</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="0">
+       <layout class="QFormLayout" name="formLayout">
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_3">
+          <property name="text">
+           <string>a</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QLineEdit" name="txtA">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit value for the slope parameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_4">
+          <property name="text">
+           <string>b</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QLineEdit" name="txtB">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit value for the constant parameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="label_7">
+          <property name="text">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ï&lt;span style=&quot; vertical-align:super;&quot;&gt;2&lt;/span&gt;/dof&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1">
+         <widget class="QLineEdit" name="txtChi2">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ï&lt;span style=&quot; vertical-align:super;&quot;&gt;2&lt;/span&gt; over degrees of freedom.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item row="0" column="1">
+       <layout class="QFormLayout" name="formLayout_2">
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_5">
+          <property name="text">
+           <string>+/-</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QLineEdit" name="txtAerr">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error on the slope parameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_6">
+          <property name="text">
+           <string>+/-</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QLineEdit" name="txtBerr">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error on the constant parameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="2">
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#000000;&quot;&gt;Resolution is NOT accounted for.&lt;br/&gt;Slit smeared data will give very wrong answers!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="1">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>3</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="5" column="0" colspan="2">
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <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>
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <item>
+        <widget class="QPushButton" name="cmdFit">
+         <property name="text">
+          <string>Fit</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="cmdClose">
+         <property name="text">
+          <string>Close</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>cmdClose</sender>
+   <signal>clicked()</signal>
+   <receiver>LinearFitUI</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>284</x>
+     <y>304</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>166</x>
+     <y>163</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Plotting/UI/MaskEditorUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/MaskEditorUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/MaskEditorUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MaskEditorUI</class>
+ <widget class="QDialog" name="MaskEditorUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>642</width>
+    <height>431</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Mask shape</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <item>
+       <widget class="QRadioButton" name="rbWings">
+        <property name="text">
+         <string>Double Wings</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rbCircularDisk">
+        <property name="text">
+         <string>Circular Disk</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rbRectangularDisk">
+        <property name="text">
+         <string>Rectangular Disk</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rbDoubleWingWindow">
+        <property name="text">
+         <string>Double Wing Window</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rbCircularWindow">
+        <property name="text">
+         <string>Circular Window</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rbRectangularWindow">
+        <property name="text">
+         <string>Rectangular Window</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="0" column="1" rowspan="4">
+    <widget class="QFrame" name="frame">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <property name="lineWidth">
+      <number>2</number>
+     </property>
+    </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>152</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="0">
+    <widget class="QPushButton" name="btnAdd">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>Add</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0">
+    <widget class="QPushButton" name="btnReset">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>Reset</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <widget class="QPushButton" name="btnClear">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>Clear</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
Index: src/sas/qtgui/Plotting/UI/PlotPropertiesUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/PlotPropertiesUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/PlotPropertiesUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PlotPropertiesUI</class>
+ <widget class="QDialog" name="PlotPropertiesUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>319</width>
+    <height>172</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Modify Plot Properties</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_3">
+   <item row="0" column="0">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Symbol</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="0">
+       <layout class="QGridLayout" name="gridLayout">
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_2">
+          <property name="text">
+           <string>Shape</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1" colspan="2">
+         <widget class="QComboBox" name="cbShape"/>
+        </item>
+        <item row="0" column="3" alignment="Qt::AlignRight">
+         <widget class="QLabel" name="label_4">
+          <property name="text">
+           <string>Size</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="4">
+         <widget class="QSpinBox" name="sbSize">
+          <property name="minimum">
+           <number>1</number>
+          </property>
+          <property name="maximum">
+           <number>72</number>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_3">
+          <property name="text">
+           <string>Color</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QComboBox" name="cbColor"/>
+        </item>
+        <item row="1" column="2">
+         <widget class="QPushButton" name="cmdCustom">
+          <property name="text">
+           <string>Custom..</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Legend Label</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLineEdit" name="txtLegend"/>
+     </item>
+    </layout>
+   </item>
+   <item row="2" column="0">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>120</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="3" column="0">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>PlotPropertiesUI</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>PlotPropertiesUI</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Plotting/UI/ScalePropertiesUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/ScalePropertiesUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/ScalePropertiesUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>scalePropertiesUI</class>
+ <widget class="QDialog" name="scalePropertiesUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>137</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Scale Properties</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>X</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Y</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>View</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QComboBox" name="cbX"/>
+     </item>
+     <item row="1" column="1">
+      <widget class="QComboBox" name="cbY"/>
+     </item>
+     <item row="1" column="2">
+      <widget class="QComboBox" name="cbView"/>
+     </item>
+    </layout>
+   </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>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="0">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>scalePropertiesUI</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>scalePropertiesUI</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Plotting/UI/SetGraphRangeUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/SetGraphRangeUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/SetGraphRangeUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>setGraphRangeUI</class>
+ <widget class="QDialog" name="setGraphRangeUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>358</width>
+    <height>144</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Set Graph Range</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>X min</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="txtXmin"/>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>X max</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="3">
+      <widget class="QLineEdit" name="txtXmax"/>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>Y min</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLineEdit" name="txtYmin"/>
+     </item>
+     <item row="1" column="2">
+      <widget class="QLabel" name="label_4">
+       <property name="text">
+        <string>Y max</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="3">
+      <widget class="QLineEdit" name="txtYmax"/>
+     </item>
+    </layout>
+   </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>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="0">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>setGraphRangeUI</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>setGraphRangeUI</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Plotting/UI/SlicerParametersUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/SlicerParametersUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/SlicerParametersUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SlicerParametersUI</class>
+ <widget class="QDialog" name="SlicerParametersUI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>328</width>
+    <height>266</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Slicer Parameters</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="main_resources.qrc">
+    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0" colspan="2">
+    <widget class="QTableView" name="lstParams"/>
+   </item>
+   <item row="1" column="1">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close|QDialogButtonBox::Help</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="main_resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>SlicerParametersUI</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>SlicerParametersUI</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Plotting/UI/WindowTitleUI.ui
===================================================================
--- src/sas/qtgui/Plotting/UI/WindowTitleUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UI/WindowTitleUI.ui	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>WindowTitle</class>
+ <widget class="QDialog" name="WindowTitle">
+  <property name="windowModality">
+   <enum>Qt::ApplicationModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>287</width>
+    <height>137</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Modify Window Title</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>New title</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QLineEdit" name="txtTitle"/>
+   </item>
+   <item row="1" column="0" colspan="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>WindowTitle</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>WindowTitle</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
Index: src/sas/qtgui/Plotting/UnitTesting/AddTextTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/AddTextTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/AddTextTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,61 @@
+import sys
+import unittest
+from mock import MagicMock
+
+from PyQt4 import QtGui
+
+# set up import paths
+import path_prepare
+
+# Local
+from sas.qtgui.Plotting.AddText import AddText
+
+app = QtGui.QApplication(sys.argv)
+
+class AddTextTest(unittest.TestCase):
+    '''Test the AddText'''
+    def setUp(self):
+        '''Create the AddText'''
+        self.widget = AddText(None)
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtGui.QDialog)
+        self.assertIsInstance(self.widget._font, QtGui.QFont)
+        self.assertEqual(self.widget._color, "black")
+        
+    def testOnFontChange(self):
+        '''Test the QFontDialog output'''
+        font_1 = QtGui.QFont("Helvetica", 15)
+        QtGui.QFontDialog.getFont = MagicMock(return_value=(font_1, True))
+        # Call the method
+        self.widget.onFontChange(None)
+        # Check that the text field got the new font info
+        self.assertEqual(self.widget.textEdit.currentFont(), font_1)
+
+        # See that rejecting the dialog doesn't modify the font
+        font_2 = QtGui.QFont("Arial", 9)
+        QtGui.QFontDialog.getFont = MagicMock(return_value=(font_2, False))
+        # Call the method
+        self.widget.onFontChange(None)
+        # Check that the text field retained the previous font info
+        self.assertEqual(self.widget.textEdit.currentFont(), font_1)
+
+    def testOnColorChange(self):
+        ''' Test the QColorDialog output'''
+        new_color = QtGui.QColor("red")
+        QtGui.QColorDialog.getColor = MagicMock(return_value=new_color)
+        # Call the method
+        self.widget.onColorChange(None)
+        # Check that the text field got the new color info for text
+        self.assertEqual(self.widget.textEdit.palette().color(QtGui.QPalette.Text), new_color)
+        # ... and the hex value of this color is correct
+        self.assertEqual(self.widget.color(), "#ff0000")
+        
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/BoxSumTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/BoxSumTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/BoxSumTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,47 @@
+import sys
+import unittest
+from mock import MagicMock
+
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+
+# set up import paths
+import path_prepare
+
+# Local
+from sas.qtgui.Plotting.BoxSum import BoxSum
+
+app = QtGui.QApplication(sys.argv)
+
+class BoxSumTest(unittest.TestCase):
+    '''Test the BoxSum'''
+    def setUp(self):
+        '''Create the BoxSum'''
+        # example model
+        model = QtGui.QStandardItemModel()
+        parameters = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
+        for index, parameter in enumerate(parameters):
+            model.setData(model.index(0, index),
+                    QtCore.QVariant(parameter))
+        self.widget = BoxSum(None, model=model)
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(0), QtGui.QLineEdit)
+        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(1), QtGui.QLineEdit)
+        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(2), QtGui.QLineEdit)
+        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(3), QtGui.QLineEdit)
+        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(4), QtGui.QLabel)
+        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(5), QtGui.QLabel)
+        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(6), QtGui.QLabel)
+        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(7), QtGui.QLabel)
+        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(8), QtGui.QLabel)
+        
+        
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/ColorMapTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/ColorMapTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/ColorMapTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,200 @@
+import sys
+import unittest
+import numpy
+
+from PyQt4 import QtGui
+from mock import MagicMock
+import matplotlib as mpl
+
+# set up import paths
+import path_prepare
+
+from sas.sasgui.guiframe.dataFitting import Data2D
+import sas.qtgui.Plotting.Plotter2D as Plotter2D
+from UnitTesting.TestUtils import WarningTestNotImplemented
+from UnitTesting.TestUtils import QtSignalSpy
+
+# Local
+from sas.qtgui.Plotting.ColorMap import ColorMap
+
+app = QtGui.QApplication(sys.argv)
+
+class ColorMapTest(unittest.TestCase):
+    '''Test the ColorMap'''
+    def setUp(self):
+        '''Create the ColorMap'''
+        self.plotter = Plotter2D.Plotter2D(None, quickplot=True)
+
+        self.data = Data2D(image=[0.1]*4,
+                           qx_data=[1.0, 2.0, 3.0, 4.0],
+                           qy_data=[10.0, 11.0, 12.0, 13.0],
+                           dqx_data=[0.1, 0.2, 0.3, 0.4],
+                           dqy_data=[0.1, 0.2, 0.3, 0.4],
+                           q_data=[1,2,3,4],
+                           xmin=-1.0, xmax=5.0,
+                           ymin=-1.0, ymax=15.0,
+                           zmin=-1.0, zmax=20.0)
+
+        self.data.title="Test data"
+        self.data.id = 1
+        self.widget = ColorMap(parent=self.plotter, data=self.data)
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtGui.QDialog)
+
+        self.assertEqual(self.widget._cmap_orig, "jet")
+        self.assertEqual(len(self.widget.all_maps), 144)
+        self.assertEqual(len(self.widget.maps), 72)
+        self.assertEqual(len(self.widget.rmaps), 72)
+
+        self.assertEqual(self.widget.lblWidth.text(), "0")
+        self.assertEqual(self.widget.lblHeight.text(), "0")
+        self.assertEqual(self.widget.lblQmax.text(), "15.8")
+        self.assertEqual(self.widget.lblStopRadius.text(), "-1")
+        self.assertFalse(self.widget.chkReverse.isChecked())
+        self.assertEqual(self.widget.cbColorMap.count(), 72)
+        self.assertEqual(self.widget.cbColorMap.currentIndex(), 60)
+
+        # validators
+        self.assertIsInstance(self.widget.txtMinAmplitude.validator(), QtGui.QDoubleValidator)
+        self.assertIsInstance(self.widget.txtMaxAmplitude.validator(), QtGui.QDoubleValidator)
+
+        # Ranges
+        self.assertEqual(self.widget.txtMinAmplitude.text(), "0")
+        self.assertEqual(self.widget.txtMaxAmplitude.text(), "100")
+        self.assertIsInstance(self.widget.slider, QtGui.QSlider)
+
+    def testOnReset(self):
+        '''Check the dialog reset function'''
+        # Set some controls to non-default state
+        self.widget.cbColorMap.setCurrentIndex(20)
+        self.widget.chkReverse.setChecked(True)
+        self.widget.txtMinAmplitude.setText("20.0")
+
+        # Reset the widget state
+        self.widget.onReset()
+
+        # Assure things went back to default
+        self.assertEqual(self.widget.cbColorMap.currentIndex(), 20)
+        self.assertFalse(self.widget.chkReverse.isChecked())
+        self.assertEqual(self.widget.txtMinAmplitude.text(), "0")
+
+    def testOnApply(self):
+        '''Check the dialog apply function'''
+        # Set some controls to non-default state
+        self.widget.show()
+        self.widget.cbColorMap.setCurrentIndex(20) # PuRd_r
+        self.widget.chkReverse.setChecked(True)
+        self.widget.txtMinAmplitude.setText("20.0")
+
+        spy_apply = QtSignalSpy(self.widget, self.widget.apply_signal)
+        # Reset the widget state
+        self.widget.onApply()
+
+        # Assure the widget is still up and the signal was sent.
+        self.assertTrue(self.widget.isVisible())
+        self.assertEqual(spy_apply.count(), 1)
+        self.assertIn('PuRd_r', spy_apply.called()[0]['args'][1])
+
+    def testInitMapCombobox(self):
+        '''Test the combo box initializer'''
+        # Set a color map from the direct list
+        self.widget._cmap = "gnuplot"
+        self.widget.initMapCombobox()
+
+        # Check the combobox
+        self.assertEqual(self.widget.cbColorMap.currentIndex(), 55)
+        self.assertFalse(self.widget.chkReverse.isChecked())
+
+        # Set a reversed value
+        self.widget._cmap = "hot_r"
+        self.widget.initMapCombobox()
+        # Check the combobox
+        self.assertEqual(self.widget.cbColorMap.currentIndex(), 56)
+        self.assertTrue(self.widget.chkReverse.isChecked())
+
+    def testInitRangeSlider(self):
+        '''Test the range slider initializer'''
+        # Set a color map from the direct list
+        self.widget._cmap = "gnuplot"
+        self.widget.initRangeSlider()
+
+        # Check the values
+        self.assertEqual(self.widget.slider.minimum(), 0)
+        self.assertEqual(self.widget.slider.maximum(), 100)
+        self.assertEqual(self.widget.slider.orientation(), 1)
+
+        # Emit new low value
+        self.widget.slider.lowValueChanged.emit(5)
+        # Assure the widget received changes
+        self.assertEqual(self.widget.txtMinAmplitude.text(), "5")
+
+        # Emit new high value
+        self.widget.slider.highValueChanged.emit(45)
+        # Assure the widget received changes
+        self.assertEqual(self.widget.txtMinAmplitude.text(), "45")
+
+    def testOnMapIndexChange(self):
+        '''Test the response to the combo box index change'''
+
+        self.widget.canvas.draw = MagicMock()
+        mpl.colorbar.ColorbarBase = MagicMock()
+
+        # simulate index change
+        self.widget.cbColorMap.setCurrentIndex(1)
+
+        # Check that draw() got called
+        self.assertTrue(self.widget.canvas.draw.called)
+        self.assertTrue(mpl.colorbar.ColorbarBase.called)
+
+    def testOnColorMapReversed(self):
+        '''Test reversing the color map functionality'''
+        # Check the defaults
+        self.assertEqual(self.widget._cmap, "jet")
+        self.widget.cbColorMap.addItems = MagicMock()
+
+        # Reverse the choice
+        self.widget.onColorMapReversed(True)
+
+        # check the behaviour
+        self.assertEqual(self.widget._cmap, "jet_r")
+        self.assertTrue(self.widget.cbColorMap.addItems.called)
+
+    def testOnAmplitudeChange(self):
+        '''Check the callback method for responding to changes in textboxes'''
+        self.widget.canvas.draw = MagicMock()
+        mpl.colors.Normalize = MagicMock()
+        mpl.colorbar.ColorbarBase = MagicMock()
+
+        self.widget.vmin = 0.0
+        self.widget.vmax = 100.0
+
+        # good values in fields
+        self.widget.txtMinAmplitude.setText("1.0")
+        self.widget.txtMaxAmplitude.setText("10.0")
+
+        self.widget.onAmplitudeChange()
+
+        # Check the arguments to Normalize
+        mpl.colors.Normalize.assert_called_with(vmin=1.0, vmax=10.0)
+        self.assertTrue(self.widget.canvas.draw.called)
+
+        # Bad values in fields
+        self.widget.txtMinAmplitude.setText("cake")
+        self.widget.txtMaxAmplitude.setText("more cake")
+
+        self.widget.onAmplitudeChange()
+
+        # Check the arguments to Normalize - should be defaults
+        mpl.colors.Normalize.assert_called_with(vmin=0.0, vmax=100.0)
+        self.assertTrue(self.widget.canvas.draw.called)
+
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/LinearFitTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/LinearFitTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/LinearFitTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,148 @@
+import sys
+import unittest
+import numpy
+
+from PyQt4 import QtGui
+from mock import MagicMock
+
+# set up import paths
+import path_prepare
+
+from sas.sasgui.guiframe.dataFitting import Data1D
+import sas.qtgui.Plotting.Plotter as Plotter
+
+# Local
+from sas.qtgui.Plotting.LinearFit import LinearFit
+
+app = QtGui.QApplication(sys.argv)
+
+class LinearFitTest(unittest.TestCase):
+    '''Test the LinearFit'''
+    def setUp(self):
+        '''Create the LinearFit'''
+        self.data = Data1D(x=[1.0, 2.0, 3.0],
+                           y=[10.0, 11.0, 12.0],
+                           dx=[0.1, 0.2, 0.3],
+                           dy=[0.1, 0.2, 0.3])
+        plotter = Plotter.Plotter(None, quickplot=True)
+        self.widget = LinearFit(parent=plotter, data=self.data, xlabel="log10(x^2)", ylabel="log10(y)")
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtGui.QDialog)
+        self.assertEqual(self.widget.windowTitle(), "Linear Fit")
+        self.assertEqual(self.widget.txtA.text(), "1")
+        self.assertEqual(self.widget.txtB.text(), "1")
+        self.assertEqual(self.widget.txtAerr.text(), "0")
+        self.assertEqual(self.widget.txtBerr.text(), "0")
+
+        self.assertEqual(self.widget.lblRange.text(), "Fit range of log10(x^2)")
+
+    def testFit(self):
+        '''Test the fitting wrapper '''
+        # Catch the update signal
+        self.widget.parent.emit = MagicMock()
+
+        # Set some initial values
+        self.widget.txtRangeMin.setText("1.0")
+        self.widget.txtRangeMax.setText("3.0")
+        self.widget.txtFitRangeMin.setText("1.0")
+        self.widget.txtFitRangeMax.setText("3.0")
+        # Run the fitting
+        self.widget.fit(None)
+        return_values = self.widget.parent.emit.call_args[0][1]
+        # Compare
+        self.assertItemsEqual(return_values[0], [1.0, 3.0])
+        self.assertAlmostEqual(return_values[1][0], 10.004054329, 6)
+        self.assertAlmostEqual(return_values[1][1], 12.030439848, 6)
+
+        # Set the log scale
+        self.widget.x_is_log = True
+        self.widget.fit(None)
+        return_values = self.widget.parent.emit.call_args[0][1]
+        # Compare
+        self.assertItemsEqual(return_values[0], [1.0, 3.0])
+        self.assertAlmostEqual(return_values[1][0], 9.987732937, 6)
+        self.assertAlmostEqual(return_values[1][1], 11.84365082, 6)
+
+    def testOrigData(self):
+        ''' Assure the un-logged data is returned'''
+        # log(x), log(y)
+        self.widget.xminFit, self.widget.xmaxFit = self.widget.range()
+        orig_x = [ 1.,  2.,  3.]
+        orig_y = [1.0, 1.0413926851582251, 1.0791812460476249]
+        orig_dy = [0.01, 0.018181818181818184, 0.024999999999999998]
+        x, y, dy = self.widget.origData()
+
+        self.assertItemsEqual(x, orig_x)
+        self.assertEqual(y[0], orig_y[0])
+        self.assertAlmostEqual(y[1], orig_y[1], 8)
+        self.assertAlmostEqual(y[2], orig_y[2], 8)
+        self.assertEqual(dy[0], orig_dy[0])
+        self.assertAlmostEqual(dy[1], orig_dy[1], 8)
+        self.assertAlmostEqual(dy[2], orig_dy[2], 8)
+
+        # x, y
+        self.widget.x_is_log = False
+        self.widget.y_is_log = False
+        self.widget.xminFit, self.widget.xmaxFit = self.widget.range()
+        orig_x = [ 1.,  2.,  3.]
+        orig_y = [10., 11., 12.]
+        orig_dy = [0.1, 0.2, 0.3]
+        x, y, dy = self.widget.origData()
+
+        self.assertItemsEqual(x, orig_x)
+        self.assertItemsEqual(y, orig_y)
+        self.assertItemsEqual(dy, orig_dy)
+
+        # x, log(y)
+        self.widget.x_is_log = False
+        self.widget.y_is_log = True
+        self.widget.xminFit, self.widget.xmaxFit = self.widget.range()
+        orig_x = [ 1.,  2.,  3.]
+        orig_y = [1.0, 1.0413926851582251, 1.0791812460476249]
+        orig_dy = [0.01, 0.018181818181818184, 0.024999999999999998]
+        x, y, dy = self.widget.origData()
+
+        self.assertItemsEqual(x, orig_x)
+        self.assertEqual(y[0], orig_y[0])
+        self.assertAlmostEqual(y[1], orig_y[1], 8)
+        self.assertAlmostEqual(y[2], orig_y[2], 8)
+        self.assertEqual(dy[0], orig_dy[0])
+        self.assertAlmostEqual(dy[1], orig_dy[1], 8)
+        self.assertAlmostEqual(dy[2], orig_dy[2], 8)
+
+    def testCheckFitValues(self):
+        '''Assure fit values are correct'''
+        # Good values
+        self.assertTrue(self.widget.checkFitValues(self.widget.txtFitRangeMin))
+        # Colors platform dependent
+        #self.assertEqual(self.widget.txtFitRangeMin.palette().color(10).name(), "#f0f0f0")
+        # Bad values
+        self.widget.x_is_log = True
+        self.widget.txtFitRangeMin.setText("-1.0")
+        self.assertFalse(self.widget.checkFitValues(self.widget.txtFitRangeMin))
+       
+
+    def testFloatInvTransform(self):
+        '''Test the helper method for providing conversion function'''
+        self.widget.xLabel="x"
+        self.assertEqual(self.widget.floatInvTransform(5.0), 5.0)
+        self.widget.xLabel="x^(2)"
+        self.assertEqual(self.widget.floatInvTransform(25.0), 5.0)
+        self.widget.xLabel="x^(4)"
+        self.assertEqual(self.widget.floatInvTransform(81.0), 3.0)
+        self.widget.xLabel="log10(x)"
+        self.assertEqual(self.widget.floatInvTransform(2.0), 100.0)
+        self.widget.xLabel="ln(x)"
+        self.assertEqual(self.widget.floatInvTransform(1.0), numpy.exp(1))
+        self.widget.xLabel="log10(x^(4))"
+        self.assertEqual(self.widget.floatInvTransform(4.0), 10.0)
+      
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/PlotHelperTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/PlotHelperTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/PlotHelperTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,54 @@
+import unittest
+
+# Tested module
+import sas.qtgui.Plotting.PlotHelper as PlotHelper
+
+class PlotHelperTest(unittest.TestCase):
+    '''Test the Plot helper functions'''
+    def setUp(self):
+        '''Empty'''
+        pass
+
+    def tearDown(self):
+        '''Empty'''
+        pass
+
+    def testDefaults(self):
+        """ default method variables values """
+        self.assertIsInstance(PlotHelper._plots, dict)
+        self.assertEqual(PlotHelper._plots, {})
+        self.assertEqual(PlotHelper._plot_id, 0)
+
+    def testFunctions(self):
+        """ Adding a plot """
+        plot = "I am a plot. Really."
+        PlotHelper.addPlot(plot)
+        plot_id = PlotHelper.idOfPlot(plot)
+
+        # We can't guarantee unique values for plot_id, as
+        # the tests are executed in random order, so just
+        # make sure we get consecutive values for 2 plots
+        plot2 = "I am also a plot."
+        PlotHelper.addPlot(plot2)
+        plot_id_2 = PlotHelper.idOfPlot(plot2)
+        id1 = int(plot_id[-1])
+        id2 = int(plot_id_2[-1])
+        self.assertEqual(id2 - id1, 1)
+
+        # Other properties
+        #self.assertEqual(PlotHelper.currentPlots(), [plot_id, plot_id_2])
+        self.assertTrue(set(PlotHelper.currentPlots()).issubset([plot_id, plot_id_2]))
+        self.assertEqual(PlotHelper.plotById(plot_id), plot)
+        self.assertEqual(PlotHelper.plotById(plot_id_2), plot2)
+
+        # Delete a graph
+        PlotHelper.deletePlot(plot_id)
+        self.assertEqual(PlotHelper.currentPlots(), [plot_id_2])
+
+        # Add another graph to see the counter
+        plot3 = "Just another plot. Move along."
+        PlotHelper.addPlot(plot3)
+        #self.assertEqual(PlotHelper.idOfPlot(plot3), plot_id_2 + 1)
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/PlotPropertiesTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/PlotPropertiesTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/PlotPropertiesTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,102 @@
+import sys
+import unittest
+from mock import MagicMock
+
+from PyQt4 import QtGui
+
+# set up import paths
+import path_prepare
+
+# Local
+from sas.qtgui.Plotting.PlotProperties import PlotProperties
+
+app = QtGui.QApplication(sys.argv)
+
+class PlotPropertiesTest(unittest.TestCase):
+    '''Test the PlotProperties'''
+    def setUp(self):
+        '''Create the PlotProperties'''
+
+        self.widget = PlotProperties(None,
+                         color=1,
+                         marker=3,
+                         marker_size=10,
+                         legend="LL")
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtGui.QDialog)
+        self.assertEqual(self.widget.windowTitle(), "Modify Plot Properties")
+
+        # Check the combo boxes
+        self.assertEqual(self.widget.cbColor.currentText(), "Green")
+        self.assertEqual(self.widget.cbColor.count(), 7)
+        self.assertEqual(self.widget.cbShape.currentText(), "Triangle Down")
+        self.assertEqual(self.widget.txtLegend.text(), "LL")
+        self.assertEqual(self.widget.sbSize.value(), 10)
+
+    def testDefaultsWithCustomColor(self):
+        '''Test the GUI when called with custom color'''
+        widget = PlotProperties(None,
+                         color="#FF00FF",
+                         marker=7,
+                         marker_size=10,
+                         legend="LL")
+
+        self.assertEqual(widget.cbColor.currentText(), "Custom")
+        self.assertEqual(widget.cbColor.count(), 8)
+        
+    def testOnColorChange(self):
+        '''Test the response to color change event'''
+        # Accept the new color
+        QtGui.QColorDialog.getColor = MagicMock(return_value=QtGui.QColor(255, 0, 255))
+
+        self.widget.onColorChange()
+
+        self.assertEqual(self.widget.color(), "#ff00ff")
+        self.assertTrue(self.widget.custom_color)
+        self.assertEqual(self.widget.cbColor.currentIndex(), 7)
+        self.assertEqual(self.widget.cbColor.currentText(), "Custom")
+
+        # Reset the color - this will remove "Custom" from the combobox
+        # and set its index to "Green"
+        self.widget.cbColor.setCurrentIndex(1)
+        self.assertEqual(self.widget.cbColor.currentText(), "Green")
+
+        # Cancel the dialog now
+        bad_color = QtGui.QColor() # constructs an invalid color
+        QtGui.QColorDialog.getColor = MagicMock(return_value=bad_color)
+        self.widget.onColorChange()
+
+        self.assertEqual(self.widget.color(), 1)
+        self.assertFalse(self.widget.custom_color)
+        self.assertEqual(self.widget.cbColor.currentIndex(), 1)
+        self.assertEqual(self.widget.cbColor.currentText(), "Green")
+
+
+    def testOnColorIndexChange(self):
+        '''Test the response to color index change event'''
+        # Intitial population of the color combo box
+        self.widget.onColorIndexChange()
+        self.assertEqual(self.widget.cbColor.count(), 7)
+        # Block the callback so we can update the cb
+        self.widget.cbColor.blockSignals(True)
+        # Add the Custom entry
+        self.widget.cbColor.addItems(["Custom"])
+        # Unblock the callback
+        self.widget.cbColor.blockSignals(False)
+        # Assert the new CB
+        self.assertEqual(self.widget.cbColor.count(), 8)
+        # Call the method
+        self.widget.onColorIndexChange()
+        # see that the Custom entry disappeared
+        self.assertEqual(self.widget.cbColor.count(), 7)
+        self.assertEqual(self.widget.cbColor.findText("Custom"), -1)
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/PlotUtilitiesTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/PlotUtilitiesTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/PlotUtilitiesTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,46 @@
+import sys
+import unittest
+from collections import OrderedDict
+
+from UnitTesting.TestUtils import WarningTestNotImplemented
+
+# Tested module
+import sas.qtgui.Plotting.PlotUtilities as PlotUtilities
+
+class PlotUtilitiesTest(unittest.TestCase):
+    '''Test the Plot Utilities functions'''
+    def setUp(self):
+        '''Empty'''
+        pass
+
+    def tearDown(self):
+        '''Empty'''
+        pass
+
+    def testDefaults(self):
+        """ default method variables values """
+        self.assertIsInstance(PlotUtilities.SHAPES, OrderedDict)
+        self.assertIsInstance(PlotUtilities.COLORS, OrderedDict)
+
+    def testBuildMatrix(self):
+        """ build matrix for 2d plot from a vector """
+        WarningTestNotImplemented()
+
+    def testGetBins(self):
+        """ test 1d arrays of the index with square binning """
+        WarningTestNotImplemented()
+
+    def testFillupPixels(self):
+        """ test filling z values of the empty cells of 2d image matrix """
+        WarningTestNotImplemented()
+
+    def testRescale(sef):
+        """ test the helper function for step based zooming """
+        WarningTestNotImplemented()
+
+    def testGgetValidColor(self):
+        """ test that the method returns a color understood by MPL """
+        WarningTestNotImplemented()
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/Plotter2DTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/Plotter2DTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/Plotter2DTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,238 @@
+import sys
+import unittest
+import numpy
+
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
+from mock import MagicMock
+from mpl_toolkits.mplot3d import Axes3D
+
+####### TEMP
+import path_prepare
+#######
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+from UnitTesting.TestUtils import WarningTestNotImplemented
+
+# Tested module
+import sas.qtgui.Plotting.Plotter2D as Plotter2D
+
+app = QtGui.QApplication(sys.argv)
+
+class Plotter2DTest(unittest.TestCase):
+    '''Test the Plotter 2D class'''
+    def setUp(self):
+        '''create'''
+        class dummy_manager(object):
+            def communicator(self):
+                return Communicate()
+            def perspective(self):
+                return MyPerspective()
+            def workspace(self):
+                return None
+
+        self.plotter = Plotter2D.Plotter2D(parent=dummy_manager(), quickplot=True)
+
+        self.data = Data2D(image=[0.1]*4,
+                           qx_data=[1.0, 2.0, 3.0, 4.0],
+                           qy_data=[10.0, 11.0, 12.0, 13.0],
+                           dqx_data=[0.1, 0.2, 0.3, 0.4],
+                           dqy_data=[0.1, 0.2, 0.3, 0.4],
+                           q_data=[1,2,3,4],
+                           xmin=-1.0, xmax=5.0,
+                           ymin=-1.0, ymax=15.0,
+                           zmin=-1.0, zmax=20.0)
+
+        self.data.title="Test data"
+        self.data.id = 1
+
+    def tearDown(self):
+        '''destroy'''
+        self.plotter = None
+
+    def testDataProperty(self):
+        """ Adding data """
+        self.plotter.data = self.data
+
+        self.assertEqual(self.plotter.data, self.data)
+        self.assertEqual(self.plotter._title, self.data.title)
+        self.assertEqual(self.plotter.xLabel, "$\\rm{Q_{x}}(A^{-1})$")
+        self.assertEqual(self.plotter.yLabel, "$\\rm{Q_{y}}(A^{-1})$")
+
+    def testPlot(self):
+        """ Look at the plotting """
+        self.plotter.data = self.data
+        self.plotter.show()
+        FigureCanvas.draw_idle = MagicMock()
+
+        self.plotter.plot()
+
+        self.assertTrue(FigureCanvas.draw_idle.called)
+
+    def testCalculateDepth(self):
+        ''' Test the depth calculator '''
+        self.plotter.data = self.data
+
+        # Default, log scale
+        depth = self.plotter.calculateDepth()
+        self.assertEqual(depth, (0.1, 1.e20))
+
+        # Change the scale to linear
+        self.plotter.scale = 'linear'
+        depth = self.plotter.calculateDepth()
+        self.assertEqual(depth[0], -32.)
+        self.assertAlmostEqual(depth[1], 1.30103, 5)
+
+    def testOnColorMap(self):
+        ''' Respond to the color map event '''
+        self.plotter.data = self.data
+        self.plotter.plot()
+        self.plotter.show()
+
+        QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
+
+        # Just this one plot
+        self.plotter.onColorMap()
+
+        # Check that exec_ got called
+        self.assertTrue(QtGui.QDialog.exec_.called)
+
+        self.assertEqual(self.plotter.cmap, "jet")
+        self.assertAlmostEqual(self.plotter.vmin, 0.1, 6)
+        self.assertAlmostEqual(self.plotter.vmax, 1e+20, 6)
+
+    def testOnToggleScale(self):
+        """ Respond to the event by replotting """
+        self.plotter.data = self.data
+        self.plotter.show()
+        FigureCanvas.draw_idle = MagicMock()
+
+        self.plotter.onToggleScale(None)
+
+        self.assertTrue(FigureCanvas.draw_idle.called)
+
+    def testOnBoxSum(self):
+        """ Test the box sum display and functionality """
+
+        # hacky way to make things work in manipulations._sum
+        self.data.detector = [1]
+        self.data.err_data = numpy.array([0.0, 0.0, 0.1, 0.0])
+        self.plotter.data = self.data
+        self.plotter.show()
+
+        # Mock the main window
+        self.plotter.manager.parent = MagicMock()
+
+        # Call the main tested method
+        self.plotter.onBoxSum()
+
+        # Test various properties
+        self.assertIsInstance(self.plotter.slicer.model(), QtGui.QStandardItemModel)
+        self.assertTrue(self.plotter.boxwidget.isVisible())
+        self.assertIsInstance(self.plotter.boxwidget.model, QtGui.QStandardItemModel)
+
+    def testContextMenuQuickPlot(self):
+        """ Test the right click menu """
+        self.plotter.data = self.data
+        self.plotter.createContextMenuQuick()
+        actions = self.plotter.contextMenu.actions()
+        self.assertEqual(len(actions), 7)
+
+        # Trigger Save Image and make sure the method is called
+        self.assertEqual(actions[0].text(), "Save Image")
+        self.plotter.toolbar.save_figure = MagicMock()
+        actions[0].trigger()
+        self.assertTrue(self.plotter.toolbar.save_figure.called)
+
+        # Trigger Print Image and make sure the method is called
+        self.assertEqual(actions[1].text(), "Print Image")
+        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
+        actions[1].trigger()
+        self.assertTrue(QtGui.QPrintDialog.exec_.called)
+
+        # Trigger Copy to Clipboard and make sure the method is called
+        self.assertEqual(actions[2].text(), "Copy to Clipboard")
+
+        # Spy on cliboard's dataChanged() signal
+        self.clipboard_called = False
+        def done():
+            self.clipboard_called = True
+        QtCore.QObject.connect(app.clipboard(), QtCore.SIGNAL("dataChanged()"), done)
+        actions[2].trigger()
+        QtGui.qApp.processEvents()
+        # Make sure clipboard got updated.
+        #self.assertTrue(self.clipboard_called)
+
+        # Trigger Toggle Grid and make sure the method is called
+        self.assertEqual(actions[4].text(), "Toggle Grid On/Off")
+        self.plotter.ax.grid = MagicMock()
+        actions[4].trigger()
+        self.assertTrue(self.plotter.ax.grid.called)
+
+        # Trigger Change Scale and make sure the method is called
+        self.assertEqual(actions[6].text(), "Toggle Linear/Log Scale")
+        FigureCanvas.draw_idle = MagicMock()
+        actions[6].trigger()
+        self.assertTrue(FigureCanvas.draw_idle.called)
+
+    def testShowNoPlot(self):
+        """ Test the plot rendering and generation """
+
+        FigureCanvas.draw_idle = MagicMock()
+        FigureCanvas.draw = MagicMock()
+
+        # Test early return on no data
+        self.plotter.showPlot(data=None,
+                              qx_data=self.data.qx_data,
+                              qy_data=self.data.qy_data,
+                              xmin=self.data.xmin,
+                              xmax=self.data.xmax,
+                              ymin=self.data.ymin, ymax=self.data.ymax,
+                              cmap=None, zmin=None,
+                              zmax=None)
+
+        self.assertFalse(FigureCanvas.draw_idle.called)
+        self.assertFalse(FigureCanvas.draw.called)
+
+    def testShow3DPlot(self):
+        """ Test the 3Dplot rendering and generation """
+        # Test 3D printout
+        FigureCanvas.draw = MagicMock()
+        Axes3D.plot_surface = MagicMock()
+        self.plotter.figure.colorbar = MagicMock()
+
+        self.plotter.dimension = 3
+        self.plotter.data = self.data
+        self.plotter.showPlot(data=self.plotter.data.data,
+                              qx_data=self.data.qx_data,
+                              qy_data=self.data.qy_data,
+                              xmin=self.data.xmin,
+                              xmax=self.data.xmax,
+                              ymin=self.data.ymin, ymax=self.data.ymax,
+                              cmap=None, zmin=None,
+                              zmax=None)
+        self.assertTrue(Axes3D.plot_surface.called)
+        self.assertTrue(FigureCanvas.draw.called)
+
+    def testShow2DPlot(self):
+        """ Test the 2Dplot rendering and generation """
+        # Test 2D printout
+        FigureCanvas.draw_idle = MagicMock()
+        self.plotter.figure.colorbar = MagicMock()
+
+        self.plotter.dimension = 2
+        self.plotter.data = self.data
+        self.plotter.showPlot(data=self.plotter.data.data,
+                              qx_data=self.data.qx_data,
+                              qy_data=self.data.qy_data,
+                              xmin=self.data.xmin,
+                              xmax=self.data.xmax,
+                              ymin=self.data.ymin, ymax=self.data.ymax,
+                              cmap=None, zmin=None,
+                              zmax=None)
+        self.assertTrue(FigureCanvas.draw_idle.called)
+
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/PlotterBaseTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/PlotterBaseTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/PlotterBaseTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,194 @@
+import sys
+import unittest
+from mock import patch, MagicMock
+
+from PyQt4 import QtGui
+import matplotlib.pyplot as plt
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
+from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
+
+####### TEMP
+import path_prepare
+#######
+
+from sas.qtgui.Plotting.ScaleProperties import ScaleProperties
+from sas.qtgui.Plotting.WindowTitle import WindowTitle
+#import sas.qtgui.GuiUtils as GuiUtils
+from sas.qtgui.Utilities.GuiUtils import *
+import sas.qtgui.Plotting.PlotHelper as PlotHelper
+
+# Tested module
+import sas.qtgui.Plotting.PlotterBase as PlotterBase
+
+app = QtGui.QApplication(sys.argv)
+
+class PlotterBaseTest(unittest.TestCase):
+    '''Test the Plotter base class'''
+    def setUp(self):
+        '''create'''
+        class dummy_manager(object):
+            def communicator(self):
+                return Communicate()
+            def perspective(self):
+                return MyPerspective()
+
+        #PlotterBase.PlotterBase.contextMenuQuickPlot = MagicMock()
+        self.plotter = PlotterBase.PlotterBase(None, manager=dummy_manager(), quickplot=True)
+
+    def tearDown(self):
+        '''destroy'''
+        self.plotter = None
+        self.plotter_qp = None
+
+    def testDefaults(self):
+        """ default method variables values """
+        self.assertIsInstance(self.plotter, QtGui.QWidget)
+        self.assertIsInstance(self.plotter.canvas, FigureCanvas)
+        self.assertIsInstance(self.plotter.toolbar, NavigationToolbar)
+        self.assertIsInstance(self.plotter.properties, ScaleProperties)
+
+        self.assertEqual(self.plotter._data, [])
+        self.assertEqual(self.plotter._xscale, 'log')
+        self.assertEqual(self.plotter._yscale, 'log')
+        self.assertEqual(self.plotter.scale, 'linear')
+        self.assertFalse(self.plotter.grid_on)
+        self.assertEqual(self.plotter.x_label, 'log10(x)')
+        self.assertEqual(self.plotter.y_label, 'log10(y)')
+
+    def testData(self):
+        ''' Test the pure virtual method '''
+        with self.assertRaises(NotImplementedError):
+            self.plotter.data=[]
+
+    def testContextMenu(self):
+        ''' Test the default context menu '''
+        with self.assertRaises(NotImplementedError):
+            self.plotter.createContextMenu()
+
+    def testClean(self):
+        ''' test the graph cleanup '''
+        self.plotter.figure.delaxes = MagicMock()
+        self.plotter.clean()
+        self.assertTrue(self.plotter.figure.delaxes.called)
+
+    def testPlot(self):
+        ''' test the pure virtual method '''
+        with self.assertRaises(NotImplementedError):
+            self.plotter.plot()
+
+    def notestOnCloseEvent(self):
+        ''' test the plotter close behaviour '''
+        PlotHelper.deletePlot = MagicMock()
+        self.plotter.closeEvent(None)
+        self.assertTrue(PlotHelper.deletePlot.called)
+
+    def testOnImageSave(self):
+        ''' test the workspace save '''
+        self.plotter.toolbar.save_figure = MagicMock()
+        self.plotter.onImageSave()
+        self.assertTrue(self.plotter.toolbar.save_figure.called)
+
+    def testOnImagePrint(self):
+        ''' test the workspace print '''
+        QtGui.QPainter.end = MagicMock()
+        QtGui.QLabel.render = MagicMock()
+
+        # First, let's cancel printing
+        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
+        self.plotter.onImagePrint()
+        self.assertFalse(QtGui.QPainter.end.called)
+        self.assertFalse(QtGui.QLabel.render.called)
+
+        # Let's print now
+        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
+        self.plotter.onImagePrint()
+        self.assertTrue(QtGui.QPainter.end.called)
+        self.assertTrue(QtGui.QLabel.render.called)
+
+    def testOnClipboardCopy(self):
+        ''' test the workspace screen copy '''
+        QtGui.QClipboard.setPixmap = MagicMock()
+        self.plotter.onClipboardCopy()
+        self.assertTrue(QtGui.QClipboard.setPixmap.called)
+
+    def testOnGridToggle(self):
+        ''' test toggling the grid lines '''
+        # Check the toggle
+        orig_toggle = self.plotter.grid_on
+        
+        FigureCanvas.draw_idle = MagicMock()
+        self.plotter.onGridToggle()
+
+        self.assertTrue(FigureCanvas.draw_idle.called)
+        self.assertTrue(self.plotter.grid_on != orig_toggle)
+
+    def testDefaultContextMenu(self):
+        """ Test the right click default menu """
+
+        self.plotter.defaultContextMenu()
+
+        actions = self.plotter.contextMenu.actions()
+        self.assertEqual(len(actions), 4)
+
+        # Trigger Save Image and make sure the method is called
+        self.assertEqual(actions[0].text(), "Save Image")
+        self.plotter.toolbar.save_figure = MagicMock()
+        actions[0].trigger()
+        self.assertTrue(self.plotter.toolbar.save_figure.called)
+
+        # Trigger Print Image and make sure the method is called
+        self.assertEqual(actions[1].text(), "Print Image")
+        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
+        actions[1].trigger()
+        self.assertTrue(QtGui.QPrintDialog.exec_.called)
+
+        # Trigger Copy to Clipboard and make sure the method is called
+        self.assertEqual(actions[2].text(), "Copy to Clipboard")
+
+        # Spy on cliboard's dataChanged() signal
+        self.clipboard_called = False
+        def done():
+            self.clipboard_called = True
+        QtCore.QObject.connect(app.clipboard(), QtCore.SIGNAL("dataChanged()"), done)
+        actions[2].trigger()
+        QtGui.qApp.processEvents()
+        # Make sure clipboard got updated.
+        self.assertTrue(self.clipboard_called)
+
+    def testOnWindowsTitle(self):
+        """ Test changing the plot title"""
+        # Mock the modal dialog's response
+        QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
+        self.plotter.show()
+        # Assure the original title is none
+        self.assertEqual(self.plotter.windowTitle(), "")
+        self.plotter.manager.communicator = MagicMock()
+
+        WindowTitle.title = MagicMock(return_value="I am a new title")
+        # Change the title
+        self.plotter.onWindowsTitle()
+
+        self.assertEqual(self.plotter.windowTitle(), "I am a new title")
+
+    def testOnMplMouseDown(self):
+        """ Test what happens on mouse click down in chart """
+        pass
+
+    def testOnMplMouseUp(self):
+        """ Test what happens on mouse release in chart """
+        pass
+
+    def testOnMplMouseMotion(self):
+        """ Test what happens on mouse move in chart """
+        pass
+
+    def testOnMplPick(self):
+        """ Test what happens on mouse pick in chart """
+        pass
+
+    def testOnMplWheel(self):
+        """ Test what happens on mouse pick in chart """
+        pass
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/PlotterTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/PlotterTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/PlotterTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,412 @@
+import sys
+import unittest
+
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
+from mock import MagicMock
+from mock import patch
+
+####### TEMP
+import path_prepare
+#######
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+from UnitTesting.TestUtils import WarningTestNotImplemented
+from sas.qtgui.Plotting.LinearFit import LinearFit
+from sas.qtgui.Plotting.PlotProperties import PlotProperties
+
+# Tested module
+import sas.qtgui.Plotting.Plotter as Plotter
+
+app = QtGui.QApplication(sys.argv)
+
+
+class PlotterTest(unittest.TestCase):
+    '''Test the Plotter 1D class'''
+    def setUp(self):
+        '''create'''
+
+        self.plotter = Plotter.Plotter(None, quickplot=True)
+        self.data = Data1D(x=[1.0, 2.0, 3.0],
+                           y=[10.0, 11.0, 12.0],
+                           dx=[0.1, 0.2, 0.3],
+                           dy=[0.1, 0.2, 0.3])
+        self.data.title="Test data"
+        self.data.name="Test name"
+        self.data.id = 1
+
+    def tearDown(self):
+        '''destroy'''
+        self.plotter = None
+
+    def testDataProperty(self):
+        """ Adding data """
+        self.plotter.data = self.data
+
+        self.assertEqual(self.plotter.data, self.data)
+        self.assertEqual(self.plotter._title, self.data.name)
+        self.assertEqual(self.plotter.xLabel, "$()$")
+        self.assertEqual(self.plotter.yLabel, "$()$")
+
+    def testPlotWithErrors(self):
+        """ Look at the plotting with error bars"""
+        self.plotter.data = self.data
+        self.plotter.show()
+        FigureCanvas.draw = MagicMock()
+
+        self.plotter.plot(hide_error=False)
+
+        self.assertEqual(self.plotter.ax.get_xscale(), 'log')
+        self.assertTrue(FigureCanvas.draw.called)
+
+    def testPlotWithoutErrors(self):
+        """ Look at the plotting without error bars"""
+        self.plotter.data = self.data
+        self.plotter.show()
+        FigureCanvas.draw = MagicMock()
+
+        self.plotter.plot(hide_error=True)
+
+        self.assertEqual(self.plotter.ax.get_yscale(), 'log')
+        self.assertTrue(FigureCanvas.draw.called)
+
+    def testCreateContextMenuQuick(self):
+        """ Test the right click menu """
+        self.plotter.createContextMenuQuick()
+        actions = self.plotter.contextMenu.actions()
+        self.assertEqual(len(actions), 7)
+
+        # Trigger Save Image and make sure the method is called
+        self.assertEqual(actions[0].text(), "Save Image")
+        self.plotter.toolbar.save_figure = MagicMock()
+        actions[0].trigger()
+        self.assertTrue(self.plotter.toolbar.save_figure.called)
+
+        # Trigger Print Image and make sure the method is called
+        self.assertEqual(actions[1].text(), "Print Image")
+        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
+        actions[1].trigger()
+        self.assertTrue(QtGui.QPrintDialog.exec_.called)
+
+        # Trigger Copy to Clipboard and make sure the method is called
+        self.assertEqual(actions[2].text(), "Copy to Clipboard")
+
+        # Spy on cliboard's dataChanged() signal
+        self.clipboard_called = False
+        def done():
+            self.clipboard_called = True
+        QtCore.QObject.connect(app.clipboard(), QtCore.SIGNAL("dataChanged()"), done)
+        actions[2].trigger()
+        QtGui.qApp.processEvents()
+        # Make sure clipboard got updated.
+        #self.assertTrue(self.clipboard_called)
+
+        # Trigger Toggle Grid and make sure the method is called
+        self.assertEqual(actions[4].text(), "Toggle Grid On/Off")
+        self.plotter.ax.grid = MagicMock()
+        actions[4].trigger()
+        self.assertTrue(self.plotter.ax.grid.called)
+
+        # Trigger Change Scale and make sure the method is called
+        self.assertEqual(actions[6].text(), "Change Scale")
+        self.plotter.properties.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
+        actions[6].trigger()
+        self.assertTrue(self.plotter.properties.exec_.called)
+
+    def testXyTransform(self):
+        """ Tests the XY transformation and new chart update """
+        self.plotter.plot(self.data)
+
+        # Transform the points
+        self.plotter.xyTransform(xLabel="x", yLabel="log10(y)")
+
+        # Assure new plot has correct labels
+        self.assertEqual(self.plotter.ax.get_xlabel(), "$()$")
+        self.assertEqual(self.plotter.ax.get_ylabel(), "$()$")
+        # ... and scale
+        self.assertEqual(self.plotter.xscale, "linear")
+        self.assertEqual(self.plotter.yscale, "log")
+        # See that just one plot is present
+        self.assertEqual(len(self.plotter.plot_dict), 1)
+        self.assertEqual(len(self.plotter.ax.collections), 1)
+
+    def testAddText(self):
+        """ Checks the functionality of adding text to graph """
+
+        self.plotter.plot(self.data)
+        self.plotter.x_click = 100.0
+        self.plotter.y_click = 100.0
+        # modify the text edit control
+        test_text = "Smoke in cabin"
+        test_font = QtGui.QFont("Arial", 16, QtGui.QFont.Bold)
+        test_color = "#00FF00"
+        self.plotter.addText.textEdit.setText(test_text)
+
+        # Return the requested font parameters
+        self.plotter.addText.font = MagicMock(return_value = test_font)
+        self.plotter.addText.color = MagicMock(return_value = test_color)
+        # Return OK from the dialog
+        self.plotter.addText.exec_ = MagicMock(return_value = QtGui.QDialog.Accepted)
+        # Add text to graph
+        self.plotter.onAddText()
+        self.plotter.show()
+        # Check if the text was added properly
+        self.assertEqual(len(self.plotter.textList), 1)
+        self.assertEqual(self.plotter.textList[0].get_text(), test_text)
+        self.assertEqual(self.plotter.textList[0].get_color(), test_color)
+        self.assertEqual(self.plotter.textList[0].get_fontproperties().get_family()[0], 'Arial')
+        self.assertEqual(self.plotter.textList[0].get_fontproperties().get_size(), 16)
+
+    def testOnRemoveText(self):
+        """ Cheks if annotations can be removed from the graph """
+
+        # Add some text
+        self.plotter.plot(self.data)
+        test_text = "Safety instructions"
+        self.plotter.addText.textEdit.setText(test_text)
+        # Return OK from the dialog
+        self.plotter.addText.exec_ = MagicMock(return_value = QtGui.QDialog.Accepted)
+        # Add text to graph
+        self.plotter.onAddText()
+        self.plotter.show()
+        # Check if the text was added properly
+        self.assertEqual(len(self.plotter.textList), 1)
+
+        # Now, remove the text
+        self.plotter.onRemoveText()
+
+        # And assure no text is displayed
+        self.assertEqual(self.plotter.textList, [])
+
+        # Attempt removal on empty and check
+        self.plotter.onRemoveText()
+        self.assertEqual(self.plotter.textList, [])
+
+    def testOnSetGraphRange(self):
+        """ Cheks if the graph can be resized for range """
+        new_x = (1,2)
+        new_y = (10,11)
+        self.plotter.plot(self.data)
+        self.plotter.show()
+        self.plotter.setRange.exec_ = MagicMock(return_value = QtGui.QDialog.Accepted)
+        self.plotter.setRange.xrange = MagicMock(return_value = new_x)
+        self.plotter.setRange.yrange = MagicMock(return_value = new_y)
+
+        # Call the tested method
+        self.plotter.onSetGraphRange()
+        # See that ranges changed accordingly
+        self.assertEqual(self.plotter.ax.get_xlim(), new_x)
+        self.assertEqual(self.plotter.ax.get_ylim(), new_y)
+
+    def testOnResetGraphRange(self):
+        """ Cheks if the graph can be reset after resizing for range """
+        # New values
+        new_x = (1,2)
+        new_y = (10,11)
+        # define the plot
+        self.plotter.plot(self.data)
+        self.plotter.show()
+
+        # mock setRange methods
+        self.plotter.setRange.exec_ = MagicMock(return_value = QtGui.QDialog.Accepted)
+        self.plotter.setRange.xrange = MagicMock(return_value = new_x)
+        self.plotter.setRange.yrange = MagicMock(return_value = new_y)
+
+        # Change the axes range
+        self.plotter.onSetGraphRange()
+
+        # Now, reset the range back
+        self.plotter.onResetGraphRange()
+
+        # See that ranges are changed
+        self.assertNotEqual(self.plotter.ax.get_xlim(), new_x)
+        self.assertNotEqual(self.plotter.ax.get_ylim(), new_y)
+
+    def testOnLinearFit(self):
+        """ Checks the response to LinearFit call """
+        self.plotter.plot(self.data)
+        self.plotter.show()
+        QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
+
+        # Just this one plot
+        self.assertEqual(len(self.plotter.plot_dict.keys()), 1)
+        self.plotter.onLinearFit(1)
+
+        # Check that exec_ got called
+        self.assertTrue(QtGui.QDialog.exec_.called)
+
+    def testOnRemovePlot(self):
+        """ Assure plots get removed when requested """
+        # Add two plots
+        self.plotter.show()
+        self.plotter.plot(self.data)
+        data2 = Data1D(x=[1.0, 2.0, 3.0],
+                       y=[11.0, 12.0, 13.0],
+                       dx=[0.1, 0.2, 0.3],
+                       dy=[0.1, 0.2, 0.3])
+        data2.title="Test data 2"
+        data2.name="Test name 2"
+        data2.id = 2
+        self.plotter.plot(data2)
+
+        # Assure the plotter window is visible
+        #self.assertTrue(self.plotter.isVisible())
+
+        # Assure we have two sets
+        self.assertEqual(len(self.plotter.plot_dict.keys()), 2)
+
+        # Delete one set
+        self.plotter.onRemovePlot(2)
+        # Assure we have two sets
+        self.assertEqual(len(self.plotter.plot_dict.keys()), 1)
+
+        self.plotter.manager = MagicMock()
+
+        # Delete the remaining set
+        self.plotter.onRemovePlot(1)
+        # Assure we have no plots
+        self.assertEqual(len(self.plotter.plot_dict.keys()), 0)
+        # Assure the plotter window is closed
+        self.assertFalse(self.plotter.isVisible())
+
+
+    def testRemovePlot(self):
+        """ Test plot removal """
+        # Add two plots
+        self.plotter.show()
+        self.plotter.plot(self.data)
+        data2 = Data1D(x=[1.0, 2.0, 3.0],
+                       y=[11.0, 12.0, 13.0],
+                       dx=[0.1, 0.2, 0.3],
+                       dy=[0.1, 0.2, 0.3])
+        data2.title="Test data 2"
+        data2.name="Test name 2"
+        data2.id = 2
+        data2._xaxis = "XAXIS"
+        data2._xunit = "furlong*fortnight^{-1}"
+        data2._yaxis = "YAXIS"
+        data2._yunit = "cake"
+        data2.hide_error = True
+        self.plotter.plot(data2)
+
+        # delete plot 1
+        self.plotter.removePlot(1)
+
+        # See that the labels didn't change
+        xl = self.plotter.ax.xaxis.label.get_text()
+        yl = self.plotter.ax.yaxis.label.get_text()
+        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$")
+        self.assertEqual(yl, "$YAXIS(cake)$")
+        # The hide_error flag should also remain
+        self.assertTrue(self.plotter.plot_dict[2].hide_error)
+
+    def testOnToggleHideError(self):
+        """ Test the error bar toggle on plots """
+        # Add two plots
+        self.plotter.show()
+        self.plotter.plot(self.data)
+        data2 = Data1D(x=[1.0, 2.0, 3.0],
+                       y=[11.0, 12.0, 13.0],
+                       dx=[0.1, 0.2, 0.3],
+                       dy=[0.1, 0.2, 0.3])
+        data2.title="Test data 2"
+        data2.name="Test name 2"
+        data2.id = 2
+        data2._xaxis = "XAXIS"
+        data2._xunit = "furlong*fortnight^{-1}"
+        data2._yaxis = "YAXIS"
+        data2._yunit = "cake"
+        error_status = True
+        data2.hide_error = error_status
+        self.plotter.plot(data2)
+
+        # Reverse the toggle
+        self.plotter.onToggleHideError(2)
+        # See that the labels didn't change
+        xl = self.plotter.ax.xaxis.label.get_text()
+        yl = self.plotter.ax.yaxis.label.get_text()
+        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$")
+        self.assertEqual(yl, "$YAXIS(cake)$")
+        # The hide_error flag should toggle
+        self.assertEqual(self.plotter.plot_dict[2].hide_error, not error_status)
+
+    def testOnFitDisplay(self):
+        """ Test the fit line display on the chart """
+        self.assertIsInstance(self.plotter.fit_result, Data1D)
+        self.assertEqual(self.plotter.fit_result.symbol, 13)
+        self.assertEqual(self.plotter.fit_result.name, "Fit")
+
+        # fudge some init data
+        fit_data = [[0.0,0.0], [5.0,5.0]]
+        # Call the method
+        self.plotter.plot = MagicMock()
+        self.plotter.onFitDisplay(fit_data)
+        self.assertTrue(self.plotter.plot.called)
+        # Look at arguments passed to .plot()
+        self.plotter.plot.assert_called_with(data=self.plotter.fit_result,
+                                             hide_error=True, marker='-')
+
+    def testReplacePlot(self):
+        """ Test the plot refresh functionality """
+        # Add original data
+        self.plotter.show()
+        self.plotter.plot(self.data)
+        # See the default labels
+        xl = self.plotter.ax.xaxis.label.get_text()
+        yl = self.plotter.ax.yaxis.label.get_text()
+        self.assertEqual(xl, "$()$")
+        self.assertEqual(yl, "$()$")
+
+        # Prepare new data
+        data2 = Data1D(x=[1.0, 2.0, 3.0],
+                       y=[11.0, 12.0, 13.0],
+                       dx=[0.1, 0.2, 0.3],
+                       dy=[0.1, 0.2, 0.3])
+        data2.title="Test data 2"
+        data2.name="Test name 2"
+        data2.id = 2
+        data2._xaxis = "XAXIS"
+        data2._xunit = "furlong*fortnight^{-1}"
+        data2._yaxis = "YAXIS"
+        data2._yunit = "cake"
+        error_status = True
+        data2.hide_error = error_status
+
+        # Replace data in plot
+        self.plotter.replacePlot(1, data2)
+
+        # See that the labels changed
+        xl = self.plotter.ax.xaxis.label.get_text()
+        yl = self.plotter.ax.yaxis.label.get_text()
+        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$")
+        self.assertEqual(yl, "$YAXIS(cake)$")
+        # The hide_error flag should be as set
+        self.assertEqual(self.plotter.plot_dict[2].hide_error, error_status)
+
+    def notestOnModifyPlot(self):
+        """ Test the functionality for changing plot properties """
+        # Prepare new data
+        data2 = Data1D(x=[1.0, 2.0, 3.0],
+                       y=[11.0, 12.0, 13.0],
+                       dx=[0.1, 0.2, 0.3],
+                       dy=[0.1, 0.2, 0.3])
+        data2.title="Test data 2"
+        data2.name="Test name 2"
+        data2.id = 2
+        data2.custom_color = None
+        data2.symbol = 1
+        data2.markersize = 11
+
+        self.plotter.plot(data2)
+
+        with patch('sas.qtgui.Plotting.PlotProperties.PlotProperties') as mock:
+            instance = mock.return_value
+            QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
+            instance.symbol.return_value = 7
+
+            self.plotter.onModifyPlot(2)
+
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/ScalePropertiesTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/ScalePropertiesTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/ScalePropertiesTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,60 @@
+import sys
+import unittest
+
+from PyQt4 import QtGui
+
+# set up import paths
+import sas.qtgui.path_prepare
+
+# Local
+from sas.qtgui.Plotting.ScaleProperties import ScaleProperties
+
+app = QtGui.QApplication(sys.argv)
+
+class ScalePropertiesTest(unittest.TestCase):
+    '''Test the ScaleProperties'''
+    def setUp(self):
+        '''Create the ScaleProperties'''
+
+        self.widget = ScaleProperties(None)
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtGui.QDialog)
+        self.assertEqual(self.widget.windowTitle(), "Scale Properties")
+        self.assertEqual(self.widget.cbX.count(), 6)
+        self.assertEqual(self.widget.cbY.count(), 12)
+        self.assertEqual(self.widget.cbView.count(), 6)
+        
+    def testGetValues(self):
+        '''Test the values returned'''
+        self.assertEqual(self.widget.getValues(), ("x", "y"))
+        self.widget.cbX.setCurrentIndex(2)
+        self.widget.cbY.setCurrentIndex(4)
+        self.assertEqual(self.widget.getValues(), ("x^(4)", "y*x^(2)"))
+
+    def testSettingView(self):
+        '''Test various settings of view'''
+        self.widget.cbView.setCurrentIndex(1)
+        self.assertEqual(self.widget.getValues(), ("x", "y"))
+        self.widget.cbView.setCurrentIndex(5)
+        self.assertEqual(self.widget.getValues(), ("x", "y*x^(2)"))
+
+        # Assure the View combobox resets on the x index changes
+        self.assertNotEqual(self.widget.cbView.currentIndex(), 0)
+        self.widget.cbX.setCurrentIndex(2)
+        self.assertEqual(self.widget.cbView.currentIndex(), 0)
+
+        # Same for Y
+        self.widget.cbView.setCurrentIndex(6)
+        self.assertNotEqual(self.widget.cbView.currentIndex(), 0)
+        self.widget.cbY.setCurrentIndex(2)
+        self.assertEqual(self.widget.cbView.currentIndex(), 0)
+      
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/SetGraphRangeTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/SetGraphRangeTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/SetGraphRangeTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,56 @@
+import sys
+import unittest
+
+from PyQt4 import QtGui
+
+# set up import paths
+import sas.qtgui.path_prepare
+
+# Local
+from sas.qtgui.Plotting.SetGraphRange import SetGraphRange
+
+app = QtGui.QApplication(sys.argv)
+
+class SetGraphRangeTest(unittest.TestCase):
+    '''Test the SetGraphRange'''
+    def setUp(self):
+        '''Create the SetGraphRange'''
+
+        self.widget = SetGraphRange(None)
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtGui.QDialog)
+        self.assertEqual(self.widget.windowTitle(), "Set Graph Range")
+        self.assertIsInstance(self.widget.txtXmin, QtGui.QLineEdit)
+        self.assertIsInstance(self.widget.txtXmin.validator(), QtGui.QDoubleValidator)
+        
+    def testGoodRanges(self):
+        '''Test the X range values set by caller''' 
+        self.assertEqual(self.widget.xrange(), (0.0, 0.0))
+        self.assertEqual(self.widget.yrange(), (0.0, 0.0))
+
+        new_widget = SetGraphRange(None, ("1.0", 2.0), (8.0, "-2"))
+        self.assertEqual(new_widget.xrange(), (1.0, 2.0))
+        self.assertEqual(new_widget.yrange(), (8.0, -2.0))
+
+
+    def testBadRanges(self):
+        '''Test the incorrect X range values set by caller'''
+        with self.assertRaises(ValueError):
+            new_widget = SetGraphRange(None, ("1.0", "aa"), (None, "@"))
+            self.assertEqual(new_widget.xrange(), (1.0, 0.0))
+            self.assertEqual(new_widget.yrange(), (0.0, 0.0))
+
+        with self.assertRaises(AssertionError):
+            new_widget = SetGraphRange(None, "I'm a tuple", None)
+            self.assertEqual(new_widget.xrange(), (1.0, 0.0))
+            self.assertEqual(new_widget.yrange(), (0.0, 0.0))
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/SlicerModelTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/SlicerModelTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/SlicerModelTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,77 @@
+import sys
+import unittest
+from mock import MagicMock
+
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+
+# set up import paths
+import sas.qtgui.path_prepare
+
+# Local
+from sas.qtgui.Plotting.SlicerModel import SlicerModel
+
+app = QtGui.QApplication(sys.argv)
+
+class SlicerModelTest(unittest.TestCase):
+    '''Test the SlicerModel'''
+    def setUp(self):
+        '''Create the SlicerModel'''
+        class SModel(SlicerModel):
+            params = {"a":1, "b":2}
+            def __init__(self):
+                SlicerModel.__init__(self)
+            def getParams(self):
+                return self.params
+            def setParams(self, par):
+                self.params = par
+        self.model = SModel()
+
+    def tearDown(self):
+        '''Destroy the model'''
+        self.model = None
+
+    def testBaseClass(self):
+        '''Assure that SlicerModel contains pure virtuals'''
+        model = SlicerModel()
+        with self.assertRaises(NotImplementedError):
+            model.setParams()
+        with self.assertRaises(NotImplementedError):
+            model.setModelFromParams()
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.model.model(), QtGui.QStandardItemModel)
+
+    def testSetModelFromParams(self):
+        '''Test the model update'''
+        # Add a row to params
+        new_dict = self.model.getParams()
+        new_dict["c"] = 3
+        self.model.setParams(new_dict)
+
+        # Call the update
+        self.model.setModelFromParams()
+
+        # Check the new model.
+        self.assertEqual(self.model.model().rowCount(), 3)
+        self.assertEqual(self.model.model().columnCount(), 2)
+
+    def testSetParamsFromModel(self):
+        ''' Test the parameters update'''
+        # First - the default model
+        self.model.setModelFromParams()
+        self.assertEqual(self.model.model().rowCount(), 2)
+        self.assertEqual(self.model.model().columnCount(), 2)
+
+        # Add a row
+        item1 = QtGui.QStandardItem("c")
+        item2 = QtGui.QStandardItem(3)
+        self.model.model().appendRow([item1, item2])
+        # Check the new model. The update should be automatic
+        self.assertEqual(self.model.model().rowCount(), 3)
+        self.assertEqual(self.model.model().columnCount(), 2)
+
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/SlicerParametersTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/SlicerParametersTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/SlicerParametersTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,110 @@
+import sys
+import unittest
+from mock import MagicMock
+
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+from PyQt4 import QtTest
+from PyQt4 import QtWebKit
+
+from mock import MagicMock
+
+# set up import paths
+import sas.qtgui.path_prepare
+
+from sas.qtgui.UnitTesting.TestUtils import QtSignalSpy
+
+# Local
+from sas.qtgui.Plotting.SlicerParameters import SlicerParameters
+
+app = QtGui.QApplication(sys.argv)
+
+class SlicerParametersTest(unittest.TestCase):
+    '''Test the SlicerParameters dialog'''
+    def setUp(self):
+        '''Create the SlicerParameters dialog'''
+
+        item1 = QtGui.QStandardItem("dromekage")
+        item2 = QtGui.QStandardItem("999.0")
+        self.model = QtGui.QStandardItemModel()
+        self.model.appendRow([item1, item2])
+        self.widget = SlicerParameters(model=self.model)
+
+    def tearDown(self):
+        '''Destroy the model'''
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        #self.widget.mapper
+        self.assertIsInstance(self.widget.proxy, QtGui.QIdentityProxyModel)
+        self.assertIsInstance(self.widget.lstParams.itemDelegate(), QtGui.QStyledItemDelegate)
+        self.assertTrue(self.widget.lstParams.model().columnReadOnly(0))
+        self.assertFalse(self.widget.lstParams.model().columnReadOnly(1))
+
+        # Test the proxy model
+        self.assertEqual(self.widget.lstParams.model(), self.widget.proxy)
+        self.assertEqual(self.widget.proxy.columnCount(), 2)
+        self.assertEqual(self.widget.proxy.rowCount(), 1)
+        self.assertEqual(self.widget.model.item(0,0).text(), 'dromekage')
+        self.assertEqual(self.widget.model.item(0,1).text(), '999.0')
+
+        # Check the flags in the proxy model
+        flags = self.widget.proxy.flags(self.widget.proxy.index(0,0))
+        self.assertFalse(flags & QtCore.Qt.ItemIsEditable)
+        self.assertTrue(flags & QtCore.Qt.ItemIsSelectable)
+        self.assertTrue(flags & QtCore.Qt.ItemIsEnabled)
+
+    def testClose(self):
+        ''' Assure that clicking on Close triggers right behaviour'''
+        self.widget.show()
+
+        # Set up the spy
+        spy_close = QtSignalSpy(self.widget, self.widget.close_signal)
+        # Click on the "Close" button
+        QtTest.QTest.mouseClick(self.widget.buttonBox.button(QtGui.QDialogButtonBox.Close), QtCore.Qt.LeftButton)
+        # Check the signal
+        self.assertEqual(spy_close.count(), 1)
+        # Assure the window got closed
+        self.assertFalse(self.widget.isVisible())
+
+    def testOnHelp(self):
+        ''' Assure clicking on help returns QtWeb view on requested page'''
+        self.widget.show()
+
+        #Mock the QWebView method
+        QtWebKit.QWebView.show = MagicMock()
+        QtWebKit.QWebView.load = MagicMock()
+
+        # Invoke the action
+        self.widget.onHelp()
+
+        # Check if show() got called
+        self.assertTrue(QtWebKit.QWebView.show.called)
+
+        # Assure the filename is correct
+        self.assertIn("graph_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
+        
+    def testSetModel(self):
+        ''' Test if resetting the model works'''
+        
+        item1 = QtGui.QStandardItem("s1")
+        item2 = QtGui.QStandardItem("5.0")
+        new_model = QtGui.QStandardItemModel()
+        new_model.appendRow([item1, item2])
+        item1 = QtGui.QStandardItem("s2")
+        item2 = QtGui.QStandardItem("20.0")
+        new_model.appendRow([item1, item2])
+        # Force the new model onto the widget
+        self.widget.setModel(model=new_model)
+
+        # Test if the widget got it
+        self.assertEqual(self.widget.model.columnCount(), 2)
+        self.assertEqual(self.widget.model.rowCount(), 2)
+        self.assertEqual(self.widget.model.item(0,0).text(), 's1')
+        self.assertEqual(self.widget.model.item(1,0).text(), 's2')
+
+
+        
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/UnitTesting/WindowTitleTest.py
===================================================================
--- src/sas/qtgui/Plotting/UnitTesting/WindowTitleTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/UnitTesting/WindowTitleTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,47 @@
+import sys
+import unittest
+
+from PyQt4 import QtGui
+
+# set up import paths
+import sas.qtgui.path_prepare
+
+# Local
+from sas.qtgui.Plotting.WindowTitle import WindowTitle
+
+app = QtGui.QApplication(sys.argv)
+
+class WindowTitleTest(unittest.TestCase):
+    '''Test the WindowTitle'''
+    def setUp(self):
+        '''Create the WindowTitle'''
+        self.widget = WindowTitle(None, new_title="some title")
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.widget.show()
+        self.assertIsInstance(self.widget, QtGui.QDialog)
+        self.assertEqual(self.widget.windowTitle(), "Modify Window Title")
+        
+    def testTitle(self):
+        '''Modify the title'''
+        self.widget.show()
+        app.processEvents()
+        # make sure we have the pre-set title
+        self.assertEqual(self.widget.txtTitle.text(), "some title")
+        # Clear the control and set it to something else
+        self.widget.txtTitle.clear()
+        self.widget.txtTitle.setText("5 elephants")
+        app.processEvents()
+        # Retrieve value
+        new_title = self.widget.title()
+        # Check
+        self.assertEqual(new_title, "5 elephants")
+       
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/Plotting/WindowTitle.py
===================================================================
--- src/sas/qtgui/Plotting/WindowTitle.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/WindowTitle.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,19 @@
+"""
+Allows users to change the title of the current graph
+from "Graph_n" to any ASCII text.
+"""
+from PyQt4 import QtGui
+
+from sas.qtgui.Plotting.UI.WindowTitleUI import Ui_WindowTitle
+
+class WindowTitle(QtGui.QDialog, Ui_WindowTitle):
+    """ Simple GUI for a single line text query """
+    def __init__(self, parent=None, new_title=""):
+        super(WindowTitle, self).__init__(parent)
+        self.setupUi(self)
+        self.txtTitle.setText(new_title)
+
+    def title(self):
+        """ Return the new title """
+        return self.txtTitle.text()
+
Index: src/sas/qtgui/Plotting/rangeSlider.py
===================================================================
--- src/sas/qtgui/Plotting/rangeSlider.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Plotting/rangeSlider.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,294 @@
+# -*- coding: utf-8 -*-
+
+"""
+/***************************************************************************
+Name                 : RangeSlider
+Description          : A slider for ranges
+Date                 : Jun 20, 2012 
+copyright            : (C) 2012 by Giuseppe Sucameli
+email                : brush.tyler@gmail.com
+
+the code is based on RangeSlider by phil
+(see https://svn.enthought.com/enthought/browser/TraitsBackendQt/trunk/enthought/traits/ui/qt4/extra/range_slider.py) licensed under GPLv2
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+"""
+
+from PyQt4 import QtGui, QtCore
+
+class RangeSlider(QtGui.QSlider):
+    """ A slider for ranges.
+    
+        This class provides a dual-slider for ranges, where there is a defined
+        maximum and minimum, as is a normal slider, but instead of having a
+        single slider value, there are 2 slider values.
+        
+        This class emits the same signals as the QSlider base class, with the 
+        exception of valueChanged. 
+
+        In addition, two new signals are emitted to catch the movement of 
+        each handle, lowValueChanged(int) and highValueChanged(int).
+    """
+    highValueChanged = QtCore.pyqtSignal(int)
+    lowValueChanged = QtCore.pyqtSignal(int)
+    def __init__(self, *args):
+        super(RangeSlider, self).__init__(*args)
+
+        self._low = self.minimum()
+        self._high = self.maximum()
+        
+        self.pressed_control = QtGui.QStyle.SC_None
+        self.hover_control = QtGui.QStyle.SC_None
+        self.click_offset = 0
+        
+        # -1 for the low, 1 for the high, 0 for both
+        self.active_slider = -1
+
+    def lowValue(self):
+        return self._low
+
+    def setLowValue(self, low):
+        if low < self.minimum():
+            low = self.minimum()
+        if low == self._low:
+            return
+
+        self._low = low
+        self.update()
+
+        if self.hasTracking():
+            self.lowValueChanged.emit(self._low)
+
+    def highValue(self):
+        return self._high
+
+    def setHighValue(self, high):
+        if high > self.maximum():
+            high = self.maximum()
+        if high == self._high:
+            return
+
+        self._high = high
+        self.update()
+
+        if self.hasTracking():
+            self.lowValueChanged.emit(self._high)
+        
+    def paintEvent(self, event):
+        # based on http://qt.gitorious.org/qt/qt/blobs/master/src/gui/widgets/qslider.cpp
+
+        painter = QtGui.QPainter(self)
+        style = QtGui.QApplication.style() 
+
+        for i, value in enumerate([self._low, self._high]):
+            opt = QtGui.QStyleOptionSlider()
+            self.initStyleOption(opt)
+
+            gr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderGroove, self)
+            sr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderHandle, self)
+
+            if self.orientation() == QtCore.Qt.Horizontal:
+                handle_length = sr.width()
+                slider_length = gr.width()
+                slider_min = gr.x()
+                slider_max = gr.right() - handle_length + 1
+            else:
+                handle_length = sr.height()
+                slider_length = gr.height()
+                slider_min = gr.y()
+                slider_max = gr.bottom() - handle_length + 1
+
+            opt.subControls = QtGui.QStyle.SC_SliderGroove | QtGui.QStyle.SC_SliderHandle
+
+            # draw the first slider with inverted appearance, then the second 
+            # slider drawn on top of the existing ones
+            if i == 0:
+                if self.orientation() == QtCore.Qt.Horizontal:
+                    opt.upsideDown = not self.invertedAppearance()
+                else:
+                    opt.upsideDown = self.invertedAppearance()
+
+                if self.orientation() == QtCore.Qt.Horizontal:
+                    opt.sliderValue = value - self.minimum()
+                    opt.sliderPosition = self.minimum() + (self.maximum() - value)
+
+                    opt.rect.setX(slider_min)
+                    opt.rect.setWidth(slider_length)
+
+                else:
+                    opt.rect.setY(slider_min)
+                    opt.rect.setHeight(slider_length)
+
+            else:
+                # do not highlight the second part when has focus to avoid 
+                # drawing of partially overlapped semi-transparent backgrounds
+                opt.state &= ~QtGui.QStyle.State_HasFocus
+
+                opt.sliderValue = 0
+                opt.sliderPosition = self.minimum()
+
+                if self.orientation() == QtCore.Qt.Horizontal:
+                    opt.upsideDown = self.invertedAppearance()
+
+                    pos = style.sliderPositionFromValue(0, self.maximum()-self.minimum(),
+                                             value-self.minimum(), slider_max - slider_min - 4,
+                                             opt.upsideDown)
+
+                    opt.rect.setX(pos + 3)
+                    opt.rect.setWidth(slider_max - pos + handle_length - 3)
+
+                else:
+                    opt.upsideDown = not self.invertedAppearance()
+
+                    pos = style.sliderPositionFromValue(0, self.maximum()-self.minimum(),
+                                             self.maximum()-value, slider_max - slider_min - 4,
+                                             opt.upsideDown)
+
+                    opt.rect.setY(slider_min-1)
+                    opt.rect.setHeight(slider_min + slider_length - pos - 2)
+
+            if self.tickPosition() != self.NoTicks:
+                opt.subControls |= QtGui.QStyle.SC_SliderTickmarks
+
+            if self.pressed_control:
+                opt.activeSubControls = self.pressed_control
+                opt.state |= QtGui.QStyle.State_Sunken
+            else:
+                opt.activeSubControls = self.hover_control
+
+            style.drawComplexControl(QtGui.QStyle.CC_Slider, opt, painter, self)
+            
+        
+    def mousePressEvent(self, event):
+        event.accept()
+        
+        style = QtGui.QApplication.style()
+        button = event.button()
+        
+        # In a normal slider control, when the user clicks on a point in the 
+        # slider's total range, but not on the slider part of the control the
+        # control would jump the slider value to where the user clicked.
+        # For this control, clicks which are not direct hits will slide both
+        # slider parts
+                
+        if button:
+            opt = QtGui.QStyleOptionSlider()
+            self.initStyleOption(opt)
+
+            self.active_slider = 0
+            mid = (self.maximum() - self.minimum()) / 2.0
+            
+            for i, value in enumerate([self._low, self._high]):
+                opt.sliderPosition = value
+                hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(), self)
+
+                if hit == style.SC_SliderHandle:
+                    self.pressed_control = hit
+
+                    # if both handles are close together, avoid locks 
+                    # choosing the one with more empty space near it
+                    if self._low + 2 >= self._high:
+                        self.active_slider = 1 if self._high < mid else -1
+                    else:
+                        self.active_slider = -1 if i == 0 else 1
+                    self.triggerAction(self.SliderMove)
+                    self.setRepeatAction(self.SliderNoAction)
+                    self.setSliderDown(True)
+                    break
+
+            if self.active_slider == 0:
+                self.pressed_control = QtGui.QStyle.SC_SliderHandle
+                self.click_offset = self.__pixelPosToRangeValue(self.__pick(event.pos()))
+                self.triggerAction(self.SliderMove)
+                self.setRepeatAction(self.SliderNoAction)
+                self.setSliderDown(True)
+        else:
+            event.ignore()
+
+    def mouseReleaseEvent(self, event):
+        if self.pressed_control != QtGui.QStyle.SC_SliderHandle:
+            event.ignore()
+            return
+
+        self.setSliderDown(False)
+        return QtGui.QSlider.mouseReleaseEvent(self, event)
+                                
+    def mouseMoveEvent(self, event):
+        if self.pressed_control != QtGui.QStyle.SC_SliderHandle:
+            event.ignore()
+            return
+        
+        event.accept()
+        new_pos = self.__pixelPosToRangeValue(self.__pick(event.pos()))
+        opt = QtGui.QStyleOptionSlider()
+        self.initStyleOption(opt)
+
+        old_click_offset = self.click_offset
+        self.click_offset = new_pos
+        
+        if self.active_slider == 0:
+            offset = new_pos - old_click_offset
+            new_low = self._low + offset
+            new_high = self._high + offset
+
+            if new_low < self.minimum():
+                diff = self.minimum() - new_low
+                new_low += diff
+                new_high += diff
+            if new_high > self.maximum():
+                diff = self.maximum() - new_high
+                new_low += diff
+                new_high += diff
+
+            self.setLowValue( new_low )
+            self.setHighValue( new_high )
+
+        elif self.active_slider < 0:
+            if new_pos > self._high:
+                new_pos = self._high
+            self.setLowValue( new_pos )
+
+        else:
+            if new_pos < self._low:
+                new_pos = self._low
+            self.setHighValue( new_pos )
+
+        if self.hasTracking():
+            self.emit(QtCore.SIGNAL('sliderMoved(int)'), new_pos)
+
+            
+    def __pick(self, pt):
+        if self.orientation() == QtCore.Qt.Horizontal:
+            return pt.x()
+        else:
+            return pt.y()
+           
+           
+    def __pixelPosToRangeValue(self, pos):
+        opt = QtGui.QStyleOptionSlider()
+        self.initStyleOption(opt)
+        style = QtGui.QApplication.style()
+        
+        gr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderGroove, self)
+        sr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderHandle, self)
+        
+        if self.orientation() == QtCore.Qt.Horizontal:
+            handle_length = sr.width()
+            slider_min = gr.x() + handle_length/2
+            slider_max = gr.right() - handle_length/2 + 1
+        else:
+            handle_length = sr.height()
+            slider_min = gr.y() + handle_length/2
+            slider_max = gr.bottom() - handle_length/2 + 1
+            
+        return self.minimum() + style.sliderValueFromPosition(0, self.maximum()-self.minimum(),
+                                            pos-slider_min, slider_max - slider_min,
+                                            opt.upsideDown)
Index: src/sas/qtgui/README.rst
===================================================================
--- src/sas/qtgui/README.rst	(revision fb0679bf34679f3a093199d30775fac384ef6ea0)
+++ src/sas/qtgui/README.rst	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -8,15 +8,10 @@
 Compile UI resources first:
 
-in shell (Linux, OSX, Cygwin):
-
-    ./make_ui.sh
-
-or in windows cmd window
-
-    make_ui.bat 
+    cd src/sas/qtgui
+    python convertUI.py
 
 Run the GUI with:
 
-    python MainWindow.py
+    python run.py
 
 
@@ -25,12 +20,8 @@
 ------------
 
-Unit testing suite can be run with either
+Unit testing suite can be run with
 
      python GUITesting.py
 
-or
-
-     ./run_tests.sh 
-     run_tests.bat
 
 Requirements
Index: c/sas/qtgui/SasviewLogger.py
===================================================================
--- src/sas/qtgui/SasviewLogger.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,62 +1,0 @@
-import os
-import sys
-import logging
-
-from PyQt4 import QtCore
-
-
-class XStream(QtCore.QObject):
-    _stdout = None
-    _stderr = None
-    messageWritten = QtCore.pyqtSignal(str)
-
-    def flush(self):
-        pass
-
-    def fileno(self):
-        return -1
-
-    def write(self, msg):
-        if(not self.signalsBlocked()):
-            self.messageWritten.emit(unicode(msg))
-
-    @staticmethod
-    def stdout():
-        if(not XStream._stdout):
-            XStream._stdout = XStream()
-            sys.stdout = XStream._stdout
-        return XStream._stdout
-
-    @staticmethod
-    def stderr():
-        if(not XStream._stderr):
-            XStream._stderr = XStream()
-            sys.stderr = XStream._stderr
-        return XStream._stderr
-
-class QtHandler(logging.Handler):
-    """
-    Version of logging handler
-    "emitting" the message to custom stdout()
-    """
-    def __init__(self):
-        logging.Handler.__init__(self)
-
-    def emit(self, record):
-        record = self.format(record)
-        if record:
-            XStream.stdout().write('%s\n'%record)
-
-
-# Define the default logger
-logger = logging.getLogger()
-
-# Add the file handler
-logging.basicConfig(level=logging.INFO,
-                    format='%(asctime)s %(levelname)s %(message)s',
-                    filename=os.path.join(os.path.expanduser("~"),
-                                          'sasview.log'))
-# Add the qt-signal logger
-handler = QtHandler()
-handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
-logger.addHandler(handler)
Index: c/sas/qtgui/ScaleProperties.py
===================================================================
--- src/sas/qtgui/ScaleProperties.py	(revision fed94a2715dc183e26bc1dfd2691e7802cc69313)
+++ 	(revision )
@@ -1,70 +1,0 @@
-from PyQt4 import QtGui
-
-import sas.sasview
-
-from sas.qtgui.UI.ScalePropertiesUI import Ui_scalePropertiesUI
-
-x_values = ["x", "x^(2)", "x^(4)", "ln(x)", "log10(x)", "log10(x^(4))"]
-y_values = ["y", "1/y", "ln(y)", "y^(2)", "y*x^(2)", "y*x^(4)", "1/sqrt(y)",
-            "log10(y)", "ln(y*x)", "ln(y*x^(2))", "ln(y*x^(4))", "log10(y*x^(4))"]
-view_values = ["--", "Linear y vs x", "Guinier lny vs x^(2)",
-            "XS Guinier ln(y*x) vs x^(2)", "Porod y*x^(4) vs x^(4)", "Kratky y*x^(2) vs x"]
-view_to_xy = {
-    view_values[0]: [None, None], # custom
-    view_values[1]: [0, 0], # linear
-    view_values[2]: [1, 2], # Guinier
-    view_values[3]: [1, 8], # XS Guinier
-    view_values[4]: [2, 5], # Porod
-    view_values[5]: [0, 4], # Kratky
-}
-class ScaleProperties(QtGui.QDialog, Ui_scalePropertiesUI):
-    def __init__(self, parent=None, init_scale_x='x', init_scale_y='y'):
-        super(ScaleProperties, self).__init__(parent)
-        self.setupUi(self)
-
-        # Set up comboboxes
-        self.cbX.addItems(x_values)
-        self.cbY.addItems(y_values)
-        self.cbView.addItems(view_values)
-        # Resize the dialog only AFTER the boxes are populated
-        self.setFixedSize(self.minimumSizeHint())
-
-        # Set up the initial values for x and y.
-        # This avoids keeping a QModel instance here.
-        if init_scale_x in x_values and init_scale_y in y_values:
-            self.cbX.setCurrentIndex(x_values.index(init_scale_x))
-            self.cbY.setCurrentIndex(y_values.index(init_scale_y))
-
-        # Connect combobox index change to a custom method
-        self.cbView.currentIndexChanged.connect(self.viewIndexChanged)
-        self.cbX.currentIndexChanged.connect(self.xyIndexChanged)
-        self.cbY.currentIndexChanged.connect(self.xyIndexChanged)
-
-    def getValues(self):
-        """
-        Return current values from comboboxes
-        """
-        return str(self.cbX.currentText()), str(self.cbY.currentText())
-
-    def viewIndexChanged(self, index):
-        """
-        Update X and Y labels based on the "View" index
-        """
-        if index > 0:
-            # Disable signals so xyIndexChanged() doesn't get called
-            self.cbX.blockSignals(True)
-            self.cbY.blockSignals(True)
-
-            # Update the sub-controls
-            self.cbX.setCurrentIndex(view_to_xy[view_values[index]][0])
-            self.cbY.setCurrentIndex(view_to_xy[view_values[index]][1])
-            # Re-enable the signals
-
-            self.cbX.blockSignals(False)
-            self.cbY.blockSignals(False)
-
-    def xyIndexChanged(self, index):
-        """
-        Update View label based on the "X" and "Y" index
-        """
-        self.cbView.setCurrentIndex(0)
Index: c/sas/qtgui/SetGraphRange.py
===================================================================
--- src/sas/qtgui/SetGraphRange.py	(revision d3ca36332a95a5caf23ee8f8223a9c9912826726)
+++ 	(revision )
@@ -1,39 +1,0 @@
-"""
-Allows users to change the range of the current graph
-"""
-from PyQt4 import QtGui
-
-# Local UI
-from sas.qtgui.UI.SetGraphRangeUI import Ui_setGraphRangeUI
-
-class SetGraphRange(QtGui.QDialog, Ui_setGraphRangeUI):
-    def __init__(self, parent=None, x_range=(0.0, 0.0), y_range=(0.0, 0.0)):
-        super(SetGraphRange, self).__init__()
-
-        self.setupUi(self)
-        assert(isinstance(x_range, tuple))
-        assert(isinstance(y_range, tuple))
-
-        self.txtXmin.setValidator(QtGui.QDoubleValidator())
-        self.txtXmax.setValidator(QtGui.QDoubleValidator())
-        self.txtYmin.setValidator(QtGui.QDoubleValidator())
-        self.txtYmax.setValidator(QtGui.QDoubleValidator())
-
-        self.txtXmin.setText(str(x_range[0]))
-        self.txtXmax.setText(str(x_range[1]))
-        self.txtYmin.setText(str(y_range[0]))
-        self.txtYmax.setText(str(y_range[1]))
-
-    def xrange(self):
-        """
-        Return a tuple with line edit content of (xmin, xmax)
-        """
-        return (float(self.txtXmin.text()),
-                float(self.txtXmax.text()))
-
-    def yrange(self):
-        """
-        Return a tuple with line edit content of (ymin, ymax)
-        """
-        return (float(self.txtYmin.text()),
-                float(self.txtYmax.text()))
Index: c/sas/qtgui/SldPanel.py
===================================================================
--- src/sas/qtgui/SldPanel.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,224 +1,0 @@
-# global
-import logging
-from PyQt4 import QtGui, QtCore
-
-from periodictable import formula as Formula
-from periodictable.xsf import xray_energy, xray_sld_from_atoms
-from periodictable.nsf import neutron_scattering
-
-from sas.qtgui.GuiUtils import FormulaValidator
-
-# Local UI
-from sas.qtgui.UI.SldPanel import Ui_SldPanel
-
-def enum(*sequential, **named):
-    enums = dict(zip(sequential, range(len(sequential))), **named)
-    return type('Enum', (), enums)
-
-MODEL = enum(
-    'MOLECULAR_FORMULA',
-    'MASS_DENSITY',
-    'WAVELENGTH',
-    'NEUTRON_SLD_REAL',
-    'NEUTRON_SLD_IMAG',
-    'CU_KA_SLD_REAL',
-    'CU_KA_SLD_IMAG',
-    'MO_KA_SLD_REAL',
-    'MO_KA_SLD_IMAG',
-    'NEUTRON_INC_XS',
-    'NEUTRON_ABS_XS',
-    'NEUTRON_LENGTH',
-)
-
-class SldResult(object):
-    def __init__(self, molecular_formula, mass_density, wavelength,
-        neutron_sld_real, neutron_sld_imag,
-        cu_ka_sld_real, cu_ka_sld_imag,
-        mo_ka_sld_real, mo_ka_sld_imag,
-        neutron_inc_xs, neutron_abs_xs, neutron_length):
-
-        self.molecular_formula = molecular_formula
-        self.mass_density = mass_density
-        self.wavelength = wavelength
-        self.neutron_sld_real = neutron_sld_real
-        self.neutron_sld_imag = neutron_sld_imag
-        self.cu_ka_sld_real = cu_ka_sld_real
-        self.cu_ka_sld_imag = cu_ka_sld_imag
-        self.mo_ka_sld_real = mo_ka_sld_real
-        self.mo_ka_sld_imag = mo_ka_sld_imag
-        self.neutron_inc_xs = neutron_inc_xs
-        self.neutron_abs_xs = neutron_abs_xs
-        self.neutron_length = neutron_length
-
-def sldAlgorithm(molecular_formula, mass_density, wavelength):
-
-    sld_formula = Formula(molecular_formula, density=mass_density)
-
-    def calculate_sld(formula):
-        if len(formula.atoms) != 1:
-            raise NotImplementedError()
-        energy = xray_energy(formula.atoms.keys()[0].K_alpha)
-        return xray_sld_from_atoms(
-            sld_formula.atoms,
-            density=mass_density,
-            energy=energy)
-
-    cu_real, cu_imag = calculate_sld(Formula("Cu"))
-    mo_real, mo_imag = calculate_sld(Formula("Mo"))
-
-    (sld_real, sld_imag, _), (_, neutron_abs_xs, neutron_inc_xs), neutron_length = \
-        neutron_scattering(
-            compound=molecular_formula,
-            density=mass_density,
-            wavelength=wavelength)
-
-    SCALE = 1e-6
-
-    # neutron sld
-    neutron_sld_real = SCALE * sld_real
-    neutron_sld_imag = SCALE * abs(sld_imag)
-
-    # Cu sld
-    cu_ka_sld_real = SCALE * cu_real
-    cu_ka_sld_imag = SCALE * abs(cu_imag)
-
-    # Mo sld
-    mo_ka_sld_real = SCALE * mo_real
-    mo_ka_sld_imag = SCALE * abs(mo_imag)
-
-    return SldResult(
-        molecular_formula, mass_density, wavelength,
-        neutron_sld_real, neutron_sld_imag,
-        cu_ka_sld_real, cu_ka_sld_imag,
-        mo_ka_sld_real, mo_ka_sld_imag,
-        neutron_inc_xs, neutron_abs_xs, neutron_length)
-
-
-class SldPanel(QtGui.QDialog):
-
-    def __init__(self, parent=None):
-        super(SldPanel, self).__init__()
-
-        self.manager = parent
-
-        self.setupUi()
-        self.setupModel()
-        self.setupMapper()
-
-    def _getOutputs(self):
-        return {
-            MODEL.NEUTRON_SLD_REAL: self.ui.editNeutronSldReal,
-            MODEL.NEUTRON_SLD_IMAG: self.ui.editNeutronSldImag,
-            MODEL.CU_KA_SLD_REAL: self.ui.editCuKaSldReal,
-            MODEL.CU_KA_SLD_IMAG: self.ui.editCuKaSldImag,
-            MODEL.MO_KA_SLD_REAL: self.ui.editMoKaSldReal,
-            MODEL.MO_KA_SLD_IMAG: self.ui.editMoKaSldImag,
-            MODEL.NEUTRON_INC_XS: self.ui.editNeutronIncXs,
-            MODEL.NEUTRON_ABS_XS: self.ui.editNeutronAbsXs,
-            MODEL.NEUTRON_LENGTH: self.ui.editNeutronLength
-        }
-
-    def setupUi(self):
-        self.ui = Ui_SldPanel()
-        self.ui.setupUi(self)
-
-        # set validators
-        self.ui.editMolecularFormula.setValidator(FormulaValidator(self.ui.editMolecularFormula))
-
-        rx = QtCore.QRegExp("[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?")
-        self.ui.editMassDensity.setValidator(QtGui.QRegExpValidator(rx, self.ui.editMassDensity))
-        self.ui.editWavelength.setValidator(QtGui.QRegExpValidator(rx, self.ui.editWavelength))
-
-        # signals
-        self.ui.buttonBox.button(QtGui.QDialogButtonBox.Reset).clicked.connect(self.modelReset)
-        self.ui.buttonBox.button(QtGui.QDialogButtonBox.Help).clicked.connect(self.displayHelp)
-
-    def setupModel(self):
-        self.model = QtGui.QStandardItemModel(self)
-        self.model.setItem(MODEL.MOLECULAR_FORMULA, QtGui.QStandardItem())
-        self.model.setItem(MODEL.MASS_DENSITY     , QtGui.QStandardItem())
-        self.model.setItem(MODEL.WAVELENGTH       , QtGui.QStandardItem())
-
-        for key in self._getOutputs().keys():
-            self.model.setItem(key, QtGui.QStandardItem())
-
-        QtCore.QObject.connect(
-            self.model,
-            QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
-            self.dataChanged)
-
-        self.modelReset()
-
-    def setupMapper(self):
-        self.mapper = QtGui.QDataWidgetMapper(self)
-        self.mapper.setModel(self.model)
-        self.mapper.setOrientation(QtCore.Qt.Vertical)
-
-        self.mapper.addMapping(self.ui.editMolecularFormula, MODEL.MOLECULAR_FORMULA)
-        self.mapper.addMapping(self.ui.editMassDensity     , MODEL.MASS_DENSITY)
-        self.mapper.addMapping(self.ui.editWavelength      , MODEL.WAVELENGTH)
-
-        for key, edit in self._getOutputs().iteritems():
-            self.mapper.addMapping(edit, key)
-
-        self.mapper.toFirst()
-
-    def dataChanged(self, top, bottom):
-        update = False
-        for index in xrange(top.row(), bottom.row() + 1):
-            if (index == MODEL.MOLECULAR_FORMULA) or (index == MODEL.MASS_DENSITY) or (index == MODEL.WAVELENGTH):
-                update = True
-
-        # calcualtion
-        if update:
-            formula = self.model.item(MODEL.MOLECULAR_FORMULA).text()
-            density = self.model.item(MODEL.MASS_DENSITY).text()
-            wavelength = self.model.item(MODEL.WAVELENGTH).text()
-            if len(formula) > 0 and len(density) > 0 and len(wavelength) > 0:
-                try:
-                    results = sldAlgorithm(str(formula), float(density), float(wavelength))
-
-                    def format(value):
-                        return ("%-5.3g" % value).strip()
-
-                    self.model.item(MODEL.NEUTRON_SLD_REAL).setText(format(results.neutron_sld_real))
-                    self.model.item(MODEL.NEUTRON_SLD_IMAG).setText(format(results.neutron_sld_imag))
-
-                    self.model.item(MODEL.CU_KA_SLD_REAL).setText(format(results.cu_ka_sld_real))
-                    self.model.item(MODEL.CU_KA_SLD_IMAG).setText(format(results.cu_ka_sld_imag))
-
-                    self.model.item(MODEL.MO_KA_SLD_REAL).setText(format(results.mo_ka_sld_real))
-                    self.model.item(MODEL.MO_KA_SLD_IMAG).setText(format(results.mo_ka_sld_imag))
-
-                    self.model.item(MODEL.NEUTRON_INC_XS).setText(format(results.neutron_inc_xs))
-                    self.model.item(MODEL.NEUTRON_ABS_XS).setText(format(results.neutron_abs_xs))
-                    self.model.item(MODEL.NEUTRON_LENGTH).setText(format(results.neutron_length))
-
-                    return
-            
-                except Exception as e:
-                    pass
-
-            for key in self._getOutputs().keys():
-                self.model.item(key).setText("")
-
-    def modelReset(self):
-        #self.model.beginResetModel()
-        try:
-            self.model.item(MODEL.MOLECULAR_FORMULA).setText("H2O")
-            self.model.item(MODEL.MASS_DENSITY     ).setText("1")
-            self.model.item(MODEL.WAVELENGTH       ).setText("6")
-        finally:
-            pass
-            #self.model.endResetModel()
-
-    def displayHelp(self):
-        try:
-            location = self.manager.HELP_DIRECTORY_LOCATION + \
-                "/user/sasgui/perspectives/calculator/sld_calculator_help.html"
-            self.manager._helpView.load(QtCore.QUrl(location))
-            self.manager._helpView.show()
-        except AttributeError:
-            # No manager defined - testing and standalone runs
-            pass
-
Index: c/sas/qtgui/SlicerModel.py
===================================================================
--- src/sas/qtgui/SlicerModel.py	(revision 161713c8e6fadc0d5442315916ec49e4df8f4dee)
+++ 	(revision )
@@ -1,57 +1,0 @@
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-
-import sas.qtgui.GuiUtils as GuiUtils
-
-class SlicerModel(object):
-    def __init__(self):
-        # Model representation of local parameters
-        self._model = QtGui.QStandardItemModel()
-
-        self.update_model = True
-        self._model.itemChanged.connect(self.setParamsFromModel)
-
-    def setModelFromParams(self):
-        """
-        Set up the Qt model for data handling between controls
-        """
-        parameters = self.getParams()
-        self._model.removeRows( 0, self._model.rowCount() )
-        # Crete/overwrite model items
-        for parameter in parameters.keys():
-            item1 = QtGui.QStandardItem(parameter)
-            item2 = QtGui.QStandardItem(GuiUtils.formatNumber(parameters[parameter]))
-            self._model.appendRow([item1, item2])
-        self._model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant("Parameter"))
-        self._model.setHeaderData(1, QtCore.Qt.Horizontal, QtCore.QVariant("Value"))
-
-    def setParamsFromModel(self, item):
-        """
-        Set up the params dictionary based on the model content.
-        """
-        params = self.getParams()
-        index = self._model.indexFromItem(item)
-        row_index = index.row()
-        param_name = str(self._model.item(row_index, 0).text())
-        params[param_name] = float(self._model.item(row_index, 1).text())
-
-        self.update_model = False
-        self.setParams(params)
-        self.update_model = True
-
-    def model(self):
-        '''getter for the model'''
-        return self._model
-
-    def getParams(self):
-        ''' pure virtual '''
-        raise NotImplementedError("Parameter getter must be implemented in derived class.")
-
-    def setParams(self):
-        ''' pure virtual '''
-        raise NotImplementedError("Parameter setter must be implemented in derived class.")
-
-    def validate(self):
-        ''' pure virtual '''
-        raise NotImplementedError("Validator must be implemented in derived class.")
-
Index: c/sas/qtgui/SlicerParameters.py
===================================================================
--- src/sas/qtgui/SlicerParameters.py	(revision 161713c8e6fadc0d5442315916ec49e4df8f4dee)
+++ 	(revision )
@@ -1,175 +1,0 @@
-"""
-Allows users to modify the box slicer parameters.
-"""
-import numpy
-import functools
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-from PyQt4 import QtWebKit
-
-# Local UI
-from sas.qtgui.UI.SlicerParametersUI import Ui_SlicerParametersUI
-
-class SlicerParameters(QtGui.QDialog, Ui_SlicerParametersUI):
-    """
-    Interaction between the QTableView and the underlying model,
-    passed from a slicer instance.
-    """
-    close_signal = QtCore.pyqtSignal()
-    def __init__(self, model=None, validate_method=None):
-        super(SlicerParameters, self).__init__()
-
-        self.setupUi(self)
-
-        assert isinstance(model, QtGui.QStandardItemModel)
-
-        self.model = model
-        self.validate_method = validate_method
-
-        # Define a proxy model so cell enablement can be finegrained.
-        self.proxy = ProxyModel(self)
-        self.proxy.setSourceModel(self.model)
-
-        # Set the proxy model for display in the Table View.
-        self.lstParams.setModel(self.proxy)
-
-        # Disallow edit of the parameter name column.
-        self.lstParams.model().setColumnReadOnly(0, True)
-
-        # Specify the validator on the parameter value column.
-        self.delegate = EditDelegate(self, validate_method=self.validate_method)
-        self.lstParams.setItemDelegate(self.delegate)
-        self.delegate.refocus_signal.connect(self.onFocus)
-
-        # Display Help on clicking the button
-        self.buttonBox.button(QtGui.QDialogButtonBox.Help).clicked.connect(self.onHelp)
-
-        # Close doesn't trigger closeEvent automatically, so force it
-        self.buttonBox.button(QtGui.QDialogButtonBox.Close).clicked.connect(functools.partial(self.closeEvent, None))
-
-        # Disable row number display
-        self.lstParams.verticalHeader().setVisible(False)
-        self.lstParams.setAlternatingRowColors(True)
-        self.lstParams.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)
-
-        # Header properties for nicer display
-        header = self.lstParams.horizontalHeader()
-        header.setResizeMode(QtGui.QHeaderView.Stretch)
-        header.setStretchLastSection(True)
-
-    def onFocus(self, row, column):
-        """ Set the focus on the cell (row, column) """
-        selection_model = self.lstParams.selectionModel()
-        selection_model.select(self.model.index(row, column), QtGui.QItemSelectionModel.Select)
-        self.lstParams.setSelectionModel(selection_model)
-        self.lstParams.setCurrentIndex(self.model.index(row, column))
-
-    def setModel(self, model):
-        """ Model setter """
-        self.model = model
-        self.proxy.setSourceModel(self.model)
-
-    def closeEvent(self, event):
-        """
-        Overwritten close widget method in order to send the close
-        signal to the parent.
-        """
-        self.close_signal.emit()
-        if event:
-            event.accept()
-
-    def onHelp(self):
-        """
-        Display generic data averaging help
-        """
-        location = "docs/sphinx-docs/build/html" + \
-            "/user/sasgui/guiframe/graph_help.html#d-data-averaging"
-        self.helpView = QtWebKit.QWebView()
-        self.helpView.load(QtCore.QUrl(location))
-        self.helpView.show()
-
-
-class ProxyModel(QtGui.QIdentityProxyModel):
-    """
-    Trivial proxy model with custom column edit flag
-    """
-    def __init__(self, parent=None):
-        super(ProxyModel, self).__init__(parent)
-        self._columns = set()
-
-    def columnReadOnly(self, column):
-        '''Returns True if column is read only, false otherwise'''
-        return column in self._columns
-
-    def setColumnReadOnly(self, column, readonly=True):
-        '''Add/removes a column from the readonly list'''
-        if readonly:
-            self._columns.add(column)
-        else:
-            self._columns.discard(column)
-
-    def flags(self, index):
-        '''Sets column flags'''
-        flags = super(ProxyModel, self).flags(index)
-        if self.columnReadOnly(index.column()):
-            flags &= ~QtCore.Qt.ItemIsEditable
-        return flags
-
-class PositiveDoubleEditor(QtGui.QLineEdit):
-    # a signal to tell the delegate when we have finished editing
-    editingFinished = QtCore.Signal()
-
-    def __init__(self, parent=None):
-            # Initialize the editor object
-            super(PositiveDoubleEditor, self).__init__(parent)
-            self.setAutoFillBackground(True)
-            validator = QtGui.QDoubleValidator()
-            # Don't use the scientific notation, cause 'e'.
-            validator.setNotation(QtGui.QDoubleValidator.StandardNotation)
-
-            self.setValidator(validator)
-
-    def focusOutEvent(self, event):
-            # Once focus is lost, tell the delegate we're done editing
-            self.editingFinished.emit()
-
-
-class EditDelegate(QtGui.QStyledItemDelegate):
-    refocus_signal = QtCore.pyqtSignal(int, int)
-    def __init__(self, parent=None, validate_method=None):
-        super(EditDelegate, self).__init__(parent)
-        self.editor = None
-        self.index = None
-        self.validate_method = validate_method
-
-    def createEditor(self, parent, option, index):
-        # Creates and returns the custom editor object we will use to edit the cell
-        if not index.isValid():
-            return 0
-
-        result = index.column()
-        if result==1:
-                self.editor = PositiveDoubleEditor(parent)
-                self.index = index
-                return self.editor
-        else:
-                return QtGui.QStyledItemDelegate.createEditor(self, parent, option, index)
-
-    def setModelData(self, editor, model, index):
-        """
-        Custom version of the model update, rejecting bad values
-        """
-        self.index = index
-
-        # Find out the changed parameter name and proposed value
-        new_value = self.editor.text().toFloat()[0]
-        param_name = str(model.sourceModel().item(index.row(),0).text())
-
-        validated = True
-        if self.validate_method:
-            # Validate the proposed value in the slicer
-            value_accepted = self.validate_method(param_name, new_value)
-
-        if value_accepted:
-            # Update the model only if value accepted
-            return super(EditDelegate, self).setModelData(editor, model, index)          
Index: c/sas/qtgui/SlitSizeCalculator.py
===================================================================
--- src/sas/qtgui/SlitSizeCalculator.py	(revision 886d2f2c2f6b63261dcd6876da8bea5382aa8536)
+++ 	(revision )
@@ -1,133 +1,0 @@
-"""
-Slit Size Calculator Panel
-"""
-import os
-import sys
-
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-from UI.SlitSizeCalculator import Ui_SlitSizeCalculator
-from sas.sascalc.dataloader.loader import Loader
-from sas.sascalc.calculator.slit_length_calculator import SlitlengthCalculator
-
-
-class SlitSizeCalculator(QtGui.QDialog, Ui_SlitSizeCalculator):
-    """
-    Provides the slit length calculator GUI.
-    """
-    def __init__(self, parent=None):
-        super(SlitSizeCalculator, self).__init__()
-        self.setupUi(self)
-
-        self.setWindowTitle("Slit Size Calculator")
-        self._parent = parent
-
-        self.thickness = SlitlengthCalculator()
-
-        # signals
-        self.helpButton.clicked.connect(self.onHelp)
-        self.browseButton.clicked.connect(self.onBrowse)
-        self.closeButton.clicked.connect(self.onClose)
-
-        # no reason to have this widget resizable
-        self.setFixedSize(self.minimumSizeHint())
-
-
-    def onHelp(self):
-        """
-        Bring up the Slit Size Calculator calculator Documentation whenever
-        the HELP button is clicked.
-        Calls DocumentationWindow with the path of the location within the
-        documentation tree (after /doc/ ....".
-        """
-        try:
-            location = self._parent.HELP_DIRECTORY_LOCATION + \
-                "/user/sasgui/perspectives/calculator/slit_calculator_help.html"
-
-            self._parent._helpView.load(QtCore.QUrl(location))
-            self._parent._helpView.show()
-        except AttributeError:
-            # No manager defined - testing and standalone runs
-            pass
-
-    def onBrowse(self):
-        """
-        Browse the file and calculate slit lenght upon loading
-        """
-        path_str = self.chooseFile()
-        if not path_str:
-            return
-        loader = Loader()
-        data = loader.load(path_str)
-
-        self.data_file.setText(os.path.basename(path_str))
-        self.calculateSlitSize(data)
-
-    def chooseFile(self):
-        """
-        Shows the Open file dialog and returns the chosen path(s)
-        """
-
-        # Location is automatically saved - no need to keep track of the last dir
-        # But only with Qt built-in dialog (non-platform native)
-        path = QtGui.QFileDialog.getOpenFileName(self, "Choose a file", "",
-                                                 "SAXSess 1D data (*.txt *.TXT *.dat *.DAT)", None,
-                                                 QtGui.QFileDialog.DontUseNativeDialog)
-
-        if path is None:
-            return
-
-        if isinstance(path, QtCore.QString):
-            path = str(path)
-
-        return path
-
-    def onClose(self):
-        """
-        close the window containing this panel
-        """
-        self.close()
-
-    def clearResults(self):
-        """
-        Clear the content of output LineEdits
-        """
-        self.slit_length_out.setText("ERROR!")
-        self.unit_out.clear()
-
-    def calculateSlitSize(self, data=None):
-        """
-        Computes slit lenght from given 1D data
-        """
-
-        if data is None:
-            self.clearResults()
-            msg = "ERROR: Data hasn't been loaded correctly"
-            raise RuntimeError, msg
-
-        if data.__class__.__name__ == 'Data2D':
-            self.clearResults()
-            msg = "Slit Length cannot be computed for 2D Data"
-            raise RuntimeError, msg
-
-        #compute the slit size
-        try:
-            xdata = data.x
-            ydata = data.y
-            if xdata == [] or xdata is None or ydata == [] or ydata is None:
-                msg = "The current data is empty please check x and y"
-                raise ValueError, msg
-            slit_length_calculator = SlitlengthCalculator()
-            slit_length_calculator.set_data(x=xdata, y=ydata)
-            slit_length = slit_length_calculator.calculate_slit_length()
-        except:
-            self.clearResults()
-            msg = "Slit Size Calculator: %s" % (sys.exc_value)
-            raise RuntimeError, msg
-
-        slit_length_str = "{:.5f}".format(slit_length)
-        self.slit_length_out.setText(slit_length_str)
-
-        #Display unit, which most likely needs to be 1/Ang but needs to be confirmed
-        self.unit_out.setText("[Unknown]")
-
Index: c/sas/qtgui/UI/AboutUI.ui
===================================================================
--- src/sas/qtgui/UI/AboutUI.ui	(revision e207c3f6f341079b70b4fd24e4a62468a656894d)
+++ 	(revision )
@@ -1,249 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>AboutUI</class>
- <widget class="QWidget" name="AboutUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>1107</width>
-    <height>449</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Form</string>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_2">
-   <item row="0" column="0" rowspan="2">
-    <widget class="QLabel" name="label">
-     <property name="text">
-      <string/>
-     </property>
-     <property name="pixmap">
-      <pixmap resource="../images/images.qrc">:/about/angles_flat.png</pixmap>
-     </property>
-    </widget>
-   </item>
-   <item row="0" column="1">
-    <widget class="QLabel" name="label_2">
-     <property name="text">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;SasView&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-    </widget>
-   </item>
-   <item row="0" column="2">
-    <widget class="QLabel" name="lblVersion">
-     <property name="text">
-      <string>TextLabel</string>
-     </property>
-    </widget>
-   </item>
-   <item row="4" column="0" colspan="4">
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
-      <widget class="QPushButton" name="cmdLinkUT">
-       <property name="text">
-        <string/>
-       </property>
-       <property name="icon">
-        <iconset resource="../images/images.qrc">
-         <normaloff>:/about/utlogo.gif</normaloff>:/about/utlogo.gif</iconset>
-       </property>
-       <property name="iconSize">
-        <size>
-         <width>48</width>
-         <height>48</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QPushButton" name="cmdLinkUMD">
-       <property name="text">
-        <string/>
-       </property>
-       <property name="icon">
-        <iconset resource="../images/images.qrc">
-         <normaloff>:/about/umd_logo.png</normaloff>:/about/umd_logo.png</iconset>
-       </property>
-       <property name="iconSize">
-        <size>
-         <width>48</width>
-         <height>48</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="2">
-      <widget class="QPushButton" name="cmdLinkNIST">
-       <property name="text">
-        <string/>
-       </property>
-       <property name="icon">
-        <iconset resource="../images/images.qrc">
-         <normaloff>:/about/nist_logo.png</normaloff>:/about/nist_logo.png</iconset>
-       </property>
-       <property name="iconSize">
-        <size>
-         <width>110</width>
-         <height>48</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="3">
-      <widget class="QPushButton" name="cmdLinkSNS">
-       <property name="text">
-        <string/>
-       </property>
-       <property name="icon">
-        <iconset resource="../images/images.qrc">
-         <normaloff>:/about/sns_logo.png</normaloff>:/about/sns_logo.png</iconset>
-       </property>
-       <property name="iconSize">
-        <size>
-         <width>64</width>
-         <height>48</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="4">
-      <widget class="QPushButton" name="cmdLinkISIS">
-       <property name="text">
-        <string/>
-       </property>
-       <property name="icon">
-        <iconset resource="../images/images.qrc">
-         <normaloff>:/about/isis_logo.png</normaloff>:/about/isis_logo.png</iconset>
-       </property>
-       <property name="iconSize">
-        <size>
-         <width>128</width>
-         <height>48</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="5">
-      <widget class="QPushButton" name="cmdLinkESS">
-       <property name="text">
-        <string/>
-       </property>
-       <property name="icon">
-        <iconset resource="../images/images.qrc">
-         <normaloff>:/about/ess_logo.png</normaloff>:/about/ess_logo.png</iconset>
-       </property>
-       <property name="iconSize">
-        <size>
-         <width>48</width>
-         <height>48</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="6">
-      <widget class="QPushButton" name="cmdLinkILL">
-       <property name="text">
-        <string/>
-       </property>
-       <property name="icon">
-        <iconset resource="../images/images.qrc">
-         <normaloff>:/about/ill_logo.png</normaloff>:/about/ill_logo.png</iconset>
-       </property>
-       <property name="iconSize">
-        <size>
-         <width>48</width>
-         <height>48</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="7">
-      <widget class="QPushButton" name="cmdLinkANSTO">
-       <property name="text">
-        <string/>
-       </property>
-       <property name="icon">
-        <iconset resource="../images/images.qrc">
-         <normaloff>:/about/ansto_logo.png</normaloff>:/about/ansto_logo.png</iconset>
-       </property>
-       <property name="iconSize">
-        <size>
-         <width>175</width>
-         <height>48</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item row="5" column="0" colspan="3">
-    <spacer name="horizontalSpacer">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>593</width>
-       <height>20</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="5" column="3">
-    <widget class="QPushButton" name="cmdOK">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="text">
-      <string>OK</string>
-     </property>
-    </widget>
-   </item>
-   <item row="1" column="1" colspan="2">
-    <widget class="QLabel" name="lblAbout">
-     <property name="text">
-      <string>TextLabel</string>
-     </property>
-    </widget>
-   </item>
-   <item row="2" column="0" colspan="4">
-    <widget class="Line" name="line">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-    </widget>
-   </item>
-   <item row="3" column="0" colspan="4">
-    <widget class="QLabel" name="lblText">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="text">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This work originally developed as part of the DANSE project funded by the NSF under grant DMR-0520547, and currently maintained by NIST, UMD, ORNL, ISIS, ESS, ILL and last but not least ANSTO.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-     <property name="wordWrap">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="../images/images.qrc"/>
- </resources>
- <connections/>
-</ui>
Index: c/sas/qtgui/UI/AcknowledgementsUI.ui
===================================================================
--- src/sas/qtgui/UI/AcknowledgementsUI.ui	(revision 9e426c11367c4fe13f88ce18932880794884e04f)
+++ 	(revision )
@@ -1,49 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Acknowledgements</class>
- <widget class="QWidget" name="Acknowledgements">
-  <property name="windowModality">
-   <enum>Qt::ApplicationModal</enum>
-  </property>
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>436</width>
-    <height>212</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Acknowledging SasView</string>
-  </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0">
-    <widget class="QLabel" name="label">
-     <property name="text">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;To ensure the long term support and development of this software please remember to&lt;/p&gt;&lt;ol style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Acknowledge its use in your publications as suggested below&lt;br/&gt;&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Reference the following website: http://www.sasview.org&lt;br/&gt;&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Reference the model you used if appropriate (see documentation for refs) &lt;br/&gt;&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Send us your reference for our records: developers@sasview.org&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-    </widget>
-   </item>
-   <item row="1" column="0">
-    <widget class="QTextBrowser" name="textBrowser">
-     <property name="html">
-      <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;This work benefited from the use of the SasView application, originally&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;developed under NSF award DMR-0520547.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
Index: c/sas/qtgui/UI/AddTextUI.ui
===================================================================
--- src/sas/qtgui/UI/AddTextUI.ui	(revision 9290b1a2e57458d51b13f1acd1798b999372c7d7)
+++ 	(revision )
@@ -1,142 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>AddText</class>
- <widget class="QDialog" name="AddText">
-  <property name="windowModality">
-   <enum>Qt::ApplicationModal</enum>
-  </property>
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>432</width>
-    <height>324</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Add Text</string>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_2">
-   <item row="0" column="0">
-    <widget class="QGroupBox" name="groupBox">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="title">
-      <string>Custom Text </string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout">
-      <item row="0" column="0">
-       <widget class="QTextEdit" name="textEdit">
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </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>44</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="2" column="0">
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <widget class="QPushButton" name="btnFont">
-       <property name="text">
-        <string>Font...</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QPushButton" name="btnColor">
-       <property name="text">
-        <string>Color...</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="QDialogButtonBox" name="buttonBox">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="standardButtons">
-        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>AddText</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>AddText</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/BoxSumUI.ui
===================================================================
--- src/sas/qtgui/UI/BoxSumUI.ui	(revision bda1faa75a06f4eb6f137fc54fb9d6eaf5ef1ed4)
+++ 	(revision )
@@ -1,452 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>BoxSumUI</class>
- <widget class="QDialog" name="BoxSumUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>322</width>
-    <height>313</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Box Sum</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_4">
-   <item row="0" column="0" colspan="2">
-    <widget class="QGroupBox" name="groupBox">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="title">
-      <string>Box dimensions</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_3">
-      <item row="0" column="0">
-       <widget class="QGroupBox" name="groupBox_4">
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-        <property name="title">
-         <string>Box size</string>
-        </property>
-        <layout class="QGridLayout" name="gridLayout">
-         <item row="0" column="0">
-          <widget class="QLabel" name="label">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-           <property name="text">
-            <string>Height</string>
-           </property>
-          </widget>
-         </item>
-         <item row="0" column="1">
-          <widget class="QLineEdit" name="txtBoxHeight">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="minimumSize">
-            <size>
-             <width>70</width>
-             <height>0</height>
-            </size>
-           </property>
-           <property name="maximumSize">
-            <size>
-             <width>70</width>
-             <height>16777215</height>
-            </size>
-           </property>
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-          </widget>
-         </item>
-         <item row="0" column="2">
-          <widget class="QLabel" name="label_10">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="text">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
-         </item>
-         <item row="1" column="0">
-          <widget class="QLabel" name="label_2">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-           <property name="text">
-            <string>Width</string>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="1">
-          <widget class="QLineEdit" name="txtBoxWidth">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="minimumSize">
-            <size>
-             <width>70</width>
-             <height>0</height>
-            </size>
-           </property>
-           <property name="maximumSize">
-            <size>
-             <width>70</width>
-             <height>16777215</height>
-            </size>
-           </property>
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="2">
-          <widget class="QLabel" name="label_11">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="text">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
-         </item>
-        </layout>
-       </widget>
-      </item>
-      <item row="0" column="1">
-       <widget class="QGroupBox" name="groupBox_2">
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-        <property name="title">
-         <string>Box center</string>
-        </property>
-        <layout class="QGridLayout" name="gridLayout_2">
-         <item row="0" column="0">
-          <widget class="QLabel" name="label_3">
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;X coordinate of the center of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-           <property name="text">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;X&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-          </widget>
-         </item>
-         <item row="0" column="1">
-          <widget class="QLineEdit" name="txtCenterX">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="minimumSize">
-            <size>
-             <width>70</width>
-             <height>0</height>
-            </size>
-           </property>
-           <property name="maximumSize">
-            <size>
-             <width>70</width>
-             <height>16777215</height>
-            </size>
-           </property>
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;X coordinate of the center of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-          </widget>
-         </item>
-         <item row="0" column="2">
-          <widget class="QLabel" name="label_13">
-           <property name="text">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
-         </item>
-         <item row="1" column="0">
-          <widget class="QLabel" name="label_4">
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Y coordinate of the center of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-           <property name="text">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;Y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="1">
-          <widget class="QLineEdit" name="txtCenterY">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="minimumSize">
-            <size>
-             <width>70</width>
-             <height>0</height>
-            </size>
-           </property>
-           <property name="maximumSize">
-            <size>
-             <width>70</width>
-             <height>16777215</height>
-            </size>
-           </property>
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Y coordinate of the center of the box.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-           <property name="text">
-            <string/>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="2">
-          <widget class="QLabel" name="label_12">
-           <property name="text">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
-         </item>
-        </layout>
-       </widget>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="1" column="0" colspan="2">
-    <widget class="QGroupBox" name="groupBox_3">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="title">
-      <string>Box parameters</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_5">
-      <item row="0" column="0">
-       <layout class="QFormLayout" name="formLayout">
-        <item row="0" column="0">
-         <widget class="QLabel" name="label_5">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Average point count in selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Avg:</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <widget class="QLabel" name="lblAvg">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Average point count in selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>TextLabel</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="0">
-         <widget class="QLabel" name="label_6">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error of average point count in selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Avg error:</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="1">
-         <widget class="QLabel" name="lblAvgErr">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error of average point count in selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>TextLabel</string>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="0">
-         <widget class="QLabel" name="label_7">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Total number of points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Num. of points:</string>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="1">
-         <widget class="QLabel" name="lblNumPoints">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Total number of points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>TextLabel</string>
-          </property>
-         </widget>
-        </item>
-        <item row="3" column="0">
-         <widget class="QLabel" name="label_8">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sum of point intensities for all points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Sum:</string>
-          </property>
-         </widget>
-        </item>
-        <item row="3" column="1">
-         <widget class="QLabel" name="lblSum">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sum of point intensities for all points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>TextLabel</string>
-          </property>
-         </widget>
-        </item>
-        <item row="4" column="0">
-         <widget class="QLabel" name="label_9">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error of point intensity sum for all points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Sum error:</string>
-          </property>
-         </widget>
-        </item>
-        <item row="4" column="1">
-         <widget class="QLabel" name="lblSumErr">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error of point intensity sum for all points in the selected region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>TextLabel</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="2" column="0">
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>18</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="3" column="1">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Close</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>BoxSumUI</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>BoxSumUI</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/ColorMapUI.ui
===================================================================
--- src/sas/qtgui/UI/ColorMapUI.ui	(revision 5d89f43266c67cb96a7bf395800ce4cce896c9f8)
+++ 	(revision )
@@ -1,273 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ColorMapUI</class>
- <widget class="QDialog" name="ColorMapUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>450</width>
-    <height>329</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Color Map</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <property name="modal">
-   <bool>true</bool>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_5">
-   <item row="1" column="1">
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>62</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="3" column="0" colspan="3">
-    <layout class="QHBoxLayout" name="horizontalLayout_2">
-     <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="QDialogButtonBox" name="buttonBox">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="standardButtons">
-        <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item row="0" column="0" colspan="2">
-    <widget class="QGroupBox" name="groupBox">
-     <property name="title">
-      <string>Color map</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_2">
-      <item row="0" column="0">
-       <layout class="QHBoxLayout" name="horizontalLayout">
-        <item>
-         <widget class="QLabel" name="label">
-          <property name="text">
-           <string>Select color map</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QComboBox" name="cbColorMap">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select color map from the list.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item row="1" column="0">
-       <layout class="QGridLayout" name="gridLayout">
-        <item row="0" column="0">
-         <widget class="QLabel" name="label_2">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter value for minimum color map amplitude.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Min amplitude for color map</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <widget class="QLineEdit" name="txtMinAmplitude">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter value for minimum color map amplitude.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="0">
-         <widget class="QLabel" name="label_3">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter value for maximum color map amplitude.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Max amplitude for color map</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="1">
-         <widget class="QLineEdit" name="txtMaxAmplitude">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter value for maximum color map amplitude.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item row="2" column="0">
-       <widget class="QCheckBox" name="chkReverse">
-        <property name="toolTip">
-         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use the color-reversed map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-        </property>
-        <property name="text">
-         <string>Reverse map</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="0" column="2">
-    <widget class="QGroupBox" name="groupBox_2">
-     <property name="title">
-      <string>Detector</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_4">
-      <item row="0" column="0">
-       <layout class="QGridLayout" name="gridLayout_3">
-        <item row="0" column="0">
-         <widget class="QLabel" name="label_4">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Detector width.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Width in pixels</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <widget class="QLabel" name="lblWidth">
-          <property name="text">
-           <string>0</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="0">
-         <widget class="QLabel" name="label_5">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Detector height.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Height in pixels</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="1">
-         <widget class="QLabel" name="lblHeight">
-          <property name="text">
-           <string>0</string>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="0">
-         <widget class="QLabel" name="label_6">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum absolute Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;x,y&lt;/span&gt; value.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;max&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="1">
-         <widget class="QLabel" name="lblQmax">
-          <property name="text">
-           <string>0</string>
-          </property>
-         </widget>
-        </item>
-        <item row="3" column="0">
-         <widget class="QLabel" name="label_7">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Minimum value of Q&lt;span style=&quot; vertical-align:sub;&quot;&gt;x&lt;/span&gt; in units of Q.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="text">
-           <string>Beam stop radius</string>
-          </property>
-         </widget>
-        </item>
-        <item row="3" column="1">
-         <widget class="QLabel" name="lblStopRadius">
-          <property name="text">
-           <string>TextLabel</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="2" column="0" colspan="3">
-    <widget class="QWidget" name="widget" native="true">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-    </widget>
-   </item>
-  </layout>
-  <zorder>groupBox</zorder>
-  <zorder>widget</zorder>
-  <zorder>groupBox_2</zorder>
-  <zorder>verticalSpacer</zorder>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>ColorMapUI</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>ColorMapUI</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/DataExplorerUI.ui
===================================================================
--- src/sas/qtgui/UI/DataExplorerUI.ui	(revision 71361f01fa009014ff017ed99dc3e33eadca5cd0)
+++ 	(revision )
@@ -1,488 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DataLoadWidget</class>
- <widget class="QTabWidget" name="DataLoadWidget">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>405</width>
-    <height>630</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-    <horstretch>0</horstretch>
-    <verstretch>5</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>TabWidget</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <property name="currentIndex">
-   <number>0</number>
-  </property>
-  <widget class="QWidget" name="dataTab">
-   <attribute name="title">
-    <string>Data</string>
-   </attribute>
-   <layout class="QGridLayout" name="gridLayout_11">
-    <item row="0" column="0">
-     <widget class="QGroupBox" name="groupBox">
-      <property name="title">
-       <string>Data</string>
-      </property>
-      <layout class="QGridLayout" name="gridLayout_9">
-       <item row="0" column="0">
-        <layout class="QGridLayout" name="gridLayout">
-         <item row="0" column="0" rowspan="2">
-          <widget class="QPushButton" name="cmdLoad">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>5</horstretch>
-             <verstretch>5</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="minimumSize">
-            <size>
-             <width>154</width>
-             <height>50</height>
-            </size>
-           </property>
-           <property name="baseSize">
-            <size>
-             <width>100</width>
-             <height>50</height>
-            </size>
-           </property>
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Load a file with data&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-           <property name="styleSheet">
-            <string notr="true">font: 13pt &quot;MS Shell Dlg 2&quot;;</string>
-           </property>
-           <property name="text">
-            <string>Load data</string>
-           </property>
-           <property name="icon">
-            <iconset resource="main_resources.qrc">
-             <normaloff>:/res/down-grey.png</normaloff>:/res/down-grey.png</iconset>
-           </property>
-           <property name="iconSize">
-            <size>
-             <width>48</width>
-             <height>48</height>
-            </size>
-           </property>
-           <property name="shortcut">
-            <string>Ctrl+R</string>
-           </property>
-          </widget>
-         </item>
-         <item row="0" column="1">
-          <widget class="QPushButton" name="cmdDeleteData">
-           <property name="text">
-            <string>Delete</string>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="1">
-          <widget class="QComboBox" name="cbSelect">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <item>
-            <property name="text">
-             <string>Select all</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Unselect all</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Select all 1D</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Unselect all 1D</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Select all 2D</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Unselect all 2D</string>
-            </property>
-           </item>
-          </widget>
-         </item>
-        </layout>
-       </item>
-       <item row="0" column="1">
-        <spacer name="horizontalSpacer_7">
-         <property name="orientation">
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>92</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item row="2" column="0">
-        <layout class="QGridLayout" name="gridLayout_2">
-         <item row="0" column="0" rowspan="2">
-          <widget class="QPushButton" name="cmdSendTo">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-             <horstretch>5</horstretch>
-             <verstretch>5</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="minimumSize">
-            <size>
-             <width>170</width>
-             <height>50</height>
-            </size>
-           </property>
-           <property name="baseSize">
-            <size>
-             <width>100</width>
-             <height>50</height>
-            </size>
-           </property>
-           <property name="font">
-            <font>
-             <pointsize>13</pointsize>
-            </font>
-           </property>
-           <property name="toolTip">
-            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Send data to perspective&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-           </property>
-           <property name="styleSheet">
-            <string notr="true">font: 13pt &quot;MS Shell Dlg 2&quot;;</string>
-           </property>
-           <property name="text">
-            <string>Send data to</string>
-           </property>
-           <property name="icon">
-            <iconset resource="main_resources.qrc">
-             <normaloff>:/res/right-grey.png</normaloff>:/res/right-grey.png</iconset>
-           </property>
-           <property name="iconSize">
-            <size>
-             <width>48</width>
-             <height>48</height>
-            </size>
-           </property>
-          </widget>
-         </item>
-         <item row="0" column="1">
-          <widget class="QComboBox" name="cbFitting">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="sizeAdjustPolicy">
-            <enum>QComboBox::AdjustToContents</enum>
-           </property>
-           <item>
-            <property name="text">
-             <string>Fitting</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Pr inversion</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Invariant</string>
-            </property>
-           </item>
-          </widget>
-         </item>
-         <item row="1" column="1">
-          <widget class="QCheckBox" name="chkBatch">
-           <property name="text">
-            <string>Batch mode</string>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
-       <item row="1" column="0" colspan="2">
-        <widget class="QTreeView" name="treeView">
-         <property name="contextMenuPolicy">
-          <enum>Qt::NoContextMenu</enum>
-         </property>
-         <property name="acceptDrops">
-          <bool>true</bool>
-         </property>
-         <property name="editTriggers">
-          <set>QAbstractItemView::NoEditTriggers</set>
-         </property>
-         <property name="dragEnabled">
-          <bool>true</bool>
-         </property>
-         <property name="dragDropOverwriteMode">
-          <bool>true</bool>
-         </property>
-         <property name="dragDropMode">
-          <enum>QAbstractItemView::DropOnly</enum>
-         </property>
-         <property name="defaultDropAction">
-          <enum>Qt::CopyAction</enum>
-         </property>
-         <property name="selectionMode">
-          <enum>QAbstractItemView::ExtendedSelection</enum>
-         </property>
-         <attribute name="headerVisible">
-          <bool>false</bool>
-         </attribute>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </item>
-    <item row="1" column="0">
-     <layout class="QGridLayout" name="gridLayout_10">
-      <item row="0" column="0" rowspan="2">
-       <layout class="QGridLayout" name="gridLayout_6">
-        <item row="0" column="0">
-         <widget class="QGroupBox" name="groupBox_3">
-          <property name="title">
-           <string>Plot</string>
-          </property>
-          <property name="flat">
-           <bool>false</bool>
-          </property>
-          <property name="checkable">
-           <bool>false</bool>
-          </property>
-          <layout class="QGridLayout" name="gridLayout_3">
-           <item row="0" column="0">
-            <widget class="QPushButton" name="cmdNew">
-             <property name="text">
-              <string>Create New</string>
-             </property>
-            </widget>
-           </item>
-           <item row="1" column="0">
-            <widget class="QPushButton" name="cmdAppend">
-             <property name="text">
-              <string>Append to</string>
-             </property>
-            </widget>
-           </item>
-           <item row="1" column="1">
-            <widget class="QComboBox" name="cbgraph">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="sizeAdjustPolicy">
-              <enum>QComboBox::AdjustToContents</enum>
-             </property>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <spacer name="horizontalSpacer_3">
-          <property name="orientation">
-           <enum>Qt::Horizontal</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>103</width>
-            <height>48</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-       </layout>
-      </item>
-      <item row="1" column="1">
-       <widget class="QPushButton" name="cmdHelp">
-        <property name="text">
-         <string>Help</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QWidget" name="theoryTab">
-   <attribute name="title">
-    <string>Theory</string>
-   </attribute>
-   <layout class="QGridLayout" name="gridLayout_8">
-    <item row="0" column="0">
-     <widget class="QGroupBox" name="groupBox_2">
-      <property name="title">
-       <string>Theory</string>
-      </property>
-      <layout class="QGridLayout" name="gridLayout_4">
-       <item row="0" column="0">
-        <layout class="QHBoxLayout" name="horizontalLayout_3">
-         <item>
-          <widget class="QPushButton" name="cmdFreeze">
-           <property name="text">
-            <string>Freeze Theory</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <spacer name="horizontalSpacer_5">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>218</width>
-             <height>20</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-         <item>
-          <widget class="QPushButton" name="cmdDeleteTheory">
-           <property name="text">
-            <string>Delete</string>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
-       <item row="1" column="0">
-        <widget class="QTreeView" name="freezeView">
-         <attribute name="headerVisible">
-          <bool>false</bool>
-         </attribute>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </item>
-    <item row="1" column="0">
-     <layout class="QGridLayout" name="gridLayout_5">
-      <item row="0" column="0">
-       <widget class="QGroupBox" name="groupBox_4">
-        <property name="title">
-         <string>Plot</string>
-        </property>
-        <layout class="QGridLayout" name="gridLayout_7">
-         <item row="0" column="0">
-          <widget class="QPushButton" name="cmdNew_2">
-           <property name="text">
-            <string>Create New</string>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="0">
-          <widget class="QPushButton" name="cmdAppend_2">
-           <property name="text">
-            <string>Append to</string>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="1">
-          <widget class="QComboBox" name="cbgraph_2">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="sizeAdjustPolicy">
-            <enum>QComboBox::AdjustToContents</enum>
-           </property>
-           <item>
-            <property name="text">
-             <string>Graph1</string>
-            </property>
-           </item>
-          </widget>
-         </item>
-        </layout>
-       </widget>
-      </item>
-      <item row="0" column="1">
-       <spacer name="horizontalSpacer_4">
-        <property name="orientation">
-         <enum>Qt::Horizontal</enum>
-        </property>
-        <property name="sizeHint" stdset="0">
-         <size>
-          <width>108</width>
-          <height>111</height>
-         </size>
-        </property>
-       </spacer>
-      </item>
-      <item row="0" column="2" alignment="Qt::AlignBottom">
-       <widget class="QPushButton" name="cmdHelp_2">
-        <property name="text">
-         <string>Help</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-   </layout>
-  </widget>
-  <action name="actionDataInfo">
-   <property name="text">
-    <string>Data Info</string>
-   </property>
-  </action>
-  <action name="actionSaveAs">
-   <property name="text">
-    <string>Save As</string>
-   </property>
-  </action>
-  <action name="actionQuickPlot">
-   <property name="text">
-    <string>Quick Plot</string>
-   </property>
-  </action>
-  <action name="actionQuick3DPlot">
-   <property name="text">
-    <string>Quick 3DPlot (slow)</string>
-   </property>
-  </action>
-  <action name="actionEditMask">
-   <property name="text">
-    <string>Edit Mask</string>
-   </property>
-  </action>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections/>
-</ui>
Index: c/sas/qtgui/UI/DensityPanel.ui
===================================================================
--- src/sas/qtgui/UI/DensityPanel.ui	(revision 1d85b5ee1bd466fc820afbac639a0c95b5c8285e)
+++ 	(revision )
@@ -1,209 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DensityPanel</class>
- <widget class="QDialog" name="DensityPanel">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>290</width>
-    <height>178</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Density/Volume Calculator</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_2">
-   <item row="0" column="0">
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
-      <widget class="QLabel" name="label_1">
-       <property name="text">
-        <string>Molecular Formula</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QLineEdit" name="editMolecularFormula"/>
-     </item>
-     <item row="0" column="2">
-      <widget class="QLabel" name="label_3">
-       <property name="text">
-        <string>e.g. H2O</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="0">
-      <widget class="QLabel" name="label_2">
-       <property name="text">
-        <string>Molar Mass</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="1">
-      <widget class="QLineEdit" name="editMolarMass">
-       <property name="styleSheet">
-        <string notr="true"/>
-       </property>
-       <property name="readOnly">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="2">
-      <widget class="QLabel" name="label_4">
-       <property name="text">
-        <string>g/mol</string>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="0" colspan="3">
-      <widget class="QFrame" name="frame">
-       <property name="minimumSize">
-        <size>
-         <width>0</width>
-         <height>5</height>
-        </size>
-       </property>
-       <property name="frameShape">
-        <enum>QFrame::HLine</enum>
-       </property>
-       <property name="frameShadow">
-        <enum>QFrame::Raised</enum>
-       </property>
-       <property name="lineWidth">
-        <number>1</number>
-       </property>
-       <property name="midLineWidth">
-        <number>0</number>
-       </property>
-      </widget>
-     </item>
-     <item row="3" column="0">
-      <widget class="QLabel" name="label_5">
-       <property name="text">
-        <string>Molar Volume</string>
-       </property>
-      </widget>
-     </item>
-     <item row="3" column="1">
-      <widget class="QLineEdit" name="editMolarVolume"/>
-     </item>
-     <item row="3" column="2">
-      <widget class="QLabel" name="label_6">
-       <property name="text">
-        <string>cmÂ³/mol</string>
-       </property>
-      </widget>
-     </item>
-     <item row="4" column="0">
-      <widget class="QLabel" name="label_7">
-       <property name="text">
-        <string>Mass Density</string>
-       </property>
-      </widget>
-     </item>
-     <item row="4" column="1">
-      <widget class="QLineEdit" name="editMassDensity"/>
-     </item>
-     <item row="4" column="2">
-      <widget class="QLabel" name="label_8">
-       <property name="text">
-        <string>g/cmÂ³</string>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item row="1" column="0">
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeType">
-      <enum>QSizePolicy::Expanding</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>40</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="2" column="0">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::Reset</set>
-     </property>
-     <property name="centerButtons">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <tabstops>
-  <tabstop>editMolecularFormula</tabstop>
-  <tabstop>editMolarMass</tabstop>
-  <tabstop>editMolarVolume</tabstop>
-  <tabstop>editMassDensity</tabstop>
-  <tabstop>buttonBox</tabstop>
- </tabstops>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>DensityPanel</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>DensityPanel</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/KiessigPanel.ui
===================================================================
--- src/sas/qtgui/UI/KiessigPanel.ui	(revision 040529d59cec22934096b06caeb1e05dcbeb7f7f)
+++ 	(revision )
@@ -1,139 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>KiessigPanel</class>
- <widget class="QDialog" name="KiessigPanel">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>354</width>
-    <height>193</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <property name="toolTip">
-   <string/>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_3">
-   <item row="0" column="0" colspan="3">
-    <widget class="QGroupBox" name="groupBox">
-     <property name="title">
-      <string>Input</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout">
-      <item row="0" column="0">
-       <layout class="QHBoxLayout" name="horizontalLayout">
-        <item>
-         <widget class="QLabel" name="label">
-          <property name="text">
-           <string>Kiessing Fringe Width (Delta Q)</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QLineEdit" name="deltaq_in"/>
-        </item>
-        <item>
-         <widget class="QLabel" name="label_2">
-          <property name="text">
-           <string>1/Ã
-</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="1" column="0" colspan="3">
-    <widget class="QGroupBox" name="groupBox_2">
-     <property name="title">
-      <string>Output</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_2">
-      <item row="0" column="0">
-       <layout class="QHBoxLayout" name="horizontalLayout_2">
-        <item>
-         <widget class="QLabel" name="label_3">
-          <property name="text">
-           <string>Thickness (or Diameter)               </string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QLineEdit" name="lengthscale_out">
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QLabel" name="label_4">
-          <property name="text">
-           <string>   Ã
-</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="2" column="2">
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>40</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="3" column="1">
-    <widget class="QPushButton" name="closeButton">
-     <property name="toolTip">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Close this window.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-     <property name="text">
-      <string>Close</string>
-     </property>
-    </widget>
-   </item>
-   <item row="3" column="2">
-    <widget class="QPushButton" name="helpButton">
-     <property name="toolTip">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Help using the Kiessing fringe calculator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-     <property name="text">
-      <string>Help</string>
-     </property>
-    </widget>
-   </item>
-   <item row="3" column="0">
-    <widget class="QPushButton" name="computeButton">
-     <property name="toolTip">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Compute the thickness or diameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-     <property name="text">
-      <string>Compute</string>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections/>
-</ui>
Index: c/sas/qtgui/UI/LinearFitUI.ui
===================================================================
--- src/sas/qtgui/UI/LinearFitUI.ui	(revision 2e3e95954828438b02ef55c47cd9553fe9a7a87a)
+++ 	(revision )
@@ -1,295 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>LinearFitUI</class>
- <widget class="QDialog" name="LinearFitUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>439</width>
-    <height>324</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Linear Fit</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_4">
-   <item row="0" column="0">
-    <widget class="QLabel" name="label">
-     <property name="text">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Perform fit for &lt;span style=&quot; font-weight:600; font-style:italic;&quot;&gt;y(x) = ax + b&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-    </widget>
-   </item>
-   <item row="1" column="0" colspan="2">
-    <widget class="QGroupBox" name="groupBox_2">
-     <property name="title">
-      <string>Fit ranges</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_3">
-      <item row="0" column="0">
-       <layout class="QGridLayout" name="gridLayout_2">
-        <item row="0" column="1">
-         <widget class="QLabel" name="label_9">
-          <property name="text">
-           <string>Min</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="2">
-         <widget class="QLabel" name="label_10">
-          <property name="text">
-           <string>Max</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="0">
-         <widget class="QLabel" name="label_8">
-          <property name="text">
-           <string>Range (linear scale)</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="1">
-         <widget class="QLineEdit" name="txtRangeMin">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Minimum value on the x-axis for the plotted data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="autoFillBackground">
-           <bool>true</bool>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="2">
-         <widget class="QLineEdit" name="txtRangeMax">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum value on the x-axis for the plotted data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="autoFillBackground">
-           <bool>true</bool>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="0">
-         <widget class="QLabel" name="lblRange">
-          <property name="text">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit range&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="1">
-         <widget class="QLineEdit" name="txtFitRangeMin">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter the minimum value on the x-axis to be included in the fit.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="2">
-         <widget class="QLineEdit" name="txtFitRangeMax">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter the maximum value on the x-axis to be included in the fit.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="2" column="0" colspan="2">
-    <widget class="QGroupBox" name="groupBox">
-     <property name="title">
-      <string>Fit parameters</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout">
-      <item row="0" column="0">
-       <layout class="QFormLayout" name="formLayout">
-        <item row="0" column="0">
-         <widget class="QLabel" name="label_3">
-          <property name="text">
-           <string>a</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <widget class="QLineEdit" name="txtA">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit value for the slope parameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="0">
-         <widget class="QLabel" name="label_4">
-          <property name="text">
-           <string>b</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="1">
-         <widget class="QLineEdit" name="txtB">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit value for the constant parameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="0">
-         <widget class="QLabel" name="label_7">
-          <property name="text">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ï&lt;span style=&quot; vertical-align:super;&quot;&gt;2&lt;/span&gt;/dof&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="1">
-         <widget class="QLineEdit" name="txtChi2">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ï&lt;span style=&quot; vertical-align:super;&quot;&gt;2&lt;/span&gt; over degrees of freedom.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item row="0" column="1">
-       <layout class="QFormLayout" name="formLayout_2">
-        <item row="0" column="0">
-         <widget class="QLabel" name="label_5">
-          <property name="text">
-           <string>+/-</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <widget class="QLineEdit" name="txtAerr">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error on the slope parameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="0">
-         <widget class="QLabel" name="label_6">
-          <property name="text">
-           <string>+/-</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="1">
-         <widget class="QLineEdit" name="txtBerr">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Error on the constant parameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="3" column="0" colspan="2">
-    <widget class="QLabel" name="label_2">
-     <property name="text">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#000000;&quot;&gt;Resolution is NOT accounted for.&lt;br/&gt;Slit smeared data will give very wrong answers!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-    </widget>
-   </item>
-   <item row="4" column="1">
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>3</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="5" column="0" colspan="2">
-    <layout class="QHBoxLayout" name="horizontalLayout_2">
-     <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>
-      <layout class="QHBoxLayout" name="horizontalLayout">
-       <item>
-        <widget class="QPushButton" name="cmdFit">
-         <property name="text">
-          <string>Fit</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="cmdClose">
-         <property name="text">
-          <string>Close</string>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </item>
-    </layout>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>cmdClose</sender>
-   <signal>clicked()</signal>
-   <receiver>LinearFitUI</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>284</x>
-     <y>304</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>166</x>
-     <y>163</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/MainWindowUI.ui
===================================================================
--- src/sas/qtgui/UI/MainWindowUI.ui	(revision 363fbfa07207fe7ae5f577b063028a6ad59c1435)
+++ 	(revision )
@@ -1,503 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>915</width>
-    <height>527</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>MainWindow</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <widget class="QWidget" name="centralwidget"/>
-  <widget class="QMenuBar" name="menubar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>915</width>
-     <height>25</height>
-    </rect>
-   </property>
-   <widget class="QMenu" name="menu_File">
-    <property name="title">
-     <string>&amp;File</string>
-    </property>
-    <addaction name="actionLoadData"/>
-    <addaction name="actionLoad_Data_Folder"/>
-    <addaction name="separator"/>
-    <addaction name="actionOpen_Project"/>
-    <addaction name="actionOpen_Analysis"/>
-    <addaction name="separator"/>
-    <addaction name="actionSave"/>
-    <addaction name="actionSave_Analysis"/>
-    <addaction name="separator"/>
-    <addaction name="actionQuit"/>
-   </widget>
-   <widget class="QMenu" name="menuEdit">
-    <property name="title">
-     <string>Edit</string>
-    </property>
-    <widget class="QMenu" name="menuCopy_Params_As">
-     <property name="title">
-      <string>Copy Params To Format...</string>
-     </property>
-     <addaction name="actionExcel"/>
-     <addaction name="actionLatex"/>
-    </widget>
-    <addaction name="actionUndo"/>
-    <addaction name="actionRedo"/>
-    <addaction name="separator"/>
-    <addaction name="actionCopy"/>
-    <addaction name="actionPaste"/>
-    <addaction name="separator"/>
-    <addaction name="menuCopy_Params_As"/>
-    <addaction name="separator"/>
-    <addaction name="actionReport"/>
-    <addaction name="actionReset"/>
-   </widget>
-   <widget class="QMenu" name="menuView">
-    <property name="title">
-     <string>View</string>
-    </property>
-    <addaction name="actionShow_Grid_Window"/>
-    <addaction name="separator"/>
-    <addaction name="actionHide_Toolbar"/>
-    <addaction name="separator"/>
-    <addaction name="actionStartup_Settings"/>
-    <addaction name="separator"/>
-    <addaction name="actionCategry_Manager"/>
-   </widget>
-   <widget class="QMenu" name="menuTool">
-    <property name="title">
-     <string>Tool</string>
-    </property>
-    <addaction name="actionData_Operation"/>
-    <addaction name="separator"/>
-    <addaction name="actionSLD_Calculator"/>
-    <addaction name="actionDensity_Volume_Calculator"/>
-    <addaction name="actionSlit_Size_Calculator"/>
-    <addaction name="actionKeissig_Calculator"/>
-    <addaction name="actionSAS_Resolution_Estimator"/>
-    <addaction name="actionGeneric_Scattering_Calculator"/>
-    <addaction name="separator"/>
-    <addaction name="actionPython_Shell_Editor"/>
-    <addaction name="actionImage_Viewer"/>
-   </widget>
-   <widget class="QMenu" name="menuFitting">
-    <property name="title">
-     <string>Fitting</string>
-    </property>
-    <addaction name="actionNew_Fit_Page"/>
-    <addaction name="separator"/>
-    <addaction name="actionConstrained_Fit"/>
-    <addaction name="actionCombine_Batch_Fit"/>
-    <addaction name="separator"/>
-    <addaction name="actionFit_Options"/>
-    <addaction name="actionFit_Results"/>
-    <addaction name="separator"/>
-    <addaction name="actionChain_Fitting"/>
-    <addaction name="separator"/>
-    <addaction name="actionEdit_Custom_Model"/>
-   </widget>
-   <widget class="QMenu" name="menuWindow">
-    <property name="title">
-     <string>Window</string>
-    </property>
-    <addaction name="actionCascade"/>
-    <addaction name="actionTile"/>
-    <addaction name="separator"/>
-    <addaction name="actionArrange_Icons"/>
-    <addaction name="actionNext"/>
-    <addaction name="actionPrevious"/>
-    <addaction name="separator"/>
-   </widget>
-   <widget class="QMenu" name="menuAnalysis">
-    <property name="title">
-     <string>Analysis</string>
-    </property>
-    <addaction name="actionFitting"/>
-    <addaction name="actionInversion"/>
-    <addaction name="actionInvariant"/>
-   </widget>
-   <widget class="QMenu" name="menuHelp">
-    <property name="title">
-     <string>Help</string>
-    </property>
-    <addaction name="actionDocumentation"/>
-    <addaction name="separator"/>
-    <addaction name="actionTutorial"/>
-    <addaction name="separator"/>
-    <addaction name="actionAcknowledge"/>
-    <addaction name="separator"/>
-    <addaction name="actionAbout"/>
-    <addaction name="actionCheck_for_update"/>
-   </widget>
-   <addaction name="menu_File"/>
-   <addaction name="menuEdit"/>
-   <addaction name="menuView"/>
-   <addaction name="menuTool"/>
-   <addaction name="menuAnalysis"/>
-   <addaction name="menuFitting"/>
-   <addaction name="menuWindow"/>
-   <addaction name="menuHelp"/>
-  </widget>
-  <widget class="QStatusBar" name="statusbar">
-   <property name="sizePolicy">
-    <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-     <horstretch>0</horstretch>
-     <verstretch>0</verstretch>
-    </sizepolicy>
-   </property>
-  </widget>
-  <widget class="QToolBar" name="toolBar">
-   <property name="windowTitle">
-    <string>toolBar</string>
-   </property>
-   <attribute name="toolBarArea">
-    <enum>TopToolBarArea</enum>
-   </attribute>
-   <attribute name="toolBarBreak">
-    <bool>false</bool>
-   </attribute>
-   <addaction name="actionReset"/>
-   <addaction name="actionSave"/>
-   <addaction name="actionReport"/>
-   <addaction name="actionUndo"/>
-   <addaction name="actionRedo"/>
-   <addaction name="actionCopy"/>
-   <addaction name="actionPaste"/>
-   <addaction name="actionBookmarks"/>
-  </widget>
-  <action name="actionReset">
-   <property name="icon">
-    <iconset resource="main_resources.qrc">
-     <normaloff>:/res/reset.png</normaloff>:/res/reset.png</iconset>
-   </property>
-   <property name="text">
-    <string>Reset Page</string>
-   </property>
-   <property name="toolTip">
-    <string>Reset</string>
-   </property>
-  </action>
-  <action name="actionSave">
-   <property name="icon">
-    <iconset resource="main_resources.qrc">
-     <normaloff>:/res/save.png</normaloff>:/res/save.png</iconset>
-   </property>
-   <property name="text">
-    <string>Save Project</string>
-   </property>
-   <property name="toolTip">
-    <string>Save</string>
-   </property>
-  </action>
-  <action name="actionReport">
-   <property name="icon">
-    <iconset resource="main_resources.qrc">
-     <normaloff>:/res/report.png</normaloff>:/res/report.png</iconset>
-   </property>
-   <property name="text">
-    <string>Report Results</string>
-   </property>
-   <property name="toolTip">
-    <string>report</string>
-   </property>
-  </action>
-  <action name="actionUndo">
-   <property name="icon">
-    <iconset resource="main_resources.qrc">
-     <normaloff>:/res/undo.png</normaloff>
-     <normalon>res/undo.png</normalon>:/res/undo.png</iconset>
-   </property>
-   <property name="text">
-    <string>Undo</string>
-   </property>
-  </action>
-  <action name="actionRedo">
-   <property name="icon">
-    <iconset resource="main_resources.qrc">
-     <normaloff>:/res/redo.png</normaloff>:/res/redo.png</iconset>
-   </property>
-   <property name="text">
-    <string>Redo</string>
-   </property>
-   <property name="toolTip">
-    <string>Redo</string>
-   </property>
-  </action>
-  <action name="actionCopy">
-   <property name="icon">
-    <iconset resource="main_resources.qrc">
-     <normaloff>:/res/copy.png</normaloff>:/res/copy.png</iconset>
-   </property>
-   <property name="text">
-    <string>Copy Params</string>
-   </property>
-   <property name="toolTip">
-    <string>Copy parameter values</string>
-   </property>
-  </action>
-  <action name="actionPaste">
-   <property name="icon">
-    <iconset resource="main_resources.qrc">
-     <normaloff>:/res/paste.png</normaloff>:/res/paste.png</iconset>
-   </property>
-   <property name="text">
-    <string>Paste Params</string>
-   </property>
-   <property name="toolTip">
-    <string>Paste parameter values</string>
-   </property>
-  </action>
-  <action name="actionBookmarks">
-   <property name="checkable">
-    <bool>true</bool>
-   </property>
-   <property name="icon">
-    <iconset resource="main_resources.qrc">
-     <normaloff>:/res/bookmark.png</normaloff>:/res/bookmark.png</iconset>
-   </property>
-   <property name="text">
-    <string>Bookmarks</string>
-   </property>
-  </action>
-  <action name="actionPerspective">
-   <property name="text">
-    <string>Perspective</string>
-   </property>
-  </action>
-  <action name="actionLoadData">
-   <property name="text">
-    <string>Load Data File(s)</string>
-   </property>
-  </action>
-  <action name="actionLoad_Data_Folder">
-   <property name="text">
-    <string>Load Data Folder</string>
-   </property>
-  </action>
-  <action name="actionOpen_Project">
-   <property name="text">
-    <string>Open Project</string>
-   </property>
-  </action>
-  <action name="actionOpen_Analysis">
-   <property name="text">
-    <string>Open Analysis</string>
-   </property>
-  </action>
-  <action name="actionSave_Analysis">
-   <property name="text">
-    <string>Save Analysis</string>
-   </property>
-  </action>
-  <action name="actionQuit">
-   <property name="text">
-    <string>Quit</string>
-   </property>
-  </action>
-  <action name="actionShow_Grid_Window">
-   <property name="text">
-    <string>Show Grid Window</string>
-   </property>
-  </action>
-  <action name="actionHide_Toolbar">
-   <property name="text">
-    <string>Hide Toolbar</string>
-   </property>
-  </action>
-  <action name="actionStartup_Settings">
-   <property name="text">
-    <string>Startup Settings</string>
-   </property>
-  </action>
-  <action name="actionCategry_Manager">
-   <property name="text">
-    <string>Categry Manager</string>
-   </property>
-  </action>
-  <action name="actionData_Operation">
-   <property name="text">
-    <string>Data Operation</string>
-   </property>
-  </action>
-  <action name="actionSLD_Calculator">
-   <property name="text">
-    <string>SLD Calculator</string>
-   </property>
-  </action>
-  <action name="actionDensity_Volume_Calculator">
-   <property name="text">
-    <string>Density/Volume Calculator</string>
-   </property>
-  </action>
-  <action name="actionSlit_Size_Calculator">
-   <property name="text">
-    <string>Slit Size Calculator</string>
-   </property>
-  </action>
-  <action name="actionSAS_Resolution_Estimator">
-   <property name="text">
-    <string>SAS Resolution Estimator</string>
-   </property>
-  </action>
-  <action name="actionGeneric_Scattering_Calculator">
-   <property name="text">
-    <string>Generic Scattering Calculator</string>
-   </property>
-  </action>
-  <action name="actionPython_Shell_Editor">
-   <property name="text">
-    <string>Python Shell/Editor</string>
-   </property>
-  </action>
-  <action name="actionImage_Viewer">
-   <property name="text">
-    <string>Image Viewer</string>
-   </property>
-  </action>
-  <action name="actionNew_Fit_Page">
-   <property name="text">
-    <string>New Fit Page</string>
-   </property>
-  </action>
-  <action name="actionConstrained_Fit">
-   <property name="text">
-    <string>Constrained or Simultaneous Fit</string>
-   </property>
-  </action>
-  <action name="actionCombine_Batch_Fit">
-   <property name="text">
-    <string>Combine Batch Fit</string>
-   </property>
-  </action>
-  <action name="actionFit_Options">
-   <property name="text">
-    <string>Fit Options</string>
-   </property>
-  </action>
-  <action name="actionFit_Results">
-   <property name="text">
-    <string>Fit Results</string>
-   </property>
-  </action>
-  <action name="actionChain_Fitting">
-   <property name="text">
-    <string>Chain Fitting (BatchFit only)</string>
-   </property>
-  </action>
-  <action name="actionEdit_Custom_Model">
-   <property name="text">
-    <string>Edit Custom Model</string>
-   </property>
-  </action>
-  <action name="actionCascade">
-   <property name="text">
-    <string>Cascade</string>
-   </property>
-  </action>
-  <action name="actionTile">
-   <property name="text">
-    <string>Tile</string>
-   </property>
-  </action>
-  <action name="actionTile_Vertically">
-   <property name="text">
-    <string>Tile Vertically</string>
-   </property>
-  </action>
-  <action name="actionArrange_Icons">
-   <property name="text">
-    <string>Arrange Icons</string>
-   </property>
-  </action>
-  <action name="actionNext">
-   <property name="text">
-    <string>Next</string>
-   </property>
-  </action>
-  <action name="actionPrevious">
-   <property name="text">
-    <string>Previous</string>
-   </property>
-  </action>
-  <action name="actionFitting">
-   <property name="checkable">
-    <bool>true</bool>
-   </property>
-   <property name="text">
-    <string>Fitting</string>
-   </property>
-  </action>
-  <action name="actionInversion">
-   <property name="checkable">
-    <bool>true</bool>
-   </property>
-   <property name="text">
-    <string>Pr Inversion</string>
-   </property>
-  </action>
-  <action name="actionInvariant">
-   <property name="checkable">
-    <bool>true</bool>
-   </property>
-   <property name="text">
-    <string>Invariant</string>
-   </property>
-  </action>
-  <action name="actionDocumentation">
-   <property name="text">
-    <string>Documentation</string>
-   </property>
-  </action>
-  <action name="actionTutorial">
-   <property name="text">
-    <string>Tutorial</string>
-   </property>
-  </action>
-  <action name="actionAcknowledge">
-   <property name="text">
-    <string>Acknowledge</string>
-   </property>
-  </action>
-  <action name="actionAbout">
-   <property name="text">
-    <string>About</string>
-   </property>
-  </action>
-  <action name="actionCheck_for_update">
-   <property name="text">
-    <string>Check for update</string>
-   </property>
-  </action>
-  <action name="actionExcel">
-   <property name="text">
-    <string>Excel</string>
-   </property>
-  </action>
-  <action name="actionLatex">
-   <property name="text">
-    <string>Latex</string>
-   </property>
-  </action>
-  <action name="actionKeissig_Calculator">
-   <property name="text">
-    <string>Kiessig Thickness Calculator</string>
-   </property>
-  </action>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections/>
-</ui>
Index: c/sas/qtgui/UI/MaskEditorUI.ui
===================================================================
--- src/sas/qtgui/UI/MaskEditorUI.ui	(revision cad617b718c0c678a25f1f6b63df93528a669bbe)
+++ 	(revision )
@@ -1,143 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MaskEditorUI</class>
- <widget class="QDialog" name="MaskEditorUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>642</width>
-    <height>431</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0">
-    <widget class="QGroupBox" name="groupBox">
-     <property name="title">
-      <string>Mask shape</string>
-     </property>
-     <layout class="QVBoxLayout" name="verticalLayout">
-      <item>
-       <widget class="QRadioButton" name="rbWings">
-        <property name="text">
-         <string>Double Wings</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QRadioButton" name="rbCircularDisk">
-        <property name="text">
-         <string>Circular Disk</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QRadioButton" name="rbRectangularDisk">
-        <property name="text">
-         <string>Rectangular Disk</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QRadioButton" name="rbDoubleWingWindow">
-        <property name="text">
-         <string>Double Wing Window</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QRadioButton" name="rbCircularWindow">
-        <property name="text">
-         <string>Circular Window</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QRadioButton" name="rbRectangularWindow">
-        <property name="text">
-         <string>Rectangular Window</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="0" column="1" rowspan="4">
-    <widget class="QFrame" name="frame">
-     <property name="frameShape">
-      <enum>QFrame::StyledPanel</enum>
-     </property>
-     <property name="frameShadow">
-      <enum>QFrame::Raised</enum>
-     </property>
-     <property name="lineWidth">
-      <number>2</number>
-     </property>
-    </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>152</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="2" column="0">
-    <widget class="QPushButton" name="btnAdd">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="text">
-      <string>Add</string>
-     </property>
-    </widget>
-   </item>
-   <item row="3" column="0">
-    <widget class="QPushButton" name="btnReset">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="text">
-      <string>Reset</string>
-     </property>
-    </widget>
-   </item>
-   <item row="4" column="0">
-    <widget class="QPushButton" name="btnClear">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="text">
-      <string>Clear</string>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections/>
-</ui>
Index: c/sas/qtgui/UI/PlotPropertiesUI.ui
===================================================================
--- src/sas/qtgui/UI/PlotPropertiesUI.ui	(revision 87cc73a1ade6168487d1841f4c285fadcf532e0c)
+++ 	(revision )
@@ -1,160 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>PlotPropertiesUI</class>
- <widget class="QDialog" name="PlotPropertiesUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>319</width>
-    <height>172</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Modify Plot Properties</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_3">
-   <item row="0" column="0">
-    <widget class="QGroupBox" name="groupBox">
-     <property name="title">
-      <string>Symbol</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_2">
-      <item row="0" column="0">
-       <layout class="QGridLayout" name="gridLayout">
-        <item row="0" column="0">
-         <widget class="QLabel" name="label_2">
-          <property name="text">
-           <string>Shape</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="1" colspan="2">
-         <widget class="QComboBox" name="cbShape"/>
-        </item>
-        <item row="0" column="3" alignment="Qt::AlignRight">
-         <widget class="QLabel" name="label_4">
-          <property name="text">
-           <string>Size</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="4">
-         <widget class="QSpinBox" name="sbSize">
-          <property name="minimum">
-           <number>1</number>
-          </property>
-          <property name="maximum">
-           <number>72</number>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="0">
-         <widget class="QLabel" name="label_3">
-          <property name="text">
-           <string>Color</string>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="1">
-         <widget class="QComboBox" name="cbColor"/>
-        </item>
-        <item row="1" column="2">
-         <widget class="QPushButton" name="cmdCustom">
-          <property name="text">
-           <string>Custom..</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="1" column="0">
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <widget class="QLabel" name="label">
-       <property name="text">
-        <string>Legend Label</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QLineEdit" name="txtLegend"/>
-     </item>
-    </layout>
-   </item>
-   <item row="2" column="0">
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>120</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="3" column="0">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>PlotPropertiesUI</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>PlotPropertiesUI</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/ScalePropertiesUI.ui
===================================================================
--- src/sas/qtgui/UI/ScalePropertiesUI.ui	(revision ef01be48d93733bf0b5ac6ff7ccce2ac92d368b6)
+++ 	(revision )
@@ -1,123 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>scalePropertiesUI</class>
- <widget class="QDialog" name="scalePropertiesUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>400</width>
-    <height>137</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Scale Properties</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_2">
-   <item row="0" column="0">
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
-      <widget class="QLabel" name="label">
-       <property name="text">
-        <string>X</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QLabel" name="label_2">
-       <property name="text">
-        <string>Y</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="2">
-      <widget class="QLabel" name="label_3">
-       <property name="text">
-        <string>View</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="0">
-      <widget class="QComboBox" name="cbX"/>
-     </item>
-     <item row="1" column="1">
-      <widget class="QComboBox" name="cbY"/>
-     </item>
-     <item row="1" column="2">
-      <widget class="QComboBox" name="cbView"/>
-     </item>
-    </layout>
-   </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>40</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="2" column="0">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>scalePropertiesUI</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>scalePropertiesUI</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/SetGraphRangeUI.ui
===================================================================
--- src/sas/qtgui/UI/SetGraphRangeUI.ui	(revision 2e3e95954828438b02ef55c47cd9553fe9a7a87a)
+++ 	(revision )
@@ -1,136 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>setGraphRangeUI</class>
- <widget class="QDialog" name="setGraphRangeUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>358</width>
-    <height>144</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Set Graph Range</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <property name="modal">
-   <bool>true</bool>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_2">
-   <item row="0" column="0">
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
-      <widget class="QLabel" name="label">
-       <property name="text">
-        <string>X min</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QLineEdit" name="txtXmin"/>
-     </item>
-     <item row="0" column="2">
-      <widget class="QLabel" name="label_2">
-       <property name="text">
-        <string>X max</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="3">
-      <widget class="QLineEdit" name="txtXmax"/>
-     </item>
-     <item row="1" column="0">
-      <widget class="QLabel" name="label_3">
-       <property name="text">
-        <string>Y min</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="1">
-      <widget class="QLineEdit" name="txtYmin"/>
-     </item>
-     <item row="1" column="2">
-      <widget class="QLabel" name="label_4">
-       <property name="text">
-        <string>Y max</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="3">
-      <widget class="QLineEdit" name="txtYmax"/>
-     </item>
-    </layout>
-   </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>40</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="2" column="0">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>setGraphRangeUI</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>setGraphRangeUI</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/SldPanel.ui
===================================================================
--- src/sas/qtgui/UI/SldPanel.ui	(revision 1d85b5ee1bd466fc820afbac639a0c95b5c8285e)
+++ 	(revision )
@@ -1,380 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SldPanel</class>
- <widget class="QDialog" name="SldPanel">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>447</width>
-    <height>403</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>SLD Calculator</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_2">
-   <item row="0" column="0">
-    <widget class="QGroupBox" name="groupBoxInput">
-     <property name="title">
-      <string>Input</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayoutInput">
-      <item row="1" column="0">
-       <widget class="QLabel" name="label_8">
-        <property name="text">
-         <string>Mass Density</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="2">
-       <widget class="QLabel" name="label_16">
-        <property name="text">
-         <string>g/cmÂ³</string>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="2">
-       <widget class="QLabel" name="label_10">
-        <property name="text">
-         <string>e.g. H2O</string>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="1">
-       <widget class="QLineEdit" name="editMolecularFormula"/>
-      </item>
-      <item row="1" column="1">
-       <widget class="QLineEdit" name="editMassDensity"/>
-      </item>
-      <item row="2" column="1">
-       <widget class="QLineEdit" name="editWavelength">
-        <property name="styleSheet">
-         <string notr="true"/>
-        </property>
-        <property name="readOnly">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="2">
-       <widget class="QLabel" name="label_12">
-        <property name="text">
-         <string>Ã
-</string>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="0">
-       <widget class="QLabel" name="label_9">
-        <property name="text">
-         <string>Molecular Formula</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="0">
-       <widget class="QLabel" name="label_11">
-        <property name="text">
-         <string>Wavelength</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="1" column="0">
-    <widget class="QGroupBox" name="groupBoxOutput">
-     <property name="title">
-      <string>Output</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayoutOutput">
-      <item row="0" column="0">
-       <widget class="QLabel" name="label_17">
-        <property name="text">
-         <string>Neutron SLD</string>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="1">
-       <widget class="QLineEdit" name="editNeutronSldReal">
-        <property name="readOnly">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="2">
-       <widget class="QLabel" name="label_18">
-        <property name="text">
-         <string>-i</string>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="3">
-       <widget class="QLineEdit" name="editNeutronSldImag">
-        <property name="readOnly">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="4">
-       <widget class="QLabel" name="label_5">
-        <property name="text">
-         <string>1/Ã
-Â²</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="0">
-       <widget class="QLabel" name="label_19">
-        <property name="text">
-         <string>Cu Ka SLD</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="1">
-       <widget class="QLineEdit" name="editCuKaSldReal">
-        <property name="styleSheet">
-         <string notr="true"/>
-        </property>
-        <property name="readOnly">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="2">
-       <widget class="QLabel" name="label_20">
-        <property name="text">
-         <string>-i</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="3">
-       <widget class="QLineEdit" name="editCuKaSldImag">
-        <property name="readOnly">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="4">
-       <widget class="QLabel" name="label_6">
-        <property name="text">
-         <string>1/Ã
-Â²</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="0">
-       <widget class="QLabel" name="label">
-        <property name="text">
-         <string>Mo Ka SLD</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="1">
-       <widget class="QLineEdit" name="editMoKaSldReal">
-        <property name="readOnly">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="2">
-       <widget class="QLabel" name="label_2">
-        <property name="text">
-         <string>-i</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="3">
-       <widget class="QLineEdit" name="editMoKaSldImag">
-        <property name="readOnly">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="4">
-       <widget class="QLabel" name="label_7">
-        <property name="text">
-         <string>1/Ã
-Â²</string>
-        </property>
-       </widget>
-      </item>
-      <item row="3" column="0" colspan="5">
-       <widget class="QFrame" name="frame">
-        <property name="minimumSize">
-         <size>
-          <width>0</width>
-          <height>5</height>
-         </size>
-        </property>
-        <property name="frameShape">
-         <enum>QFrame::HLine</enum>
-        </property>
-        <property name="frameShadow">
-         <enum>QFrame::Raised</enum>
-        </property>
-        <property name="lineWidth">
-         <number>1</number>
-        </property>
-        <property name="midLineWidth">
-         <number>0</number>
-        </property>
-       </widget>
-      </item>
-      <item row="4" column="0">
-       <widget class="QLabel" name="label_21">
-        <property name="text">
-         <string>Neutron Inc. Xs</string>
-        </property>
-       </widget>
-      </item>
-      <item row="4" column="1">
-       <widget class="QLineEdit" name="editNeutronIncXs">
-        <property name="readOnly">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="4" column="2" colspan="2">
-       <widget class="QLabel" name="label_22">
-        <property name="text">
-         <string>1/cm</string>
-        </property>
-       </widget>
-      </item>
-      <item row="5" column="0">
-       <widget class="QLabel" name="label_23">
-        <property name="text">
-         <string>Neutron Abs. Xs</string>
-        </property>
-       </widget>
-      </item>
-      <item row="5" column="1">
-       <widget class="QLineEdit" name="editNeutronAbsXs">
-        <property name="readOnly">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="5" column="2" colspan="2">
-       <widget class="QLabel" name="label_24">
-        <property name="text">
-         <string>1/cm</string>
-        </property>
-       </widget>
-      </item>
-      <item row="6" column="0">
-       <widget class="QLabel" name="label_3">
-        <property name="text">
-         <string>Neutron 1/e length</string>
-        </property>
-       </widget>
-      </item>
-      <item row="6" column="1">
-       <widget class="QLineEdit" name="editNeutronLength">
-        <property name="readOnly">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-      <item row="6" column="2" colspan="2">
-       <widget class="QLabel" name="label_4">
-        <property name="text">
-         <string>cm</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="2" column="0">
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>40</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="3" column="0">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::Reset</set>
-     </property>
-     <property name="centerButtons">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <tabstops>
-  <tabstop>editMolecularFormula</tabstop>
-  <tabstop>editMassDensity</tabstop>
-  <tabstop>editWavelength</tabstop>
-  <tabstop>editNeutronSldReal</tabstop>
-  <tabstop>editNeutronSldImag</tabstop>
-  <tabstop>editCuKaSldReal</tabstop>
-  <tabstop>editCuKaSldImag</tabstop>
-  <tabstop>editMoKaSldReal</tabstop>
-  <tabstop>editMoKaSldImag</tabstop>
-  <tabstop>editNeutronIncXs</tabstop>
-  <tabstop>editNeutronAbsXs</tabstop>
-  <tabstop>editNeutronLength</tabstop>
-  <tabstop>buttonBox</tabstop>
- </tabstops>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>SldPanel</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>SldPanel</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/SlicerParametersUI.ui
===================================================================
--- src/sas/qtgui/UI/SlicerParametersUI.ui	(revision 57b7ee2a03730ca7183c233fa0fcae728926ee09)
+++ 	(revision )
@@ -1,79 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SlicerParametersUI</class>
- <widget class="QDialog" name="SlicerParametersUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>328</width>
-    <height>266</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Slicer Parameters</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0" colspan="2">
-    <widget class="QTableView" name="lstParams"/>
-   </item>
-   <item row="1" column="1">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Close|QDialogButtonBox::Help</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>SlicerParametersUI</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>SlicerParametersUI</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UI/SlitSizeCalculator.ui
===================================================================
--- src/sas/qtgui/UI/SlitSizeCalculator.ui	(revision 0532d7c15f8e5962a80241e030a2c4d28323411d)
+++ 	(revision )
@@ -1,189 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SlitSizeCalculator</class>
- <widget class="QDialog" name="SlitSizeCalculator">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>496</width>
-    <height>253</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <property name="toolTip">
-   <string/>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_3">
-   <item row="0" column="0">
-    <widget class="QGroupBox" name="groupBox">
-     <property name="title">
-      <string>Input</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout">
-      <item row="0" column="0">
-       <layout class="QHBoxLayout" name="horizontalLayout">
-        <item>
-         <widget class="QLabel" name="label">
-          <property name="text">
-           <string>Data</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QLineEdit" name="data_file">
-          <property name="minimumSize">
-           <size>
-            <width>200</width>
-            <height>21</height>
-           </size>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="2" column="0">
-    <spacer name="verticalSpacer_2">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>40</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="1" column="0" colspan="3">
-    <widget class="QGroupBox" name="groupBox_2">
-     <property name="title">
-      <string>Output</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_2">
-      <item row="0" column="0">
-       <layout class="QHBoxLayout" name="horizontalLayout_2">
-        <item>
-         <widget class="QLabel" name="label_3">
-          <property name="text">
-           <string>Slit Size (FWHM/2):</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QLineEdit" name="slit_length_out">
-          <property name="minimumSize">
-           <size>
-            <width>110</width>
-            <height>21</height>
-           </size>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item row="0" column="1">
-       <layout class="QHBoxLayout" name="horizontalLayout_3">
-        <item>
-         <widget class="QLabel" name="label_2">
-          <property name="text">
-           <string>Unit:</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QLineEdit" name="unit_out">
-          <property name="minimumSize">
-           <size>
-            <width>100</width>
-            <height>21</height>
-           </size>
-          </property>
-          <property name="readOnly">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item row="0" column="2">
-    <widget class="QPushButton" name="browseButton">
-     <property name="toolTip">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Compute the thickness or diameter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-     <property name="text">
-      <string>Browse</string>
-     </property>
-    </widget>
-   </item>
-   <item row="4" column="2">
-    <widget class="QPushButton" name="helpButton">
-     <property name="toolTip">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Help using the Kiessing fringe calculator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-     <property name="text">
-      <string>Help</string>
-     </property>
-    </widget>
-   </item>
-   <item row="4" column="0">
-    <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 row="4" column="1">
-    <widget class="QPushButton" name="closeButton">
-     <property name="toolTip">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Close this window.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-     <property name="text">
-      <string>Close</string>
-     </property>
-    </widget>
-   </item>
-   <item row="0" column="1">
-    <spacer name="horizontalSpacer_2">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>40</width>
-       <height>20</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections/>
-</ui>
Index: c/sas/qtgui/UI/TabbedFileLoadUI.ui
===================================================================
--- src/sas/qtgui/UI/TabbedFileLoadUI.ui	(revision 481ff261d4487dbfcc8eabb342125294e0c6f514)
+++ 	(revision )
@@ -1,353 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DataLoadWidget</class>
- <widget class="QTabWidget" name="DataLoadWidget">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>481</width>
-    <height>620</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>TabWidget</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="main_resources.qrc">
-    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset>
-  </property>
-  <property name="currentIndex">
-   <number>0</number>
-  </property>
-  <widget class="QWidget" name="dataTab">
-   <attribute name="title">
-    <string>Data</string>
-   </attribute>
-   <layout class="QGridLayout" name="gridLayout_6">
-    <item row="0" column="0">
-     <widget class="QLabel" name="label">
-      <property name="text">
-       <string>Selection Options</string>
-      </property>
-     </widget>
-    </item>
-    <item row="1" column="0">
-     <widget class="QComboBox" name="cbSelect">
-      <item>
-       <property name="text">
-        <string>Select all</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>Unselect all</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>Select all 1D</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>Unselect all 1D</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>Select all 2D</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>Unselect all 2D</string>
-       </property>
-      </item>
-     </widget>
-    </item>
-    <item row="1" column="1" colspan="2">
-     <spacer name="horizontalSpacer_2">
-      <property name="orientation">
-       <enum>Qt::Horizontal</enum>
-      </property>
-      <property name="sizeHint" stdset="0">
-       <size>
-        <width>352</width>
-        <height>20</height>
-       </size>
-      </property>
-     </spacer>
-    </item>
-    <item row="2" column="0" colspan="3">
-     <widget class="QGroupBox" name="groupBox">
-      <property name="title">
-       <string>Data</string>
-      </property>
-      <layout class="QGridLayout" name="gridLayout_2">
-       <item row="0" column="0">
-        <layout class="QGridLayout" name="gridLayout">
-         <item row="0" column="0" colspan="4">
-          <widget class="QTreeView" name="treeView">
-           <attribute name="headerVisible">
-            <bool>false</bool>
-           </attribute>
-          </widget>
-         </item>
-         <item row="1" column="0">
-          <widget class="QPushButton" name="cmdLoad">
-           <property name="text">
-            <string>Load</string>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="1">
-          <widget class="QPushButton" name="cmdFreeze">
-           <property name="text">
-            <string>Freeze</string>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="2">
-          <spacer name="horizontalSpacer_4">
-           <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 row="1" column="3">
-          <widget class="QPushButton" name="cmdDeleteData">
-           <property name="text">
-            <string>Delete</string>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
-       <item row="1" column="0">
-        <layout class="QHBoxLayout" name="horizontalLayout">
-         <item>
-          <widget class="QPushButton" name="cmdSendTo">
-           <property name="text">
-            <string>Send to</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QComboBox" name="cbFitting">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="sizeAdjustPolicy">
-            <enum>QComboBox::AdjustToContents</enum>
-           </property>
-           <item>
-            <property name="text">
-             <string>Fitting</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Pr inversion</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Invariant</string>
-            </property>
-           </item>
-          </widget>
-         </item>
-         <item>
-          <widget class="QCheckBox" name="chkBatch">
-           <property name="text">
-            <string>Batch mode</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <spacer name="horizontalSpacer">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>197</width>
-             <height>20</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-        </layout>
-       </item>
-      </layout>
-     </widget>
-    </item>
-    <item row="3" column="0" colspan="2">
-     <widget class="QGroupBox" name="groupBox_3">
-      <property name="title">
-       <string>Plot</string>
-      </property>
-      <layout class="QGridLayout" name="gridLayout_3">
-       <item row="0" column="0">
-        <widget class="QPushButton" name="cmdNew">
-         <property name="text">
-          <string>New</string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="0">
-        <widget class="QPushButton" name="cmdAppend">
-         <property name="text">
-          <string>Append to</string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <widget class="QComboBox" name="cbgraph">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="sizeAdjustPolicy">
-          <enum>QComboBox::AdjustToContents</enum>
-         </property>
-         <item>
-          <property name="text">
-           <string>Graph1</string>
-          </property>
-         </item>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </item>
-    <item row="3" column="2">
-     <spacer name="horizontalSpacer_3">
-      <property name="orientation">
-       <enum>Qt::Horizontal</enum>
-      </property>
-      <property name="sizeHint" stdset="0">
-       <size>
-        <width>287</width>
-        <height>20</height>
-       </size>
-      </property>
-     </spacer>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QWidget" name="theoryTab">
-   <attribute name="title">
-    <string>Theory</string>
-   </attribute>
-   <layout class="QGridLayout" name="gridLayout_7">
-    <item row="0" column="0" colspan="2">
-     <widget class="QGroupBox" name="groupBox_2">
-      <property name="title">
-       <string>Theory</string>
-      </property>
-      <layout class="QGridLayout" name="gridLayout_4">
-       <item row="1" column="0">
-        <widget class="QPushButton" name="cmdDeleteTheory">
-         <property name="text">
-          <string>Delete</string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <spacer name="horizontalSpacer_5">
-         <property name="orientation">
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>353</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item row="0" column="0" colspan="2">
-        <widget class="QTreeView" name="freezeView">
-         <attribute name="headerVisible">
-          <bool>false</bool>
-         </attribute>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </item>
-    <item row="1" column="0">
-     <widget class="QGroupBox" name="groupBox_4">
-      <property name="title">
-       <string>Plot</string>
-      </property>
-      <layout class="QGridLayout" name="gridLayout_5">
-       <item row="0" column="0">
-        <widget class="QPushButton" name="cmdNew_2">
-         <property name="text">
-          <string>New</string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="0">
-        <widget class="QPushButton" name="cmdAppend_2">
-         <property name="text">
-          <string>Append to</string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <widget class="QComboBox" name="cbgraph_2">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="sizeAdjustPolicy">
-          <enum>QComboBox::AdjustToContents</enum>
-         </property>
-         <item>
-          <property name="text">
-           <string>Graph1</string>
-          </property>
-         </item>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </item>
-    <item row="1" column="1">
-     <spacer name="horizontalSpacer_6">
-      <property name="orientation">
-       <enum>Qt::Horizontal</enum>
-      </property>
-      <property name="sizeHint" stdset="0">
-       <size>
-        <width>287</width>
-        <height>20</height>
-       </size>
-      </property>
-     </spacer>
-    </item>
-   </layout>
-  </widget>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections/>
-</ui>
Index: c/sas/qtgui/UI/WelcomePanelUI.ui
===================================================================
--- src/sas/qtgui/UI/WelcomePanelUI.ui	(revision b27c681dcc684bfc59c71325a76d3179b807bc16)
+++ 	(revision )
@@ -1,85 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>WelcomePanelUI</class>
- <widget class="QDialog" name="WelcomePanelUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>746</width>
-    <height>947</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0">
-    <widget class="QLabel" name="imgSasView">
-     <property name="text">
-      <string/>
-     </property>
-     <property name="pixmap">
-      <pixmap resource="main_resources.qrc">:/res/SVwelcome.png</pixmap>
-     </property>
-     <property name="alignment">
-      <set>Qt::AlignCenter</set>
-     </property>
-    </widget>
-   </item>
-   <item row="1" column="0">
-    <widget class="Line" name="line">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-    </widget>
-   </item>
-   <item row="2" column="0">
-    <widget class="QLabel" name="lblAcknowledgements">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="text">
-      <string>This work originally developed as part of the DANSE project funded by the NSF under grant DMR-0520547, and currently maintained by NIST, UMD, ORNL, ISIS, ESS, ILL and ANSTO.</string>
-     </property>
-     <property name="wordWrap">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-   <item row="3" column="0">
-    <widget class="QLabel" name="lblVersion">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="text">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;SasView 4.0.0-Alpha&lt;br/&gt;Build: 1&lt;br/&gt;(c) 2009 - 2017, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL and ANSTO&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-    </widget>
-   </item>
-   <item row="4" column="0">
-    <widget class="QLabel" name="lblLink">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="text">
-      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Comments? Bugs? Requests?&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;mailto:help@sasview.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Send us a ticket at: help@sasview.org&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="main_resources.qrc"/>
- </resources>
- <connections/>
-</ui>
Index: c/sas/qtgui/UI/WindowTitleUI.ui
===================================================================
--- src/sas/qtgui/UI/WindowTitleUI.ui	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
+++ 	(revision )
@@ -1,77 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>WindowTitle</class>
- <widget class="QDialog" name="WindowTitle">
-  <property name="windowModality">
-   <enum>Qt::ApplicationModal</enum>
-  </property>
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>287</width>
-    <height>137</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Modify Window Title</string>
-  </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0">
-    <widget class="QLabel" name="label">
-     <property name="text">
-      <string>New title</string>
-     </property>
-    </widget>
-   </item>
-   <item row="0" column="1">
-    <widget class="QLineEdit" name="txtTitle"/>
-   </item>
-   <item row="1" column="0" colspan="2">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>WindowTitle</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>WindowTitle</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
Index: c/sas/qtgui/UnitTesting/AboutBoxTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/AboutBoxTest.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,103 +1,0 @@
-import sys
-import unittest
-import webbrowser
-
-from PyQt4.QtGui import *
-from PyQt4.QtTest import QTest
-from PyQt4.QtCore import *
-from mock import MagicMock
-
-# set up import paths
-import path_prepare
-
-# Local
-from AboutBox import AboutBox
-import sas.qtgui.LocalConfig as LocalConfig
-
-app = QApplication(sys.argv)
-
-class AboutBoxTest(unittest.TestCase):
-    '''Test the AboutBox'''
-    def setUp(self):
-        '''Create the AboutBox'''
-        self.widget = AboutBox(None)
-
-    def tearDown(self):
-        '''Destroy the AboutBox'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QWidget)
-        self.assertEqual(self.widget.windowTitle(), "About")
-        self.assertEqual(self.widget.cmdOK.text(), "OK")
-
-        self.assertIn("SasView", self.widget.label_2.text())
-        # Link buttons pixmaps don't contain image filenames, so can't check this.
-        # self.assertEqual(self.widget.cmdLinkUT.icon().name(), "utlogo.gif")
-
-
-    def testVersion(self):
-        """
-        Assure the version number is as expected
-        """
-        version = self.widget.lblVersion
-        self.assertIsInstance(version, QLabel)
-        self.assertEqual(str(version.text()), str(LocalConfig.__version__))
-
-    def testAbout(self):
-        """
-        Assure the about label is filled properly
-        """
-        about = self.widget.lblAbout
-        self.assertIsInstance(about, QLabel)
-        # build version
-        self.assertIn(str(LocalConfig.__build__), about.text())
-        # License
-        self.assertIn(str(LocalConfig._copyright), about.text())
-        # URLs
-        self.assertIn(str(LocalConfig._homepage), about.text())
-        self.assertIn(str(LocalConfig.__download_page__), about.text())
-        self.assertIn(str(LocalConfig._license), about.text())
-
-        # Are links enabled?
-        self.assertTrue(about.openExternalLinks())
-
-    def testAddActions(self):
-        """
-        Assure link buttons are set up correctly
-        """
-        webbrowser.open = MagicMock()
-        all_hosts = [
-                LocalConfig._nist_url,
-                LocalConfig._umd_url,
-                LocalConfig._sns_url,
-                LocalConfig._nsf_url,
-                LocalConfig._isis_url,
-                LocalConfig._ess_url,
-                LocalConfig._ill_url,
-                LocalConfig._ansto_url,
-                LocalConfig._inst_url]
-
-        # Press the buttons
-        buttonList = self.widget.findChildren(QPushButton)
-        for button in buttonList:
-            QTest.mouseClick(button, Qt.LeftButton)
-            #open_link = webbrowser.open.call_args
-            args, _ = webbrowser.open.call_args
-            # args[0] contains the actual argument sent to open()
-            self.assertIn(args[0], all_hosts)
-
-        # The above test also greedily catches the OK button,
-        # so let's test it separately.
-        # Show the widget
-        self.widget.show()
-        self.assertTrue(self.widget.isVisible())
-        # Click on the OK button
-        QTest.mouseClick(self.widget.cmdOK, Qt.LeftButton)
-        # assure the widget is no longer seen
-        self.assertFalse(self.widget.isVisible())
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/AddTextTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/AddTextTest.py	(revision 9290b1a2e57458d51b13f1acd1798b999372c7d7)
+++ 	(revision )
@@ -1,61 +1,0 @@
-import sys
-import unittest
-from mock import MagicMock
-
-from PyQt4 import QtGui
-
-# set up import paths
-import path_prepare
-
-# Local
-from AddText import AddText
-
-app = QtGui.QApplication(sys.argv)
-
-class AddTextTest(unittest.TestCase):
-    '''Test the AddText'''
-    def setUp(self):
-        '''Create the AddText'''
-        self.widget = AddText(None)
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QtGui.QDialog)
-        self.assertIsInstance(self.widget._font, QtGui.QFont)
-        self.assertEqual(self.widget._color, "black")
-        
-    def testOnFontChange(self):
-        '''Test the QFontDialog output'''
-        font_1 = QtGui.QFont("Helvetica", 15)
-        QtGui.QFontDialog.getFont = MagicMock(return_value=(font_1, True))
-        # Call the method
-        self.widget.onFontChange(None)
-        # Check that the text field got the new font info
-        self.assertEqual(self.widget.textEdit.currentFont(), font_1)
-
-        # See that rejecting the dialog doesn't modify the font
-        font_2 = QtGui.QFont("Arial", 9)
-        QtGui.QFontDialog.getFont = MagicMock(return_value=(font_2, False))
-        # Call the method
-        self.widget.onFontChange(None)
-        # Check that the text field retained the previous font info
-        self.assertEqual(self.widget.textEdit.currentFont(), font_1)
-
-    def testOnColorChange(self):
-        ''' Test the QColorDialog output'''
-        new_color = QtGui.QColor("red")
-        QtGui.QColorDialog.getColor = MagicMock(return_value=new_color)
-        # Call the method
-        self.widget.onColorChange(None)
-        # Check that the text field got the new color info for text
-        self.assertEqual(self.widget.textEdit.palette().color(QtGui.QPalette.Text), new_color)
-        # ... and the hex value of this color is correct
-        self.assertEqual(self.widget.color(), "#ff0000")
-        
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/BoxSumTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/BoxSumTest.py	(revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ 	(revision )
@@ -1,47 +1,0 @@
-import sys
-import unittest
-from mock import MagicMock
-
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-
-# set up import paths
-import path_prepare
-
-# Local
-from BoxSum import BoxSum
-
-app = QtGui.QApplication(sys.argv)
-
-class BoxSumTest(unittest.TestCase):
-    '''Test the BoxSum'''
-    def setUp(self):
-        '''Create the BoxSum'''
-        # example model
-        model = QtGui.QStandardItemModel()
-        parameters = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
-        for index, parameter in enumerate(parameters):
-            model.setData(model.index(0, index),
-                    QtCore.QVariant(parameter))
-        self.widget = BoxSum(None, model=model)
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(0), QtGui.QLineEdit)
-        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(1), QtGui.QLineEdit)
-        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(2), QtGui.QLineEdit)
-        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(3), QtGui.QLineEdit)
-        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(4), QtGui.QLabel)
-        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(5), QtGui.QLabel)
-        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(6), QtGui.QLabel)
-        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(7), QtGui.QLabel)
-        self.assertIsInstance(self.widget.mapper.mappedWidgetAt(8), QtGui.QLabel)
-        
-        
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/ColorMapTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/ColorMapTest.py	(revision 5d89f43266c67cb96a7bf395800ce4cce896c9f8)
+++ 	(revision )
@@ -1,200 +1,0 @@
-import sys
-import unittest
-import numpy
-
-from PyQt4 import QtGui
-from mock import MagicMock
-import matplotlib as mpl
-
-# set up import paths
-import path_prepare
-
-from sas.sasgui.guiframe.dataFitting import Data2D
-import sas.qtgui.Plotter2D as Plotter2D
-from UnitTesting.TestUtils import WarningTestNotImplemented
-from UnitTesting.TestUtils import QtSignalSpy
-
-# Local
-from sas.qtgui.ColorMap import ColorMap
-
-app = QtGui.QApplication(sys.argv)
-
-class ColorMapTest(unittest.TestCase):
-    '''Test the ColorMap'''
-    def setUp(self):
-        '''Create the ColorMap'''
-        self.plotter = Plotter2D.Plotter2D(None, quickplot=True)
-
-        self.data = Data2D(image=[0.1]*4,
-                           qx_data=[1.0, 2.0, 3.0, 4.0],
-                           qy_data=[10.0, 11.0, 12.0, 13.0],
-                           dqx_data=[0.1, 0.2, 0.3, 0.4],
-                           dqy_data=[0.1, 0.2, 0.3, 0.4],
-                           q_data=[1,2,3,4],
-                           xmin=-1.0, xmax=5.0,
-                           ymin=-1.0, ymax=15.0,
-                           zmin=-1.0, zmax=20.0)
-
-        self.data.title="Test data"
-        self.data.id = 1
-        self.widget = ColorMap(parent=self.plotter, data=self.data)
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QtGui.QDialog)
-
-        self.assertEqual(self.widget._cmap_orig, "jet")
-        self.assertEqual(len(self.widget.all_maps), 144)
-        self.assertEqual(len(self.widget.maps), 72)
-        self.assertEqual(len(self.widget.rmaps), 72)
-
-        self.assertEqual(self.widget.lblWidth.text(), "0")
-        self.assertEqual(self.widget.lblHeight.text(), "0")
-        self.assertEqual(self.widget.lblQmax.text(), "15.8")
-        self.assertEqual(self.widget.lblStopRadius.text(), "-1")
-        self.assertFalse(self.widget.chkReverse.isChecked())
-        self.assertEqual(self.widget.cbColorMap.count(), 72)
-        self.assertEqual(self.widget.cbColorMap.currentIndex(), 60)
-
-        # validators
-        self.assertIsInstance(self.widget.txtMinAmplitude.validator(), QtGui.QDoubleValidator)
-        self.assertIsInstance(self.widget.txtMaxAmplitude.validator(), QtGui.QDoubleValidator)
-
-        # Ranges
-        self.assertEqual(self.widget.txtMinAmplitude.text(), "0")
-        self.assertEqual(self.widget.txtMaxAmplitude.text(), "100")
-        self.assertIsInstance(self.widget.slider, QtGui.QSlider)
-
-    def testOnReset(self):
-        '''Check the dialog reset function'''
-        # Set some controls to non-default state
-        self.widget.cbColorMap.setCurrentIndex(20)
-        self.widget.chkReverse.setChecked(True)
-        self.widget.txtMinAmplitude.setText("20.0")
-
-        # Reset the widget state
-        self.widget.onReset()
-
-        # Assure things went back to default
-        self.assertEqual(self.widget.cbColorMap.currentIndex(), 20)
-        self.assertFalse(self.widget.chkReverse.isChecked())
-        self.assertEqual(self.widget.txtMinAmplitude.text(), "0")
-
-    def testOnApply(self):
-        '''Check the dialog apply function'''
-        # Set some controls to non-default state
-        self.widget.show()
-        self.widget.cbColorMap.setCurrentIndex(20) # PuRd_r
-        self.widget.chkReverse.setChecked(True)
-        self.widget.txtMinAmplitude.setText("20.0")
-
-        spy_apply = QtSignalSpy(self.widget, self.widget.apply_signal)
-        # Reset the widget state
-        self.widget.onApply()
-
-        # Assure the widget is still up and the signal was sent.
-        self.assertTrue(self.widget.isVisible())
-        self.assertEqual(spy_apply.count(), 1)
-        self.assertIn('PuRd_r', spy_apply.called()[0]['args'][1])
-
-    def testInitMapCombobox(self):
-        '''Test the combo box initializer'''
-        # Set a color map from the direct list
-        self.widget._cmap = "gnuplot"
-        self.widget.initMapCombobox()
-
-        # Check the combobox
-        self.assertEqual(self.widget.cbColorMap.currentIndex(), 55)
-        self.assertFalse(self.widget.chkReverse.isChecked())
-
-        # Set a reversed value
-        self.widget._cmap = "hot_r"
-        self.widget.initMapCombobox()
-        # Check the combobox
-        self.assertEqual(self.widget.cbColorMap.currentIndex(), 56)
-        self.assertTrue(self.widget.chkReverse.isChecked())
-
-    def testInitRangeSlider(self):
-        '''Test the range slider initializer'''
-        # Set a color map from the direct list
-        self.widget._cmap = "gnuplot"
-        self.widget.initRangeSlider()
-
-        # Check the values
-        self.assertEqual(self.widget.slider.minimum(), 0)
-        self.assertEqual(self.widget.slider.maximum(), 100)
-        self.assertEqual(self.widget.slider.orientation(), 1)
-
-        # Emit new low value
-        self.widget.slider.lowValueChanged.emit(5)
-        # Assure the widget received changes
-        self.assertEqual(self.widget.txtMinAmplitude.text(), "5")
-
-        # Emit new high value
-        self.widget.slider.highValueChanged.emit(45)
-        # Assure the widget received changes
-        self.assertEqual(self.widget.txtMinAmplitude.text(), "45")
-
-    def testOnMapIndexChange(self):
-        '''Test the response to the combo box index change'''
-
-        self.widget.canvas.draw = MagicMock()
-        mpl.colorbar.ColorbarBase = MagicMock()
-
-        # simulate index change
-        self.widget.cbColorMap.setCurrentIndex(1)
-
-        # Check that draw() got called
-        self.assertTrue(self.widget.canvas.draw.called)
-        self.assertTrue(mpl.colorbar.ColorbarBase.called)
-
-    def testOnColorMapReversed(self):
-        '''Test reversing the color map functionality'''
-        # Check the defaults
-        self.assertEqual(self.widget._cmap, "jet")
-        self.widget.cbColorMap.addItems = MagicMock()
-
-        # Reverse the choice
-        self.widget.onColorMapReversed(True)
-
-        # check the behaviour
-        self.assertEqual(self.widget._cmap, "jet_r")
-        self.assertTrue(self.widget.cbColorMap.addItems.called)
-
-    def testOnAmplitudeChange(self):
-        '''Check the callback method for responding to changes in textboxes'''
-        self.widget.canvas.draw = MagicMock()
-        mpl.colors.Normalize = MagicMock()
-        mpl.colorbar.ColorbarBase = MagicMock()
-
-        self.widget.vmin = 0.0
-        self.widget.vmax = 100.0
-
-        # good values in fields
-        self.widget.txtMinAmplitude.setText("1.0")
-        self.widget.txtMaxAmplitude.setText("10.0")
-
-        self.widget.onAmplitudeChange()
-
-        # Check the arguments to Normalize
-        mpl.colors.Normalize.assert_called_with(vmin=1.0, vmax=10.0)
-        self.assertTrue(self.widget.canvas.draw.called)
-
-        # Bad values in fields
-        self.widget.txtMinAmplitude.setText("cake")
-        self.widget.txtMaxAmplitude.setText("more cake")
-
-        self.widget.onAmplitudeChange()
-
-        # Check the arguments to Normalize - should be defaults
-        mpl.colors.Normalize.assert_called_with(vmin=0.0, vmax=100.0)
-        self.assertTrue(self.widget.canvas.draw.called)
-
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/DataExplorerTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/DataExplorerTest.py	(revision 2155824bc3dcd6c0afe1204caa0357472cf9b060)
+++ 	(revision )
@@ -1,807 +1,0 @@
-import sys
-import unittest
-
-from PyQt4.QtGui import *
-from PyQt4.QtTest import QTest
-from PyQt4.QtCore import *
-from mock import MagicMock
-from mock import patch
-from mpl_toolkits.mplot3d import Axes3D
-
-# set up import paths
-import path_prepare
-
-# Local
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sascalc.dataloader.loader import Loader
-from sas.sasgui.guiframe.data_manager import DataManager
-
-from DataExplorer import DataExplorerWindow
-from GuiManager import GuiManager
-from sas.qtgui.GuiUtils import *
-from UnitTesting.TestUtils import QtSignalSpy
-from sas.qtgui.Plotter import Plotter
-from sas.qtgui.Plotter2D import Plotter2D
-import sas.qtgui.PlotHelper as PlotHelper
-
-app = QApplication(sys.argv)
-
-class DataExplorerTest(unittest.TestCase):
-    '''Test the Data Explorer GUI'''
-    def setUp(self):
-        '''Create the GUI'''
-        class MyPerspective(object):
-            def communicator(self):
-                return Communicate()
-            def allowBatch(self):
-                return False
-            def setData(self, data_item=None):
-                return None
-            def title(self):
-                return "Dummy Perspective"
-
-        class dummy_manager(object):
-            def communicator(self):
-                return Communicate()
-            def perspective(self):
-                return MyPerspective()
-            def workspace(self):
-                return None
-
-        self.form = DataExplorerWindow(None, dummy_manager())
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.form.close()
-        self.form = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        # Tab widget
-        self.assertIsInstance(self.form, QTabWidget)
-        self.assertEqual(self.form.count(), 2)
-
-        # Buttons - data tab
-        self.assertEqual(self.form.cmdLoad.text(), "Load data")
-        self.assertEqual(self.form.cmdDeleteData.text(), "Delete")
-        self.assertEqual(self.form.cmdDeleteTheory.text(), "Delete")
-        self.assertEqual(self.form.cmdFreeze.text(), "Freeze Theory")
-        self.assertEqual(self.form.cmdSendTo.text(), "Send data to")
-        self.assertEqual(self.form.cmdSendTo.iconSize(), QSize(48, 48))
-        self.assertIsInstance(self.form.cmdSendTo.icon(), QIcon)
-        self.assertEqual(self.form.chkBatch.text(), "Batch mode")
-        self.assertFalse(self.form.chkBatch.isChecked())
-
-        # Buttons - theory tab
-
-        # Combo boxes
-        self.assertEqual(self.form.cbSelect.count(), 6)
-        self.assertEqual(self.form.cbSelect.currentIndex(), 0)
-
-        # Models - data
-        self.assertIsInstance(self.form.model, QStandardItemModel)
-        self.assertEqual(self.form.treeView.model().rowCount(), 0)
-        self.assertEqual(self.form.treeView.model().columnCount(), 0)
-        self.assertEqual(self.form.model.rowCount(), 0)
-        self.assertEqual(self.form.model.columnCount(), 0)
-        self.assertIsInstance(self.form.data_proxy, QSortFilterProxyModel)
-        self.assertEqual(self.form.data_proxy.sourceModel(), self.form.model)
-        self.assertEqual("[^()]", str(self.form.data_proxy.filterRegExp().pattern()))
-        self.assertIsInstance(self.form.treeView, QTreeView)
-
-        # Models - theory
-        self.assertIsInstance(self.form.theory_model, QStandardItemModel)
-        self.assertEqual(self.form.freezeView.model().rowCount(), 0)
-        self.assertEqual(self.form.freezeView.model().columnCount(), 0)
-        self.assertEqual(self.form.theory_model.rowCount(), 0)
-        self.assertEqual(self.form.theory_model.columnCount(), 0)
-        self.assertIsInstance(self.form.theory_proxy, QSortFilterProxyModel)
-        self.assertEqual(self.form.theory_proxy.sourceModel(), self.form.theory_model)
-        self.assertEqual("[^()]", str(self.form.theory_proxy.filterRegExp().pattern()))
-        self.assertIsInstance(self.form.freezeView, QTreeView)
-
-    def testWidgets(self):
-        """
-        Test if all required widgets got added
-        """
-    def testLoadButton(self):
-        loadButton = self.form.cmdLoad
-
-        filename = "cyl_400_20.txt"
-        # Initialize signal spy instances
-        spy_file_read = QtSignalSpy(self.form, self.form.communicator.fileReadSignal)
-
-        # Return no files.
-        QtGui.QFileDialog.getOpenFileNames = MagicMock(return_value=None)
-
-        # Click on the Load button
-        QTest.mouseClick(loadButton, Qt.LeftButton)
-
-        # Test the getOpenFileName() dialog called once
-        self.assertTrue(QtGui.QFileDialog.getOpenFileNames.called)
-        QtGui.QFileDialog.getOpenFileNames.assert_called_once()
-
-        # Make sure the signal has not been emitted
-        self.assertEqual(spy_file_read.count(), 0)
-
-        # Now, return a single file
-        QtGui.QFileDialog.getOpenFileNames = MagicMock(return_value=filename)
-
-        # Click on the Load button
-        QTest.mouseClick(loadButton, Qt.LeftButton)
-        QtGui.qApp.processEvents()
-
-        # Test the getOpenFileName() dialog called once
-        self.assertTrue(QtGui.QFileDialog.getOpenFileNames.called)
-        QtGui.QFileDialog.getOpenFileNames.assert_called_once()
-
-        # Expected one spy instance
-        #self.assertEqual(spy_file_read.count(), 1)
-        #self.assertIn(filename, str(spy_file_read.called()[0]['args'][0]))
-
-    def testLoadFiles(self):
-        """
-        Test progress bar update while loading of multiple files
-        """
-        # Set up the spy on progress bar update signal
-        spy_progress_bar_update = QtSignalSpy(self.form,
-            self.form.communicator.progressBarUpdateSignal)
-
-        # Populate the model
-        filename = ["cyl_400_20.txt", "Dec07031.ASC", "cyl_400_20.txt"]
-        self.form.readData(filename)
-
-        # 0, 0, 33, 66, -1 -> 5 signals reaching progressBar
-        self.assertEqual(spy_progress_bar_update.count(), 5)
-
-        expected_list = [0, 0, 33, 66, -1]
-        spied_list = [spy_progress_bar_update.called()[i]['args'][0] for i in xrange(5)]
-        self.assertEqual(expected_list, spied_list)
-        
-    def testDeleteButton(self):
-        """
-        Functionality of the delete button
-        """
-        deleteButton = self.form.cmdDeleteData
-
-        # Mock the confirmation dialog with return=No
-        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.No)
-
-        # Populate the model
-        filename = ["cyl_400_20.txt", "Dec07031.ASC", "cyl_400_20.txt"]
-        self.form.readData(filename)
-
-        # Assure the model contains three items
-        self.assertEqual(self.form.model.rowCount(), 3)
-
-        # Assure the checkboxes are on
-        item1 = self.form.model.item(0)
-        item2 = self.form.model.item(1)
-        item3 = self.form.model.item(2)
-        self.assertTrue(item1.checkState() == QtCore.Qt.Checked)
-        self.assertTrue(item2.checkState() == QtCore.Qt.Checked)
-        self.assertTrue(item3.checkState() == QtCore.Qt.Checked)
-
-        # Click on the delete  button
-        QTest.mouseClick(deleteButton, Qt.LeftButton)
-
-        # Test the warning dialog called once
-        self.assertTrue(QtGui.QMessageBox.question.called)
-
-        # Assure the model still contains the items
-        self.assertEqual(self.form.model.rowCount(), 3)
-
-        # Now, mock the confirmation dialog with return=Yes
-        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.Yes)
-
-        # Click on the delete  button
-        QTest.mouseClick(deleteButton, Qt.LeftButton)
-
-        # Test the warning dialog called once
-        self.assertTrue(QtGui.QMessageBox.question.called)
-
-        # Assure the model contains no items
-        self.assertEqual(self.form.model.rowCount(), 0)
-
-        # Click delete once again to assure no nasty behaviour on empty model
-        QTest.mouseClick(deleteButton, Qt.LeftButton)
-
-    def testDeleteTheory(self):
-        """
-        Test that clicking "Delete" in theories tab removes selected indices
-        """
-        deleteButton = self.form.cmdDeleteTheory
-
-        # Mock the confirmation dialog with return=No
-        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.No)
-
-        # Populate the model
-        item1 = QtGui.QStandardItem(True)
-        item1.setCheckable(True)
-        item1.setCheckState(QtCore.Qt.Checked)
-        item1.setText("item 1")
-        self.form.theory_model.appendRow(item1)
-        item2 = QtGui.QStandardItem(True)
-        item2.setCheckable(True)
-        item2.setCheckState(QtCore.Qt.Unchecked)
-        item2.setText("item 2")
-        self.form.theory_model.appendRow(item2)
-
-        # Assure the model contains two items
-        self.assertEqual(self.form.theory_model.rowCount(), 2)
-
-        # Assure the checkboxes are on
-        self.assertTrue(item1.checkState() == QtCore.Qt.Checked)
-        self.assertTrue(item2.checkState() == QtCore.Qt.Unchecked)
-
-        # Click on the delete  button
-        QTest.mouseClick(deleteButton, Qt.LeftButton)
-
-        # Test the warning dialog called once
-        self.assertTrue(QtGui.QMessageBox.question.called)
-
-        # Assure the model still contains the items
-        self.assertEqual(self.form.theory_model.rowCount(), 2)
-
-        # Now, mock the confirmation dialog with return=Yes
-        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.Yes)
-
-        # Click on the delete  button
-        QTest.mouseClick(deleteButton, Qt.LeftButton)
-
-        # Test the warning dialog called once
-        self.assertTrue(QtGui.QMessageBox.question.called)
-
-        # Assure the model contains 1 item
-        self.assertEqual(self.form.theory_model.rowCount(), 1)
-
-        # Set the remaining item to checked
-        self.form.theory_model.item(0).setCheckState(QtCore.Qt.Checked)
-
-        # Click on the delete button again
-        QTest.mouseClick(deleteButton, Qt.LeftButton)
-
-        # Assure the model contains no items
-        self.assertEqual(self.form.theory_model.rowCount(), 0)
-
-        # Click delete once again to assure no nasty behaviour on empty model
-        QTest.mouseClick(deleteButton, Qt.LeftButton)
-
-
-    def testSendToButton(self):
-        """
-        Test that clicking the Send To button sends checked data to a perspective
-        """
-        # Send empty data
-        mocked_perspective = self.form.parent.perspective()
-        mocked_perspective.setData = MagicMock()
-
-        # Click on the Send To  button
-        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
-
-        # The set_data method not called
-        self.assertFalse(mocked_perspective.setData.called)
-               
-        # Populate the model
-        filename = ["cyl_400_20.txt"]
-        self.form.readData(filename)
-
-        # setData is the method we want to see called
-        mocked_perspective = self.form.parent.perspective()
-        mocked_perspective.setData = MagicMock(filename)
-
-        # Assure the checkbox is on
-        self.form.cbSelect.setCurrentIndex(0)
-
-        # Click on the Send To  button
-        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
-
-        # Test the set_data method called once
-        #self.assertTrue(mocked_perspective.setData.called)
-
-        # open another file
-        filename = ["cyl_400_20.txt"]
-        self.form.readData(filename)
-
-        # Mock the warning message
-        QtGui.QMessageBox = MagicMock()
-
-        # Click on the button
-        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
-
-        # Assure the message box popped up
-        QtGui.QMessageBox.assert_called_once()
-
-    def testDataSelection(self):
-        """
-        Tests the functionality of the Selection Option combobox
-        """
-        # Populate the model with 1d and 2d data
-        filename = ["cyl_400_20.txt", "Dec07031.ASC"]
-        self.form.readData(filename)
-
-        # Unselect all data
-        self.form.cbSelect.setCurrentIndex(1)
-
-        # Test the current selection
-        item1D = self.form.model.item(0)
-        item2D = self.form.model.item(1)
-        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
-        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)        
-
-        # Select all data
-        self.form.cbSelect.setCurrentIndex(0)
-
-        # Test the current selection
-        self.assertTrue(item1D.checkState() == QtCore.Qt.Checked)
-        self.assertTrue(item2D.checkState() == QtCore.Qt.Checked)        
-
-        # select 1d data
-        self.form.cbSelect.setCurrentIndex(2)
-
-        # Test the current selection
-        self.assertTrue(item1D.checkState() == QtCore.Qt.Checked)
-        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)        
-
-        # unselect 1d data
-        self.form.cbSelect.setCurrentIndex(3)
-
-        # Test the current selection
-        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
-        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)        
-
-        # select 2d data
-        self.form.cbSelect.setCurrentIndex(4)
-
-        # Test the current selection
-        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
-        self.assertTrue(item2D.checkState() == QtCore.Qt.Checked)        
-
-        # unselect 2d data
-        self.form.cbSelect.setCurrentIndex(5)
-
-        # Test the current selection
-        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
-        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)        
-
-        # choose impossible index and assure the code raises
-        #with self.assertRaises(Exception):
-        #    self.form.cbSelect.setCurrentIndex(6)
-
-    def testFreezeTheory(self):
-        """
-        Assure theory freeze functionality works
-        """
-        # Not yet tested - agree on design first.
-        pass
-
-    def testRecursivelyCloneItem(self):
-        """
-        Test the rescursive QAbstractItem/QStandardItem clone
-        """
-        # Create an item with several branches
-        item1 = QtGui.QStandardItem()
-        item2 = QtGui.QStandardItem()
-        item3 = QtGui.QStandardItem()
-        item4 = QtGui.QStandardItem()
-        item5 = QtGui.QStandardItem()
-        item6 = QtGui.QStandardItem()
-
-        item4.appendRow(item5)
-        item2.appendRow(item4)
-        item2.appendRow(item6)
-        item1.appendRow(item2)
-        item1.appendRow(item3)
-
-        # Clone
-        new_item = self.form.recursivelyCloneItem(item1)
-
-        # assure the trees look identical
-        self.assertEqual(item1.rowCount(), new_item.rowCount())
-        self.assertEqual(item1.child(0).rowCount(), new_item.child(0).rowCount())
-        self.assertEqual(item1.child(1).rowCount(), new_item.child(1).rowCount())
-        self.assertEqual(item1.child(0).child(0).rowCount(), new_item.child(0).child(0).rowCount())
-
-    def testReadData(self):
-        """
-        Test the low level readData() method
-        """
-        filename = ["cyl_400_20.txt"]
-        self.form.manager.add_data = MagicMock()
-
-        # Initialize signal spy instances
-        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
-        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
-
-        # Read in the file
-        self.form.readData(filename)
-
-        # Expected two status bar updates
-        self.assertEqual(spy_status_update.count(), 2)
-        self.assertIn(filename[0], str(spy_status_update.called()[0]['args'][0]))
-
-
-        # Check that the model contains the item
-        self.assertEqual(self.form.model.rowCount(), 1)
-        self.assertEqual(self.form.model.columnCount(), 1)
-
-        # The 0th item header should be the name of the file
-        model_item = self.form.model.index(0,0)
-        model_name = str(self.form.model.data(model_item).toString())
-        self.assertEqual(model_name, filename[0])
-
-    def skip_testDisplayHelp(self): # Skip due to help path change
-        """
-        Test that the Help window gets shown correctly
-        """
-        partial_url = "sasgui/guiframe/data_explorer_help.html"
-        button1 = self.form.cmdHelp
-        button2 = self.form.cmdHelp_2
-
-        # Click on the Help button
-        QTest.mouseClick(button1, Qt.LeftButton)
-        qApp.processEvents()
-
-        # Check the browser
-        self.assertIn(partial_url, str(self.form._helpView.url()))
-        # Close the browser
-        self.form._helpView.close()
-
-        # Click on the Help_2 button
-        QTest.mouseClick(button2, Qt.LeftButton)
-        qApp.processEvents()
-        # Check the browser
-        self.assertIn(partial_url, str(self.form._helpView.url()))
-
-    def testLoadFile(self):
-        """
-        Test the threaded call to readData()
-        """
-        #self.form.loadFile()
-        pass
-
-    def testGetWList(self):
-        """
-        Test the list of known extensions
-        """
-        w_list = self.form.getWlist()
-
-        defaults = 'All (*.*);;canSAS files (*.xml);;SESANS files' +\
-            ' (*.ses);;ASCII files (*.txt);;IGOR 2D files (*.asc);;' +\
-            'IGOR/DAT 2D Q_map files (*.dat);;IGOR 1D files (*.abs);;'+\
-            'HFIR 1D files (*.d1d);;DANSE files (*.sans);;NXS files (*.nxs)'
-        default_list = defaults.split(';;')
-
-        for def_format in default_list:
-            self.assertIn(def_format, w_list)
-       
-    def testLoadComplete(self):
-        """
-        Test the callback method updating the data object
-        """
-        message="Loading Data Complete"
-        data_dict = {"a1":Data1D()}
-        output_data = (data_dict, message)
-
-        self.form.manager.add_data = MagicMock()
-
-        # Initialize signal spy instances
-        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
-        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
-
-        # Read in the file
-        self.form.loadComplete(output_data)
-
-        # "Loading data complete" no longer sent in LoadFile but in callback
-        self.assertIn("Loading Data Complete", str(spy_status_update.called()[0]['args'][0]))
-
-        # Expect one Data Received signal
-        self.assertEqual(spy_data_received.count(), 1)
-
-        # Assure returned dictionary has correct data
-        # We don't know the data ID, so need to iterate over dict
-        data_dict = spy_data_received.called()[0]['args'][0]
-        for data_key, data_value in data_dict.iteritems():
-            self.assertIsInstance(data_value, Data1D)
-
-        # Assure add_data on data_manager was called (last call)
-        self.assertTrue(self.form.manager.add_data.called)
-
-    def testNewPlot1D(self):
-        """
-        Creating new plots from Data1D/2D
-        """
-        loader = Loader()
-        manager = DataManager()
-        PlotHelper.clear()
-        self.form.enableGraphCombo(None)
-
-        # Make sure the controls are disabled
-        self.assertFalse(self.form.cbgraph.isEnabled())
-        self.assertFalse(self.form.cmdAppend.isEnabled())
-
-        # get Data1D
-        p_file="cyl_400_20.txt"
-        output_object = loader.load(p_file)
-        new_data = [manager.create_gui_data(output_object, p_file)]
-
-        # Mask retrieval of the data
-        self.form.plotsFromCheckedItems = MagicMock(return_value=new_data)
-
-        # Mask plotting
-        self.form.parent.workspace = MagicMock()
-
-        # Call the plotting method
-        self.form.newPlot()
-
-        # The plot was registered
-        self.assertEqual(len(PlotHelper.currentPlots()), 1)
-
-        self.assertTrue(self.form.cbgraph.isEnabled())
-        self.assertTrue(self.form.cmdAppend.isEnabled())
-
-    def testNewPlot2D(self):
-        """
-        Creating new plots from Data1D/2D
-        """
-        loader = Loader()
-        manager = DataManager()
-        PlotHelper.clear()
-        self.form.enableGraphCombo(None)
-
-        # Make sure the controls are disabled
-        self.assertFalse(self.form.cbgraph.isEnabled())
-        self.assertFalse(self.form.cmdAppend.isEnabled())
-
-        # get Data2D
-        p_file="Dec07031.ASC"
-        output_object = loader.load(p_file)
-        new_data = [manager.create_gui_data(output_object, p_file)]
-
-        # Mask retrieval of the data
-        self.form.plotsFromCheckedItems = MagicMock(return_value=new_data)
-
-        # Mask plotting
-        self.form.parent.workspace = MagicMock()
-
-        # Call the plotting method
-        self.form.newPlot()
-
-        # The plot was registered
-        self.assertEqual(len(PlotHelper.currentPlots()), 1)
-
-        self.assertTrue(self.form.cbgraph.isEnabled())
-        self.assertTrue(self.form.cmdAppend.isEnabled())
-
-    @patch('sas.qtgui.GuiUtils.plotsFromCheckedItems')
-    def testAppendPlot(self, test_patch):
-        """
-        Creating new plots from Data1D/2D
-        """
-        loader = Loader()
-        manager = DataManager()
-
-        PlotHelper.clear()
-        self.form.enableGraphCombo(None)
-
-        # Make sure the controls are disabled
-        self.assertFalse(self.form.cbgraph.isEnabled())
-        self.assertFalse(self.form.cmdAppend.isEnabled())
-
-        # get Data1D
-        p_file="cyl_400_20.txt"
-        output_object = loader.load(p_file)
-        output_item = QtGui.QStandardItem()
-        new_data = [(output_item, manager.create_gui_data(output_object, p_file))]
-
-        # Mask plotting
-        self.form.parent.workspace = MagicMock()
-
-        # Mask the plot show call
-        Plotter.show = MagicMock()
-
-        # Mask retrieval of the data
-        test_patch.return_value = new_data
-
-        # Call the plotting method
-        self.form.newPlot()
-
-        # Call the plotting method again, so we have 2 graphs
-        self.form.newPlot()
-
-        # See that we have two plots
-        self.assertEqual(len(PlotHelper.currentPlots()), 2)
-
-        # Add data to plot #1
-        self.form.cbgraph.setCurrentIndex(1)
-        self.form.appendPlot()
-
-        # See that we still have two plots
-        self.assertEqual(len(PlotHelper.currentPlots()), 2)
-
-    def testUpdateGraphCombo(self):
-        """
-        Test the combo box update
-        """
-        PlotHelper.clear()
-
-        graph_list=["1","2","3"]
-        self.form.updateGraphCombo(graph_list)
-
-        self.assertEqual(self.form.cbgraph.count(), 3)
-        self.assertEqual(self.form.cbgraph.currentText(), '1')
-
-        graph_list=[]
-        self.form.updateGraphCombo(graph_list)
-        self.assertEqual(self.form.cbgraph.count(), 0)
-
-    def testUpdateModelFromPerspective(self):
-        """
-        Assure the model update is correct
-        """
-        good_item = QtGui.QStandardItem()
-        bad_item = "I'm so bad"
-
-        self.form.model.reset = MagicMock()
-
-        self.form.updateModelFromPerspective(good_item)
-
-        # See that the model got reset
-        self.form.model.reset.assert_called_once()
-
-        # See that the bad item causes raise
-        with self.assertRaises(Exception):
-            self.form.updateModelFromPerspective(bad_item)
-
-    def testContextMenu(self):
-        """
-        See if the context menu is present
-        """
-        # get Data1D
-        p_file=["cyl_400_20.txt"]
-        # Read in the file
-        output, message = self.form.readData(p_file)
-        self.form.loadComplete((output, message))
-
-        # Pick up the treeview index corresponding to that file
-        index = self.form.treeView.indexAt(QtCore.QPoint(5,5))
-        self.form.show()
-
-        # Find out the center pointof the treeView row
-        rect = self.form.treeView.visualRect(index).center()
-
-        self.form.context_menu.exec_ = MagicMock()
-
-        # Move the mouse pointer to the first row
-        QTest.mouseMove(self.form.treeView.viewport(), pos=rect)
-
-        # This doesn't invoke the action/signal. Investigate why?
-        # QTest.mouseClick(self.form.treeView.viewport(), Qt.RightButton, pos=rect)
-
-        # Instead, send the signal directly
-        self.form.treeView.customContextMenuRequested.emit(rect)
-
-        # app.exec_() # debug
-
-        # See that the menu has been shown
-        self.form.context_menu.exec_.assert_called_once()
-
-    def testShowDataInfo(self):
-        """
-        Test of the showDataInfo method
-        """
-        # get Data1D
-        p_file=["cyl_400_20.txt"]
-        # Read in the file
-        output, message = self.form.readData(p_file)
-        self.form.loadComplete((output, message))
-
-        # select the data
-        self.form.treeView.selectAll()
-
-        # Call the tested method
-        self.form.showDataInfo()
-
-        # Test the properties
-        self.assertTrue(self.form.txt_widget.isReadOnly())
-        self.assertEqual(self.form.txt_widget.windowTitle(), "Data Info: cyl_400_20.txt")
-        self.assertIn("Waveln_max", self.form.txt_widget.toPlainText())
-
-        # Slider moved all the way up
-        self.assertEqual(self.form.txt_widget.verticalScrollBar().sliderPosition(), 0)
-
-    def testSaveDataAs(self):
-        """
-        Test the Save As context menu action
-        """
-        # get Data1D
-        p_file=["cyl_400_20.txt"]
-        # Read in the file
-        output, message = self.form.readData(p_file)
-        self.form.loadComplete((output, message))
-
-        # select the data
-        self.form.treeView.selectAll()
-
-        QFileDialog.getSaveFileName = MagicMock()
-
-        # Call the tested method
-        self.form.saveDataAs()
-        QFileDialog.getSaveFileName.assert_called_with(
-                                caption="Save As",
-                                directory='cyl_400_20_out.txt',
-                                filter='Text files (*.txt);;CanSAS 1D files(*.xml)',
-                                parent=None)
-        QFileDialog.getSaveFileName.assert_called_once()
-
-        # get Data2D
-        p_file=["Dec07031.ASC"]
-        # Read in the file
-        output, message = self.form.readData(p_file)
-        self.form.loadComplete((output, message))
-
-        # select the data
-        index = self.form.model.index(1, 0)
-        selmodel = self.form.treeView.selectionModel()
-        selmodel.setCurrentIndex(index, QItemSelectionModel.NoUpdate)
-        selmodel.select(index, QItemSelectionModel.Select|QItemSelectionModel.Rows)
-
-        QFileDialog.getSaveFileName = MagicMock()
-
-        # Call the tested method
-        self.form.saveDataAs()
-        QFileDialog.getSaveFileName.assert_called_with(
-                                caption="Save As",
-                                directory='Dec07031_out.dat',
-                                filter='IGOR/DAT 2D file in Q_map (*.dat)',
-                                parent=None)
-        QFileDialog.getSaveFileName.assert_called_once()
-
-    def testQuickDataPlot(self):
-        """
-        Quick data plot generation.
-        """
-        # get Data1D
-        p_file=["cyl_400_20.txt"]
-        # Read in the file
-        output, message = self.form.readData(p_file)
-        self.form.loadComplete((output, message))
-
-        # select the data
-        self.form.treeView.selectAll()
-
-        Plotter.show = MagicMock() # for masking the display
-
-        self.form.quickDataPlot()
-        self.assertTrue(Plotter.show.called)
-
-    def testQuickData3DPlot(self):
-        """
-        Slow(er) 3D data plot generation.
-        """
-        # get Data1D
-        p_file=["Dec07031.ASC"]
-        # Read in the file
-        output, message = self.form.readData(p_file)
-        self.form.loadComplete((output, message))
-
-        # select the data
-        self.form.treeView.selectAll()
-
-        Plotter2D.show = MagicMock() # for masking the display
-
-        self.form.quickData3DPlot()
-
-        self.assertTrue(Plotter2D.show.called)
-
-    def testShowEditMask(self):
-        """
-        Edit mask on a 2D plot.
-
-        TODO: add content once plotting finalized
-        """
-        pass
-
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/DensityCalculatorTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/DensityCalculatorTest.py	(revision 416fa8fe6ed121e335fb8f0e75cdd9a8ab89b80d)
+++ 	(revision )
@@ -1,121 +1,0 @@
-import sys
-import unittest
-import webbrowser
-
-from PyQt4 import QtGui
-from PyQt4.QtTest import QTest
-from PyQt4 import QtCore
-from mock import MagicMock
-
-####### TEMP
-import path_prepare
-#######
-
-# Local
-from DensityPanel import DensityPanel
-from DensityPanel import toMolarMass
-from sas.qtgui.GuiUtils import FormulaValidator
-
-import sas.qtgui.LocalConfig
-
-app = QtGui.QApplication(sys.argv)
-
-class ToMolarMassTest(unittest.TestCase):
-    """ Test the auxiliary conversion method"""
-    def testGoodEasy(self):
-        self.assertEqual(toMolarMass("H2"), "2.01588")
-
-    def testGoodComplex(self):
-        self.assertEqual(toMolarMass("H24O12C4C6N2Pu"), "608.304")
-
-    def testGoodComplex2(self):
-        self.assertEqual(toMolarMass("(H2O)0.5(D2O)0.5"), "19.0214")
-
-    def testBadInputInt(self):
-        self.assertEqual(toMolarMass(1), "")
-
-    def testBadInputStr(self):
-        self.assertEqual(toMolarMass("Im a bad string"), "")
-
-class DensityCalculatorTest(unittest.TestCase):
-    '''Test the DensityCalculator'''
-    def setUp(self):
-        '''Create the DensityCalculator'''
-        self.widget = DensityPanel(None)
-
-    def tearDown(self):
-        '''Destroy the DensityCalculator'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QtGui.QWidget)
-        self.assertEqual(self.widget.windowTitle(), "Density/Volume Calculator")
-        self.assertIsInstance(self.widget.ui.editMolecularFormula.validator(), FormulaValidator)
-        self.assertEqual(self.widget.ui.editMolecularFormula.styleSheet(), '')
-        self.assertEqual(self.widget.model.columnCount(), 1)
-        self.assertEqual(self.widget.model.rowCount(), 4)
-        self.assertEqual(self.widget.sizePolicy().Policy(), QtGui.QSizePolicy.Fixed)
-
-    def testSimpleEntry(self):
-        ''' Default compound calculations '''
-        self.widget.ui.editMolarVolume.insert("1.0")
-
-        self.widget.show()
-        # Send tab x3
-        key = QtCore.Qt.Key_Tab
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.qWait(100)
-
-        # Assure the mass density field is set
-        self.assertEqual(self.widget.ui.editMassDensity.text(), '18.0153')
-
-        # Change mass density
-        self.widget.ui.editMassDensity.insert("16.0")
-        # Send shift-tab to update the molar volume field
-        key =  QtCore.Qt.Key_Tab
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.ShiftModifier)
-        QTest.qWait(100)
-
-        # Assure the molar volume field got updated
-        self.assertEqual(self.widget.ui.editMolarVolume.text(), '1.12595625')
-
-    def testComplexEntryAndReset(self):
-        ''' User entered compound calculations and subsequent reset'''
-
-        self.widget.ui.editMolecularFormula.clear()
-        self.widget.ui.editMolecularFormula.insert("KMnO4")
-        self.widget.ui.editMolarVolume.insert("2.0")
-
-        self.widget.show()
-        # Send tab x3
-        key = QtCore.Qt.Key_Tab
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.qWait(100)
-
-        # Assure the mass density field is set
-        self.assertEqual(self.widget.ui.editMassDensity.text(), '79.017')
-
-        # Reset the widget
-        self.widget.modelReset()
-
-        self.assertEqual(self.widget.ui.editMolecularFormula.text(), "H2O")
-        self.assertEqual(self.widget.ui.editMolarMass.text(), "18.0153")
-        self.assertEqual(self.widget.ui.editMolarVolume.text(), "")
-        self.assertEqual(self.widget.ui.editMassDensity.text(), "")
-
-        #self.widget.exec_()
-
-    def testHelp(self):
-        """ Assure help file is shown """
-
-        # this should not rise
-        self.widget.displayHelp()
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/DroppableDataLoadWidgetTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/DroppableDataLoadWidgetTest.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,75 +1,0 @@
-import sys
-import unittest
-
-from PyQt4.QtGui import QApplication
-from PyQt4.QtTest import QTest
-from PyQt4 import QtCore
-
-# set up import paths
-import path_prepare
-
-from DroppableDataLoadWidget import DroppableDataLoadWidget
-from GuiUtils import *
-from UnitTesting.TestUtils import QtSignalSpy
-
-app = QApplication(sys.argv)
-
-class DroppableDataLoadWidgetTest(unittest.TestCase):
-    '''Test the DroppableDataLoadWidget GUI'''
-    def setUp(self):
-        '''Create the GUI'''
-        class dummy_manager(object):
-            def communicator(self):
-                return Communicate()
-            def perspective(self):
-                return MyPerspective()
-
-        self.form = DroppableDataLoadWidget(None, guimanager=dummy_manager())
-
-        # create dummy mime object
-        self.mime_data = QtCore.QMimeData()
-        self.testfile = 'testfile.txt'
-        self.mime_data.setUrls([QtCore.QUrl(self.testfile)])
-
-    def testDragIsOK(self):
-        """
-        Test the item being dragged over the load widget
-        """
-        good_drag_event = QtGui.QDragMoveEvent(QtCore.QPoint(0,0),
-                                               QtCore.Qt.CopyAction,
-                                               self.mime_data,
-                                               QtCore.Qt.LeftButton,
-                                               QtCore.Qt.NoModifier)
-        mime_data = QtCore.QMimeData()
-        bad_drag_event = QtGui.QDragMoveEvent(QtCore.QPoint(0,0),
-                                               QtCore.Qt.CopyAction,
-                                               mime_data,
-                                               QtCore.Qt.LeftButton,
-                                               QtCore.Qt.NoModifier)
-
-        # Call the drag handler with good event
-        self.assertTrue(self.form.dragIsOK(good_drag_event))
-
-        # Call the drag handler with bad event
-        self.assertFalse(self.form.dragIsOK(bad_drag_event))
-
-    def testDropEvent(self):
-        """
-        Test what happens if an object is dropped onto the load widget
-        """
-        spy_file_read = QtSignalSpy(self.form, self.form.communicator.fileReadSignal)
-
-        drop_event = QtGui.QDropEvent(QtCore.QPoint(0,0),
-                                           QtCore.Qt.CopyAction,
-                                           self.mime_data,
-                                           QtCore.Qt.LeftButton,
-                                           QtCore.Qt.NoModifier)
-
-        self.form.dropEvent(drop_event)
-        QtGui.qApp.processEvents()
-        self.assertEqual(spy_file_read.count(), 1)
-        self.assertIn(self.testfile, str(spy_file_read.signal(index=0)))
-
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/GuiManagerTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/GuiManagerTest.py	(revision 2155824bc3dcd6c0afe1204caa0357472cf9b060)
+++ 	(revision )
@@ -1,332 +1,0 @@
-import sys
-import subprocess
-import unittest
-import webbrowser
-import logging
-
-from PyQt4.QtGui import *
-from PyQt4.QtTest import QTest
-from PyQt4.QtCore import *
-from PyQt4.QtWebKit import *
-from mock import MagicMock
-
-# set up import paths
-import path_prepare
-
-# Local
-from sas.qtgui.DataExplorer import DataExplorerWindow
-from sas.qtgui.AboutBox import AboutBox
-from sas.qtgui.WelcomePanel import WelcomePanel
-from sas.qtgui.IPythonWidget import IPythonWidget
-
-from GuiManager import Acknowledgements, GuiManager
-from MainWindow import MainSasViewWindow
-from UnitTesting.TestUtils import QtSignalSpy
-
-app = QApplication(sys.argv)
-
-class GuiManagerTest(unittest.TestCase):
-    '''Test the Main Window functionality'''
-    def setUp(self):
-        '''Create the tested object'''
-        class MainWindow(MainSasViewWindow):
-            # Main window of the application
-            def __init__(self, reactor, parent=None):
-                super(MainWindow, self).__init__(parent)
-        
-                # define workspace for dialogs.
-                self.workspace = QWorkspace(self)
-                self.setCentralWidget(self.workspace)
-
-        self.manager = GuiManager(MainWindow(None))
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.manager = None
-
-    def testDefaults(self):
-        """
-        Test the object in its default state
-        """
-        self.assertIsInstance(self.manager.filesWidget, DataExplorerWindow)
-        self.assertIsInstance(self.manager.dockedFilesWidget, QDockWidget)
-        self.assertIsInstance(self.manager.dockedFilesWidget.widget(), DataExplorerWindow)
-        self.assertEqual(self.manager.dockedFilesWidget.features(), QDockWidget.NoDockWidgetFeatures)
-        self.assertEqual(self.manager._workspace.dockWidgetArea(self.manager.dockedFilesWidget), Qt.LeftDockWidgetArea)
-
-        self.assertIsInstance(self.manager.logDockWidget, QDockWidget)
-        self.assertIsInstance(self.manager.logDockWidget.widget(), QTextBrowser)
-        self.assertEqual(self.manager._workspace.dockWidgetArea(self.manager.logDockWidget), Qt.BottomDockWidgetArea)
-
-        self.assertIsInstance(self.manager.ackWidget, Acknowledgements)
-        self.assertIsInstance(self.manager.aboutWidget, AboutBox)
-        self.assertIsInstance(self.manager.welcomePanel, WelcomePanel)
-
-    def skip_testLogging(self):
-        """
-        Test logging of stdout, stderr and log messages
-        """
-        # See if the log window is empty
-        self.assertEqual(self.manager.logDockWidget.widget().toPlainText(), "")
-
-        # Now, send some message to stdout.
-        # We are in the MainWindow scope, so simple 'print' will work
-        message = "from stdout"
-        print message
-        self.assertIn(message, self.manager.logDockWidget.widget().toPlainText())
-
-        # Send some message to stderr
-        message = "from stderr"
-        sys.stderr.write(message)
-        self.assertIn(message, self.manager.logDockWidget.widget().toPlainText())
-
-        # And finally, send a log message
-        import logging
-        message = "from logging"
-        message_logged = "ERROR: " + message
-        logging.error(message)
-        self.assertIn(message_logged, self.manager.logDockWidget.widget().toPlainText())
-
-    def testConsole(self):
-        """
-        Test the docked QtConsole
-        """
-        # Invoke the console action
-        self.manager.actionPython_Shell_Editor()
-
-        # Test the widegt properties
-        self.assertIsInstance(self.manager.ipDockWidget, QDockWidget)
-        self.assertIsInstance(self.manager.ipDockWidget.widget(), IPythonWidget)
-        self.assertEqual(self.manager._workspace.dockWidgetArea(self.manager.ipDockWidget), Qt.RightDockWidgetArea)
-
-    def testUpdatePerspective(self):
-        """
-        """
-        pass
-
-    def testUpdateStatusBar(self):
-        """
-        """
-        pass
-
-    def testSetData(self):
-        """
-        """
-        pass
-
-    def testQuitApplication(self):
-        """
-        Test that the custom exit method is called on shutdown
-        """
-        self.manager._workspace.show()
-
-        # Must mask sys.exit, otherwise the whole testing process stops.
-        sys.exit = MagicMock()
-
-        # Say No to the close dialog
-        QMessageBox.question = MagicMock(return_value=QMessageBox.No)
-
-        # Open, then close the manager
-        self.manager.quitApplication()
-
-        # See that the MessageBox method got called
-        #self.assertTrue(QMessageBox.question.called)
-
-        # Say Yes to the close dialog
-        QMessageBox.question = MagicMock(return_value=QMessageBox.Yes)
-
-        # Open, then close the manager
-        self.manager.quitApplication()
-
-        # See that the MessageBox method got called
-        #self.assertTrue(QMessageBox.question.called)
-
-    def testCheckUpdate(self):
-        """
-        Tests the SasView website version polling
-        """
-        self.manager.processVersion = MagicMock()
-        version = {'update_url'  : 'http://www.sasview.org/sasview.latestversion', 
-                   'version'     : '4.1.0',
-                   'download_url': 'https://github.com/SasView/sasview/releases'}
-        self.manager.checkUpdate()
-
-        self.manager.processVersion.assert_called_with(version)
-
-        pass
-
-    def testProcessVersion(self):
-        """
-        Tests the version checker logic
-        """
-        # 1. version = 0.0.0
-        version_info = {u'version' : u'0.0.0'}
-        spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal)
-
-        self.manager.processVersion(version_info)
-
-        self.assertEqual(spy_status_update.count(), 1)
-        message = 'Could not connect to the application server. Please try again later.'
-        self.assertIn(message, str(spy_status_update.signal(index=0)))
-
-        # 2. version < LocalConfig.__version__
-        version_info = {u'version' : u'0.0.1'}
-        spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal)
-
-        self.manager.processVersion(version_info)
-
-        self.assertEqual(spy_status_update.count(), 1)
-        message = 'You have the latest version of SasView'
-        self.assertIn(message, str(spy_status_update.signal(index=0)))
-
-        # 3. version > LocalConfig.__version__
-        version_info = {u'version' : u'999.0.0'}
-        spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal)
-        webbrowser.open = MagicMock()
-
-        self.manager.processVersion(version_info)
-
-        self.assertEqual(spy_status_update.count(), 1)
-        message = 'Version 999.0.0 is available!'
-        self.assertIn(message, str(spy_status_update.signal(index=0)))
-
-        webbrowser.open.assert_called_with("https://github.com/SasView/sasview/releases")
-
-        # 4. couldn't load version
-        version_info = {}
-        logging.error = MagicMock()
-        spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal)
-
-        self.manager.processVersion(version_info)
-
-        # Retrieve and compare arguments of the mocked call
-        message = "guiframe: could not get latest application version number"
-        args, _ = logging.error.call_args
-        self.assertIn(message, args[0])
-
-        # Check the signal message
-        message = 'Could not connect to the application server.'
-        self.assertIn(message, str(spy_status_update.signal(index=0)))
-
-    def testActions(self):
-        """
-        """
-        pass
-
-    #### FILE ####
-    def testActionLoadData(self):
-        """
-        Menu File/Load Data File(s)
-        """
-        # Mock the system file open method
-        QFileDialog.getOpenFileNames = MagicMock(return_value=None)
-
-        # invoke the action
-        self.manager.actionLoadData()
-
-        # Test the getOpenFileName() dialog called once
-        self.assertTrue(QFileDialog.getOpenFileNames.called)
-
-    def testActionLoadDataFolder(self):
-        """
-        Menu File/Load Data Folder
-        """
-        # Mock the system file open method
-        QFileDialog.getExistingDirectory = MagicMock(return_value=None)
-
-        # invoke the action
-        self.manager.actionLoad_Data_Folder()
-
-        # Test the getOpenFileName() dialog called once
-        self.assertTrue(QFileDialog.getExistingDirectory.called)
-
-    #### VIEW ####
-    def testActionHideToolbar(self):
-        """
-        Menu View/Hide Toolbar
-        """
-        # Need to display the main window to initialize the toolbar.
-        self.manager._workspace.show()
-
-        # Check the initial state
-        self.assertTrue(self.manager._workspace.toolBar.isVisible())
-        self.assertEqual('Hide Toolbar', self.manager._workspace.actionHide_Toolbar.text())
-
-        # Invoke action
-        self.manager.actionHide_Toolbar()
-
-        # Assure changes propagated correctly
-        self.assertFalse(self.manager._workspace.toolBar.isVisible())
-        self.assertEqual('Show Toolbar', self.manager._workspace.actionHide_Toolbar.text())
-
-        # Revert
-        self.manager.actionHide_Toolbar()
-
-        # Assure the original values are back
-        self.assertTrue(self.manager._workspace.toolBar.isVisible())
-        self.assertEqual('Hide Toolbar', self.manager._workspace.actionHide_Toolbar.text())
-
-
-    #### HELP ####
-    def testActionDocumentation(self):
-        """
-        Menu Help/Documentation
-        """
-        #Mock the QWebView method
-        QWebView.show = MagicMock()
-
-        # Assure the filename is correct
-        self.assertIn("index.html", self.manager._helpLocation)
-
-        # Invoke the action
-        self.manager.actionDocumentation()
-
-        # Check if show() got called
-        self.assertTrue(QWebView.show.called)
-
-    def skip_testActionTutorial(self):
-        """
-        Menu Help/Tutorial
-        """
-        # Mock subprocess.Popen
-        subprocess.Popen = MagicMock()
-
-        tested_location = self.manager._tutorialLocation
-
-        # Assure the filename is correct
-        self.assertIn("Tutorial.pdf", tested_location)
-
-        # Invoke the action
-        self.manager.actionTutorial()
-
-        # Check if popen() got called
-        self.assertTrue(subprocess.Popen.called)
-
-        #Check the popen() call arguments
-        subprocess.Popen.assert_called_with([tested_location], shell=True)
-
-    def testActionAcknowledge(self):
-        """
-        Menu Help/Acknowledge
-        """
-        self.manager.actionAcknowledge()
-
-        # Check if the window is actually opened.
-        self.assertTrue(self.manager.ackWidget.isVisible())
-        self.assertIn("developers@sasview.org", self.manager.ackWidget.label.text())
-
-    def testActionCheck_for_update(self):
-        """
-        Menu Help/Check for update
-        """
-        # Just make sure checkUpdate is called.
-        self.manager.checkUpdate = MagicMock()
-
-        self.manager.actionCheck_for_update()
-
-        self.assertTrue(self.manager.checkUpdate.called)
-             
-       
-if __name__ == "__main__":
-    unittest.main()
-
Index: c/sas/qtgui/UnitTesting/GuiUtilsTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/GuiUtilsTest.py	(revision 965fbd854b36d33e3c78f5ffed0a6040af2ad43e)
+++ 	(revision )
@@ -1,443 +1,0 @@
-import sys
-import unittest
-import webbrowser
-
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-from mock import MagicMock
-
-# set up import paths
-import path_prepare
-
-# SV imports
-from sas.sascalc.dataloader.loader import Loader
-from sas.sasgui.guiframe.data_manager import DataManager
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.dataFitting import Data2D
-
-# Tested module
-from GuiUtils import *
-
-app = QtGui.QApplication(sys.argv)
-
-class GuiUtilsTest(unittest.TestCase):
-    '''Test the GUI Utilities methods'''
-    def setUp(self):
-        '''Empty'''
-        pass
-
-    def tearDown(self):
-        '''Empty'''
-        pass
-
-    def testDefaults(self):
-        """
-        Test all the global constants defined in the file.
-        """
-        # Should probably test the constants in the file,
-        # but this will done after trimming down GuiUtils
-        # and retaining only necessary variables.
-        pass
-
-    def testGetAppDir(self):
-        """
-        """
-        pass
-
-    def testGetUserDirectory(self):
-        """
-        Simple test of user directory getter
-        """
-        home_dir = os.path.expanduser("~")
-        self.assertIn(home_dir, get_user_directory())
-
-    def testCommunicate(self):
-        """
-        Test the container class with signal definitions
-        """
-        com = Communicate()
-
-        # All defined signals
-        list_of_signals = [
-            'fileReadSignal',
-            'fileDataReceivedSignal',
-            'statusBarUpdateSignal',
-            'updatePerspectiveWithDataSignal',
-            'updateModelFromPerspectiveSignal',
-            'plotRequestedSignal',
-            'progressBarUpdateSignal',
-            'activeGraphName',
-        ]
-
-        # Assure all signals are defined.
-        for signal in list_of_signals:
-            self.assertIn(signal, dir(com))
-
-    def testupdateModelItem(self):
-        """
-        Test the generic QModelItem update method
-        """
-        test_item = QtGui.QStandardItem()
-        test_list = ['aa', 4, True, ]
-        name = "Black Sabbath"
-
-        # update the item
-        updateModelItem(test_item, test_list, name)
-
-        # Make sure test_item got all data added
-        self.assertEqual(test_item.child(0).text(), name)
-        list_from_item = test_item.child(0).data().toList()
-        self.assertIsInstance(list_from_item, list)
-        self.assertEqual(list_from_item[0].toPyObject(), test_list[0])
-        self.assertEqual(list_from_item[1].toPyObject(), test_list[1])
-        self.assertEqual(list_from_item[2].toPyObject(), test_list[2])
-
-    def testupdateModelItemWithPlot(self):
-        """
-        Test the QModelItem checkbox update method
-        """
-        test_item = QtGui.QStandardItem()
-        test_list = ['aa','11']
-        update_data = QtCore.QVariant(test_list)
-        name = "Black Sabbath"
-
-        # update the item
-        updateModelItemWithPlot(test_item, update_data, name)
-        
-        # Make sure test_item got all data added
-        self.assertEqual(test_item.child(0).text(), name)
-        self.assertTrue(test_item.child(0).isCheckable())
-        list_from_item = test_item.child(0).child(0).data().toPyObject()
-        self.assertIsInstance(list_from_item, list)
-        self.assertEqual(str(list_from_item[0]), test_list[0])
-        self.assertEqual(str(list_from_item[1]), test_list[1])
-
-
-    def testPlotsFromCheckedItems(self):
-        """
-        Test addition of a plottable to the model
-        """
-
-        # Mockup data
-        test_list0 = "FRIDAY"
-        test_list1 = "SATURDAY"
-        test_list2 = "MONDAY"
-
-        # Main item ("file")
-        checkbox_model = QtGui.QStandardItemModel()
-        checkbox_item = QtGui.QStandardItem(True)
-        checkbox_item.setCheckable(True)
-        checkbox_item.setCheckState(QtCore.Qt.Checked)
-        test_item0 = QtGui.QStandardItem()
-        test_item0.setData(QtCore.QVariant(test_list0))
-
-        # Checked item 1
-        test_item1 = QtGui.QStandardItem(True)
-        test_item1.setCheckable(True)
-        test_item1.setCheckState(QtCore.Qt.Checked)
-        object_item = QtGui.QStandardItem()
-        object_item.setData(QtCore.QVariant(test_list1))
-        test_item1.setChild(0, object_item)
-
-        checkbox_item.setChild(0, test_item0)
-        checkbox_item.appendRow(test_item1)
-
-        # Unchecked item 2
-        test_item2 = QtGui.QStandardItem(True)
-        test_item2.setCheckable(True)
-        test_item2.setCheckState(QtCore.Qt.Unchecked)
-        object_item = QtGui.QStandardItem()
-        object_item.setData(QtCore.QVariant(test_list2))
-        test_item2.setChild(0, object_item)
-        checkbox_item.appendRow(test_item2)
-
-        checkbox_model.appendRow(checkbox_item)
-
-        # Pull out the "plottable" documents
-        plot_list = plotsFromCheckedItems(checkbox_model)
-
-        # Make sure only the checked data is present
-        # FRIDAY IN
-        self.assertIn(test_list0, plot_list[0])
-        # SATURDAY IN
-        self.assertIn(test_list1, plot_list[1])
-        # MONDAY NOT IN
-        self.assertNotIn(test_list2, plot_list[0])
-        self.assertNotIn(test_list2, plot_list[1])
-
-    def testInfoFromData(self):
-        """
-        Test Info element extraction from a plottable object
-        """
-        loader = Loader()
-        manager = DataManager()
-
-        # get Data1D
-        p_file="cyl_400_20.txt"
-        output_object = loader.load(p_file)
-        new_data = manager.create_gui_data(output_object, p_file)
-
-        # Extract Info elements into a model item
-        item = infoFromData(new_data)
-
-        # Test the item and its children
-        self.assertIsInstance(item, QtGui.QStandardItem)
-        self.assertEqual(item.rowCount(), 5)
-        self.assertEqual(item.text(), "Info")
-        self.assertIn(p_file,   item.child(0).text())
-        self.assertIn("Run",    item.child(1).text())
-        self.assertIn("Data1D", item.child(2).text())
-        self.assertIn(p_file,   item.child(3).text())
-        self.assertIn("Process",item.child(4).text())
-
-    def testOpenLink(self):
-        """
-        Opening a link in the external browser
-        """
-        good_url1 = r"http://test.test.com"
-        good_url2 = r"mailto:test@mail.com"
-        good_url3 = r"https://127.0.0.1"
-
-        bad_url1 = ""
-        bad_url2 = QtGui.QStandardItem()
-        bad_url3 = r"poop;//**I.am.a.!bad@url"
-
-        webbrowser.open = MagicMock()
-        openLink(good_url1)
-        openLink(good_url2)
-        openLink(good_url3)
-        self.assertEqual(webbrowser.open.call_count, 3)
-
-        with self.assertRaises(AttributeError):
-            openLink(bad_url1)
-        with self.assertRaises(AttributeError):
-            openLink(bad_url2)
-        with self.assertRaises(AttributeError):
-            openLink(bad_url3)
-
-    def testRetrieveData1d(self):
-        """
-        """
-        with self.assertRaises(AttributeError):
-            retrieveData1d("BOOP")
-
-        #data = Data1D()
-        #with self.assertRaises(ValueError):
-        #    retrieveData1d(data)
-
-        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0])
-
-        text = retrieveData1d(data)
-
-        self.assertIn("Temperature:", text)
-        self.assertIn("Beam_size:", text)
-        self.assertIn("X_min = 1.0:  X_max = 3.0", text)
-        self.assertIn("3.0 \t12.0 \t0.0 \t0.0", text)
-
-    def testRetrieveData2d(self):
-        """
-        """
-        with self.assertRaises(AttributeError):
-            retrieveData2d("BOOP")
-        data = Data2D(image=[1.0, 2.0, 3.0],
-                      err_image=[0.01, 0.02, 0.03],
-                      qx_data=[0.1, 0.2, 0.3],
-                      qy_data=[0.1, 0.2, 0.3])
-
-        text = retrieveData2d(data)
-
-        self.assertIn("Type:         Data2D", text)
-        self.assertIn("I_min = 1.0", text)
-        self.assertIn("I_max = 3.0", text)
-        self.assertIn("2 \t0.3 \t0.3 \t3.0 \t0.03 \t0.0 \t0.0", text)
-
-    def testOnTXTSave(self):
-        """
-        Test the file writer for saving 1d/2d data
-        """
-        path = "test123"
-        if os.path.isfile(path):
-            os.remove(path)
-
-        # Broken data
-        data = Data1D(x=[1.0, 2.0, 3.0], y=[])
-        # Expect a raise
-        with self.assertRaises(IndexError):
-            onTXTSave(data, path)
-
-        # Good data - no dX/dY
-        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0])
-        onTXTSave(data, path)
-
-        self.assertTrue(os.path.isfile(path))
-        with open(path,'r') as out:
-            data_read = out.read()
-            self.assertEqual("<X>   <Y>\n1  10\n2  11\n3  12\n", data_read)
-
-        if os.path.isfile(path):
-            os.remove(path)
-
-        # Good data - with dX/dY
-        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0],
-                      dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
-
-        onTXTSave(data, path)
-        with open(path,'r') as out:
-            data_read = out.read()
-            self.assertIn("<X>   <Y>   <dY>   <dX>\n", data_read)
-            self.assertIn("1  10  0.1  0.1\n", data_read)
-            self.assertIn("2  11  0.2  0.2\n", data_read)
-            self.assertIn("3  12  0.3  0.3\n", data_read)
-
-        if os.path.isfile(path):
-            os.remove(path)
-
-    def testSaveData1D(self):
-        """
-        Test the 1D file save method
-        """
-        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0],
-                      dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
-
-        # Test the .txt format
-        file_name = "test123_out.txt"
-        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
-        data.filename = "test123.txt"
-        saveData1D(data)
-        self.assertTrue(os.path.isfile(file_name))
-        os.remove(file_name)
-
-        # Test the .xml format
-        file_name = "test123_out.xml"
-        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
-        data.filename = "test123.xml"
-        saveData1D(data)
-        self.assertTrue(os.path.isfile(file_name))
-        os.remove(file_name)
-
-        # Test the wrong format
-        file_name = "test123_out.mp3"
-        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
-        data.filename = "test123.mp3"
-        saveData1D(data)
-        self.assertFalse(os.path.isfile(file_name))
-
-    def testSaveData2D(self):
-        """
-        Test the 1D file save method
-        """
-        data = Data2D(image=[1.0, 2.0, 3.0],
-                      err_image=[0.01, 0.02, 0.03],
-                      qx_data=[0.1, 0.2, 0.3],
-                      qy_data=[0.1, 0.2, 0.3])
-
-        # Test the .txt format
-        file_name = "test123_out.dat"
-        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
-        data.filename = "test123.dat"
-        saveData2D(data)
-        self.assertTrue(os.path.isfile(file_name))
-        os.remove(file_name)
-
-        # Test the wrong format
-        file_name = "test123_out.mp3"
-        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
-        data.filename = "test123.mp3"
-        saveData2D(data)
-        self.assertFalse(os.path.isfile(file_name))
-
-    def testXYTransform(self):
-        """ Assure the unit/legend transformation is correct"""
-        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0],
-                      dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="y")
-        self.assertEqual(xLabel, "()")
-        self.assertEqual(xscale, "linear")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x^(2)", yLabel="1/y")
-        self.assertEqual(xLabel, "^{2}(()^{2})")
-        self.assertEqual(yLabel, "1/(()^{-1})")
-        self.assertEqual(xscale, "linear")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x^(4)", yLabel="ln(y)")
-        self.assertEqual(xLabel, "^{4}(()^{4})")
-        self.assertEqual(yLabel, "\\ln{()}()")
-        self.assertEqual(xscale, "linear")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="ln(x)", yLabel="y^(2)")
-        self.assertEqual(xLabel, "\\ln{()}()")
-        self.assertEqual(yLabel, "^{2}(()^{2})")
-        self.assertEqual(xscale, "linear")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="log10(x)", yLabel="y*x^(2)")
-        self.assertEqual(xLabel, "()")
-        self.assertEqual(yLabel, " \\ \\ ^{2}(()^{2})")
-        self.assertEqual(xscale, "log")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="log10(x^(4))", yLabel="y*x^(4)")
-        self.assertEqual(xLabel, "^{4}(()^{4})")
-        self.assertEqual(yLabel, " \\ \\ ^{4}(()^{16})")
-        self.assertEqual(xscale, "log")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="1/sqrt(y)")
-        self.assertEqual(yLabel, "1/\\sqrt{}(()^{-0.5})")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="log10(y)")
-        self.assertEqual(yLabel, "()")
-        self.assertEqual(yscale, "log")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="ln(y*x)")
-        self.assertEqual(yLabel, "\\ln{( \\ \\ )}()")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="ln(y*x^(2))")
-        self.assertEqual(yLabel, "\\ln ( \\ \\ ^{2})(()^{2})")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="ln(y*x^(4))")
-        self.assertEqual(yLabel, "\\ln ( \\ \\ ^{4})(()^{4})")
-        self.assertEqual(yscale, "linear")
-
-        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="log10(y*x^(4))")
-        self.assertEqual(yLabel, " \\ \\ ^{4}(()^{4})")
-        self.assertEqual(yscale, "log")
-
-class FormulaValidatorTest(unittest.TestCase):
-    """ Test the formula validator """
-    def setUp(self):
-        '''Create the validator'''
-        self.validator = FormulaValidator()
-
-    def tearDown(self):
-        '''Destroy the validator'''
-        self.validator = None
-
-    def testValidateGood(self):
-        """Test a valid Formula """
-        formula_good = "H24O12C4C6N2Pu"
-        self.assertEqual(self.validator.validate(formula_good, 1)[0], QtGui.QValidator.Acceptable)
-
-        formula_good = "(H2O)0.5(D2O)0.5"
-        self.assertEqual(self.validator.validate(formula_good, 1)[0], QtGui.QValidator.Acceptable)
-
-    def testValidateBad(self):
-        """Test a valid Formula """
-        formula_bad = "H24 %%%O12C4C6N2Pu"
-        self.assertRaises(self.validator.validate(formula_bad, 1)[0])
-        self.assertEqual(self.validator.validate(formula_bad, 1)[0], QtGui.QValidator.Intermediate)
-
-        formula_bad = [1]
-        self.assertEqual(self.validator.validate(formula_bad, 1)[0], QtGui.QValidator.Intermediate)
-
-
-if __name__ == "__main__":
-    unittest.main()
-
Index: c/sas/qtgui/UnitTesting/InvariantTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/InvariantTest.py	(revision f721030e66e61dc6279aa8e024da03b25f8e0d42)
+++ 	(revision )
@@ -1,32 +1,0 @@
-import sys
-import unittest
-
-from PyQt4.QtGui import QApplication
-from PyQt4.QtTest import QTest
-from PyQt4.QtCore import Qt
-from new_invariant import InvariantWindow
-
-app = QApplication(sys.argv)
-
-class InvariantTest(unittest.TestCase):
-    '''Test the invariant GUI'''
-    def setUp(self):
-        '''Create the GUI'''
-        self.form = InvariantWindow()
-
-    def test_defaults(self):
-        '''Test the GUI in its default state'''
-        self.assertEqual(self.form.lineEdit_4.text(), "0.0")
-        self.assertEqual(self.form.lineEdit_6.text(), "1.0")
-        self.assertEqual(self.form.pushButton.text(), "Calculate")
-
-        # Class is in the default state even without pressing OK
-        self.assertEqual(self.form._background, 0.0)
-        self.assertEqual(self.form._scale, 1.0)
-        
-        # Push OK with the left mouse button
-        helpButton = self.form.pushButton_3
-        QTest.mouseClick(helpButton, Qt.LeftButton)
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/KiessigCalculatorTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/KiessigCalculatorTest.py	(revision 040529d59cec22934096b06caeb1e05dcbeb7f7f)
+++ 	(revision )
@@ -1,83 +1,0 @@
-import sys
-import unittest
-from PyQt4 import QtGui
-from PyQt4.QtTest import QTest
-from PyQt4.QtCore import Qt
-
-# TEMP
-import path_prepare
-
-
-from KiessigPanel import KiessigPanel
-
-app = QtGui.QApplication(sys.argv)
-
-
-class KiessigCalculatorTest(unittest.TestCase):
-    """Test the KiessigCalculator"""
-    def setUp(self):
-        """Create the KiessigCalculator"""
-        self.widget = KiessigPanel(None)
-
-    def tearDown(self):
-        """Destroy the KiessigCalculator"""
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        """Test the GUI in its default state"""
-        self.assertIsInstance(self.widget, QtGui.QWidget)
-        self.assertEqual(self.widget.windowTitle(), "Kiessig Thickness Calculator")
-        self.assertEqual(self.widget.sizePolicy().Policy(), QtGui.QSizePolicy.Fixed)
-
-    def testHelp(self):
-        """ Assure help file is shown """
-
-        # this should not rise
-        self.widget.onHelp()
-
-    def testComplexEntryNumbers(self):
-        """ User entered compound calculations and subsequent reset"""
-
-        self.widget.deltaq_in.clear()
-        self.widget.deltaq_in.insert('0.05')
-        #
-        # Push Compute with the left mouse button
-        computeButton = self.widget.computeButton
-        QTest.mouseClick(computeButton, Qt.LeftButton)
-        self.assertEqual(self.widget.lengthscale_out.text(), '125.664')
-
-    def testComplexEntryNumbers2(self):
-        """ User entered compound calculations and subsequent reset"""
-
-        self.widget.deltaq_in.clear()
-        self.widget.deltaq_in.insert('1.0')
-        #
-        # Push Compute with the left mouse button
-        computeButton = self.widget.computeButton
-        QTest.mouseClick(computeButton, Qt.LeftButton)
-        self.assertEqual(self.widget.lengthscale_out.text(), '6.283')
-
-    def testComplexEntryNumbers3(self):
-        """ User entered compound calculations and subsequent reset"""
-
-        self.widget.deltaq_in.clear()
-        self.widget.deltaq_in.insert('2.0')
-        #
-        # Push Compute with the left mouse button
-        computeButton = self.widget.computeButton
-        QTest.mouseClick(computeButton, Qt.LeftButton)
-        self.assertEqual(self.widget.lengthscale_out.text(), '3.142')
-
-    def testComplexEntryLetters(self):
-        """ User entered compound calculations and subsequent reset"""
-
-        self.widget.deltaq_in.insert("xyz")
-
-        # Push Compute with the left mouse button
-        computeButton = self.widget.computeButton
-        QTest.mouseClick(computeButton, Qt.LeftButton)
-        self.assertEqual(self.widget.lengthscale_out.text(), '')
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/LinearFitTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/LinearFitTest.py	(revision 2e3e95954828438b02ef55c47cd9553fe9a7a87a)
+++ 	(revision )
@@ -1,148 +1,0 @@
-import sys
-import unittest
-import numpy
-
-from PyQt4 import QtGui
-from mock import MagicMock
-
-# set up import paths
-import path_prepare
-
-from sas.sasgui.guiframe.dataFitting import Data1D
-import sas.qtgui.Plotter as Plotter
-
-# Local
-from LinearFit import LinearFit
-
-app = QtGui.QApplication(sys.argv)
-
-class LinearFitTest(unittest.TestCase):
-    '''Test the LinearFit'''
-    def setUp(self):
-        '''Create the LinearFit'''
-        self.data = Data1D(x=[1.0, 2.0, 3.0],
-                           y=[10.0, 11.0, 12.0],
-                           dx=[0.1, 0.2, 0.3],
-                           dy=[0.1, 0.2, 0.3])
-        plotter = Plotter.Plotter(None, quickplot=True)
-        self.widget = LinearFit(parent=plotter, data=self.data, xlabel="log10(x^2)", ylabel="log10(y)")
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QtGui.QDialog)
-        self.assertEqual(self.widget.windowTitle(), "Linear Fit")
-        self.assertEqual(self.widget.txtA.text(), "1")
-        self.assertEqual(self.widget.txtB.text(), "1")
-        self.assertEqual(self.widget.txtAerr.text(), "0")
-        self.assertEqual(self.widget.txtBerr.text(), "0")
-
-        self.assertEqual(self.widget.lblRange.text(), "Fit range of log10(x^2)")
-
-    def testFit(self):
-        '''Test the fitting wrapper '''
-        # Catch the update signal
-        self.widget.parent.emit = MagicMock()
-
-        # Set some initial values
-        self.widget.txtRangeMin.setText("1.0")
-        self.widget.txtRangeMax.setText("3.0")
-        self.widget.txtFitRangeMin.setText("1.0")
-        self.widget.txtFitRangeMax.setText("3.0")
-        # Run the fitting
-        self.widget.fit(None)
-        return_values = self.widget.parent.emit.call_args[0][1]
-        # Compare
-        self.assertItemsEqual(return_values[0], [1.0, 3.0])
-        self.assertAlmostEqual(return_values[1][0], 10.004054329, 6)
-        self.assertAlmostEqual(return_values[1][1], 12.030439848, 6)
-
-        # Set the log scale
-        self.widget.x_is_log = True
-        self.widget.fit(None)
-        return_values = self.widget.parent.emit.call_args[0][1]
-        # Compare
-        self.assertItemsEqual(return_values[0], [1.0, 3.0])
-        self.assertAlmostEqual(return_values[1][0], 9.987732937, 6)
-        self.assertAlmostEqual(return_values[1][1], 11.84365082, 6)
-
-    def testOrigData(self):
-        ''' Assure the un-logged data is returned'''
-        # log(x), log(y)
-        self.widget.xminFit, self.widget.xmaxFit = self.widget.range()
-        orig_x = [ 1.,  2.,  3.]
-        orig_y = [1.0, 1.0413926851582251, 1.0791812460476249]
-        orig_dy = [0.01, 0.018181818181818184, 0.024999999999999998]
-        x, y, dy = self.widget.origData()
-
-        self.assertItemsEqual(x, orig_x)
-        self.assertEqual(y[0], orig_y[0])
-        self.assertAlmostEqual(y[1], orig_y[1], 8)
-        self.assertAlmostEqual(y[2], orig_y[2], 8)
-        self.assertEqual(dy[0], orig_dy[0])
-        self.assertAlmostEqual(dy[1], orig_dy[1], 8)
-        self.assertAlmostEqual(dy[2], orig_dy[2], 8)
-
-        # x, y
-        self.widget.x_is_log = False
-        self.widget.y_is_log = False
-        self.widget.xminFit, self.widget.xmaxFit = self.widget.range()
-        orig_x = [ 1.,  2.,  3.]
-        orig_y = [10., 11., 12.]
-        orig_dy = [0.1, 0.2, 0.3]
-        x, y, dy = self.widget.origData()
-
-        self.assertItemsEqual(x, orig_x)
-        self.assertItemsEqual(y, orig_y)
-        self.assertItemsEqual(dy, orig_dy)
-
-        # x, log(y)
-        self.widget.x_is_log = False
-        self.widget.y_is_log = True
-        self.widget.xminFit, self.widget.xmaxFit = self.widget.range()
-        orig_x = [ 1.,  2.,  3.]
-        orig_y = [1.0, 1.0413926851582251, 1.0791812460476249]
-        orig_dy = [0.01, 0.018181818181818184, 0.024999999999999998]
-        x, y, dy = self.widget.origData()
-
-        self.assertItemsEqual(x, orig_x)
-        self.assertEqual(y[0], orig_y[0])
-        self.assertAlmostEqual(y[1], orig_y[1], 8)
-        self.assertAlmostEqual(y[2], orig_y[2], 8)
-        self.assertEqual(dy[0], orig_dy[0])
-        self.assertAlmostEqual(dy[1], orig_dy[1], 8)
-        self.assertAlmostEqual(dy[2], orig_dy[2], 8)
-
-    def testCheckFitValues(self):
-        '''Assure fit values are correct'''
-        # Good values
-        self.assertTrue(self.widget.checkFitValues(self.widget.txtFitRangeMin))
-        # Colors platform dependent
-        #self.assertEqual(self.widget.txtFitRangeMin.palette().color(10).name(), "#f0f0f0")
-        # Bad values
-        self.widget.x_is_log = True
-        self.widget.txtFitRangeMin.setText("-1.0")
-        self.assertFalse(self.widget.checkFitValues(self.widget.txtFitRangeMin))
-       
-
-    def testFloatInvTransform(self):
-        '''Test the helper method for providing conversion function'''
-        self.widget.xLabel="x"
-        self.assertEqual(self.widget.floatInvTransform(5.0), 5.0)
-        self.widget.xLabel="x^(2)"
-        self.assertEqual(self.widget.floatInvTransform(25.0), 5.0)
-        self.widget.xLabel="x^(4)"
-        self.assertEqual(self.widget.floatInvTransform(81.0), 3.0)
-        self.widget.xLabel="log10(x)"
-        self.assertEqual(self.widget.floatInvTransform(2.0), 100.0)
-        self.widget.xLabel="ln(x)"
-        self.assertEqual(self.widget.floatInvTransform(1.0), numpy.exp(1))
-        self.widget.xLabel="log10(x^(4))"
-        self.assertEqual(self.widget.floatInvTransform(4.0), 10.0)
-      
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/MainWindowTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/MainWindowTest.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,55 +1,0 @@
-import sys
-import unittest
-
-from PyQt4 import QtGui
-from PyQt4 import QtTest
-from PyQt4 import QtCore
-from mock import MagicMock
-
-# set up import paths
-import path_prepare
-
-# Local
-from MainWindow import MainSasViewWindow
-from MainWindow import SplashScreen
-
-app = QtGui.QApplication(sys.argv)
-
-class MainWindowTest(unittest.TestCase):
-    """Test the Main Window GUI"""
-    def setUp(self):
-        """Create the GUI"""
-
-        self.widget = MainSasViewWindow(None)
-
-    def tearDown(self):
-        """Destroy the GUI"""
-        self.widget = None
-
-    def testDefaults(self):
-        """Test the GUI in its default state"""
-        self.assertIsInstance(self.widget, QtGui.QMainWindow)
-        self.assertIsInstance(self.widget.centralWidget(), QtGui.QWorkspace)
-        
-    def testSplashScreen(self):
-        """ Test the splash screen """
-        splash = SplashScreen()
-        self.assertIsInstance(splash, QtGui.QSplashScreen)
-
-    def testExit(self):
-        """
-        Test that the custom exit method is called on shutdown
-        """
-        # Must mask sys.exit, otherwise the whole testing process stops.
-        sys.exit = MagicMock()
-        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.Yes)
-
-        # Open, then close the main window
-        tmp_main = MainSasViewWindow(None)
-        tmp_main.close()
-
-        # See that the MessageBox method got called
-        self.assertTrue(QtGui.QMessageBox.question.called)
-       
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/PlotHelperTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/PlotHelperTest.py	(revision 0268aed2269053d708f7e97fbea13db43e371ab4)
+++ 	(revision )
@@ -1,54 +1,0 @@
-import unittest
-
-# Tested module
-import PlotHelper
-
-class PlotHelperTest(unittest.TestCase):
-    '''Test the Plot helper functions'''
-    def setUp(self):
-        '''Empty'''
-        pass
-
-    def tearDown(self):
-        '''Empty'''
-        pass
-
-    def testDefaults(self):
-        """ default method variables values """
-        self.assertIsInstance(PlotHelper._plots, dict)
-        self.assertEqual(PlotHelper._plots, {})
-        self.assertEqual(PlotHelper._plot_id, 0)
-
-    def testFunctions(self):
-        """ Adding a plot """
-        plot = "I am a plot. Really."
-        PlotHelper.addPlot(plot)
-        plot_id = PlotHelper.idOfPlot(plot)
-
-        # We can't guarantee unique values for plot_id, as
-        # the tests are executed in random order, so just
-        # make sure we get consecutive values for 2 plots
-        plot2 = "I am also a plot."
-        PlotHelper.addPlot(plot2)
-        plot_id_2 = PlotHelper.idOfPlot(plot2)
-        id1 = int(plot_id[-1])
-        id2 = int(plot_id_2[-1])
-        self.assertEqual(id2 - id1, 1)
-
-        # Other properties
-        #self.assertEqual(PlotHelper.currentPlots(), [plot_id, plot_id_2])
-        self.assertTrue(set(PlotHelper.currentPlots()).issubset([plot_id, plot_id_2]))
-        self.assertEqual(PlotHelper.plotById(plot_id), plot)
-        self.assertEqual(PlotHelper.plotById(plot_id_2), plot2)
-
-        # Delete a graph
-        PlotHelper.deletePlot(plot_id)
-        self.assertEqual(PlotHelper.currentPlots(), [plot_id_2])
-
-        # Add another graph to see the counter
-        plot3 = "Just another plot. Move along."
-        PlotHelper.addPlot(plot3)
-        #self.assertEqual(PlotHelper.idOfPlot(plot3), plot_id_2 + 1)
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/PlotPropertiesTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/PlotPropertiesTest.py	(revision 0f3c22d6d78f70dfa622751e9a7254328e99bf1c)
+++ 	(revision )
@@ -1,102 +1,0 @@
-import sys
-import unittest
-from mock import MagicMock
-
-from PyQt4 import QtGui
-
-# set up import paths
-import path_prepare
-
-# Local
-from PlotProperties import PlotProperties
-
-app = QtGui.QApplication(sys.argv)
-
-class PlotPropertiesTest(unittest.TestCase):
-    '''Test the PlotProperties'''
-    def setUp(self):
-        '''Create the PlotProperties'''
-
-        self.widget = PlotProperties(None,
-                         color=1,
-                         marker=3,
-                         marker_size=10,
-                         legend="LL")
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QtGui.QDialog)
-        self.assertEqual(self.widget.windowTitle(), "Modify Plot Properties")
-
-        # Check the combo boxes
-        self.assertEqual(self.widget.cbColor.currentText(), "Green")
-        self.assertEqual(self.widget.cbColor.count(), 7)
-        self.assertEqual(self.widget.cbShape.currentText(), "Triangle Down")
-        self.assertEqual(self.widget.txtLegend.text(), "LL")
-        self.assertEqual(self.widget.sbSize.value(), 10)
-
-    def testDefaultsWithCustomColor(self):
-        '''Test the GUI when called with custom color'''
-        widget = PlotProperties(None,
-                         color="#FF00FF",
-                         marker=7,
-                         marker_size=10,
-                         legend="LL")
-
-        self.assertEqual(widget.cbColor.currentText(), "Custom")
-        self.assertEqual(widget.cbColor.count(), 8)
-        
-    def testOnColorChange(self):
-        '''Test the response to color change event'''
-        # Accept the new color
-        QtGui.QColorDialog.getColor = MagicMock(return_value=QtGui.QColor(255, 0, 255))
-
-        self.widget.onColorChange()
-
-        self.assertEqual(self.widget.color(), "#ff00ff")
-        self.assertTrue(self.widget.custom_color)
-        self.assertEqual(self.widget.cbColor.currentIndex(), 7)
-        self.assertEqual(self.widget.cbColor.currentText(), "Custom")
-
-        # Reset the color - this will remove "Custom" from the combobox
-        # and set its index to "Green"
-        self.widget.cbColor.setCurrentIndex(1)
-        self.assertEqual(self.widget.cbColor.currentText(), "Green")
-
-        # Cancel the dialog now
-        bad_color = QtGui.QColor() # constructs an invalid color
-        QtGui.QColorDialog.getColor = MagicMock(return_value=bad_color)
-        self.widget.onColorChange()
-
-        self.assertEqual(self.widget.color(), 1)
-        self.assertFalse(self.widget.custom_color)
-        self.assertEqual(self.widget.cbColor.currentIndex(), 1)
-        self.assertEqual(self.widget.cbColor.currentText(), "Green")
-
-
-    def testOnColorIndexChange(self):
-        '''Test the response to color index change event'''
-        # Intitial population of the color combo box
-        self.widget.onColorIndexChange()
-        self.assertEqual(self.widget.cbColor.count(), 7)
-        # Block the callback so we can update the cb
-        self.widget.cbColor.blockSignals(True)
-        # Add the Custom entry
-        self.widget.cbColor.addItems(["Custom"])
-        # Unblock the callback
-        self.widget.cbColor.blockSignals(False)
-        # Assert the new CB
-        self.assertEqual(self.widget.cbColor.count(), 8)
-        # Call the method
-        self.widget.onColorIndexChange()
-        # see that the Custom entry disappeared
-        self.assertEqual(self.widget.cbColor.count(), 7)
-        self.assertEqual(self.widget.cbColor.findText("Custom"), -1)
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/PlotUtilitiesTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/PlotUtilitiesTest.py	(revision db5cd8da62c5627b9811d209d913219ab45e3c75)
+++ 	(revision )
@@ -1,46 +1,0 @@
-import sys
-import unittest
-from collections import OrderedDict
-
-from UnitTesting.TestUtils import WarningTestNotImplemented
-
-# Tested module
-import PlotUtilities
-
-class PlotUtilitiesTest(unittest.TestCase):
-    '''Test the Plot Utilities functions'''
-    def setUp(self):
-        '''Empty'''
-        pass
-
-    def tearDown(self):
-        '''Empty'''
-        pass
-
-    def testDefaults(self):
-        """ default method variables values """
-        self.assertIsInstance(PlotUtilities.SHAPES, OrderedDict)
-        self.assertIsInstance(PlotUtilities.COLORS, OrderedDict)
-
-    def testBuildMatrix(self):
-        """ build matrix for 2d plot from a vector """
-        WarningTestNotImplemented()
-
-    def testGetBins(self):
-        """ test 1d arrays of the index with square binning """
-        WarningTestNotImplemented()
-
-    def testFillupPixels(self):
-        """ test filling z values of the empty cells of 2d image matrix """
-        WarningTestNotImplemented()
-
-    def testRescale(sef):
-        """ test the helper function for step based zooming """
-        WarningTestNotImplemented()
-
-    def testGgetValidColor(self):
-        """ test that the method returns a color understood by MPL """
-        WarningTestNotImplemented()
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/Plotter2DTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/Plotter2DTest.py	(revision 965fbd854b36d33e3c78f5ffed0a6040af2ad43e)
+++ 	(revision )
@@ -1,238 +1,0 @@
-import sys
-import unittest
-import numpy
-
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
-from mock import MagicMock
-from mpl_toolkits.mplot3d import Axes3D
-
-####### TEMP
-import path_prepare
-#######
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.dataFitting import Data2D
-from UnitTesting.TestUtils import WarningTestNotImplemented
-
-# Tested module
-import sas.qtgui.Plotter2D as Plotter2D
-
-app = QtGui.QApplication(sys.argv)
-
-class Plotter2DTest(unittest.TestCase):
-    '''Test the Plotter 2D class'''
-    def setUp(self):
-        '''create'''
-        class dummy_manager(object):
-            def communicator(self):
-                return Communicate()
-            def perspective(self):
-                return MyPerspective()
-            def workspace(self):
-                return None
-
-        self.plotter = Plotter2D.Plotter2D(parent=dummy_manager(), quickplot=True)
-
-        self.data = Data2D(image=[0.1]*4,
-                           qx_data=[1.0, 2.0, 3.0, 4.0],
-                           qy_data=[10.0, 11.0, 12.0, 13.0],
-                           dqx_data=[0.1, 0.2, 0.3, 0.4],
-                           dqy_data=[0.1, 0.2, 0.3, 0.4],
-                           q_data=[1,2,3,4],
-                           xmin=-1.0, xmax=5.0,
-                           ymin=-1.0, ymax=15.0,
-                           zmin=-1.0, zmax=20.0)
-
-        self.data.title="Test data"
-        self.data.id = 1
-
-    def tearDown(self):
-        '''destroy'''
-        self.plotter = None
-
-    def testDataProperty(self):
-        """ Adding data """
-        self.plotter.data = self.data
-
-        self.assertEqual(self.plotter.data, self.data)
-        self.assertEqual(self.plotter._title, self.data.title)
-        self.assertEqual(self.plotter.xLabel, "$\\rm{Q_{x}}(A^{-1})$")
-        self.assertEqual(self.plotter.yLabel, "$\\rm{Q_{y}}(A^{-1})$")
-
-    def testPlot(self):
-        """ Look at the plotting """
-        self.plotter.data = self.data
-        self.plotter.show()
-        FigureCanvas.draw_idle = MagicMock()
-
-        self.plotter.plot()
-
-        self.assertTrue(FigureCanvas.draw_idle.called)
-
-    def testCalculateDepth(self):
-        ''' Test the depth calculator '''
-        self.plotter.data = self.data
-
-        # Default, log scale
-        depth = self.plotter.calculateDepth()
-        self.assertEqual(depth, (0.1, 1.e20))
-
-        # Change the scale to linear
-        self.plotter.scale = 'linear'
-        depth = self.plotter.calculateDepth()
-        self.assertEqual(depth[0], -32.)
-        self.assertAlmostEqual(depth[1], 1.30103, 5)
-
-    def testOnColorMap(self):
-        ''' Respond to the color map event '''
-        self.plotter.data = self.data
-        self.plotter.plot()
-        self.plotter.show()
-
-        QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
-
-        # Just this one plot
-        self.plotter.onColorMap()
-
-        # Check that exec_ got called
-        self.assertTrue(QtGui.QDialog.exec_.called)
-
-        self.assertEqual(self.plotter.cmap, "jet")
-        self.assertAlmostEqual(self.plotter.vmin, 0.1, 6)
-        self.assertAlmostEqual(self.plotter.vmax, 1e+20, 6)
-
-    def testOnToggleScale(self):
-        """ Respond to the event by replotting """
-        self.plotter.data = self.data
-        self.plotter.show()
-        FigureCanvas.draw_idle = MagicMock()
-
-        self.plotter.onToggleScale(None)
-
-        self.assertTrue(FigureCanvas.draw_idle.called)
-
-    def testOnBoxSum(self):
-        """ Test the box sum display and functionality """
-
-        # hacky way to make things work in manipulations._sum
-        self.data.detector = [1]
-        self.data.err_data = numpy.array([0.0, 0.0, 0.1, 0.0])
-        self.plotter.data = self.data
-        self.plotter.show()
-
-        # Mock the main window
-        self.plotter.manager.parent = MagicMock()
-
-        # Call the main tested method
-        self.plotter.onBoxSum()
-
-        # Test various properties
-        self.assertIsInstance(self.plotter.slicer.model(), QtGui.QStandardItemModel)
-        self.assertTrue(self.plotter.boxwidget.isVisible())
-        self.assertIsInstance(self.plotter.boxwidget.model, QtGui.QStandardItemModel)
-
-    def testContextMenuQuickPlot(self):
-        """ Test the right click menu """
-        self.plotter.data = self.data
-        self.plotter.createContextMenuQuick()
-        actions = self.plotter.contextMenu.actions()
-        self.assertEqual(len(actions), 7)
-
-        # Trigger Save Image and make sure the method is called
-        self.assertEqual(actions[0].text(), "Save Image")
-        self.plotter.toolbar.save_figure = MagicMock()
-        actions[0].trigger()
-        self.assertTrue(self.plotter.toolbar.save_figure.called)
-
-        # Trigger Print Image and make sure the method is called
-        self.assertEqual(actions[1].text(), "Print Image")
-        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
-        actions[1].trigger()
-        self.assertTrue(QtGui.QPrintDialog.exec_.called)
-
-        # Trigger Copy to Clipboard and make sure the method is called
-        self.assertEqual(actions[2].text(), "Copy to Clipboard")
-
-        # Spy on cliboard's dataChanged() signal
-        self.clipboard_called = False
-        def done():
-            self.clipboard_called = True
-        QtCore.QObject.connect(app.clipboard(), QtCore.SIGNAL("dataChanged()"), done)
-        actions[2].trigger()
-        QtGui.qApp.processEvents()
-        # Make sure clipboard got updated.
-        #self.assertTrue(self.clipboard_called)
-
-        # Trigger Toggle Grid and make sure the method is called
-        self.assertEqual(actions[4].text(), "Toggle Grid On/Off")
-        self.plotter.ax.grid = MagicMock()
-        actions[4].trigger()
-        self.assertTrue(self.plotter.ax.grid.called)
-
-        # Trigger Change Scale and make sure the method is called
-        self.assertEqual(actions[6].text(), "Toggle Linear/Log Scale")
-        FigureCanvas.draw_idle = MagicMock()
-        actions[6].trigger()
-        self.assertTrue(FigureCanvas.draw_idle.called)
-
-    def testShowNoPlot(self):
-        """ Test the plot rendering and generation """
-
-        FigureCanvas.draw_idle = MagicMock()
-        FigureCanvas.draw = MagicMock()
-
-        # Test early return on no data
-        self.plotter.showPlot(data=None,
-                              qx_data=self.data.qx_data,
-                              qy_data=self.data.qy_data,
-                              xmin=self.data.xmin,
-                              xmax=self.data.xmax,
-                              ymin=self.data.ymin, ymax=self.data.ymax,
-                              cmap=None, zmin=None,
-                              zmax=None)
-
-        self.assertFalse(FigureCanvas.draw_idle.called)
-        self.assertFalse(FigureCanvas.draw.called)
-
-    def testShow3DPlot(self):
-        """ Test the 3Dplot rendering and generation """
-        # Test 3D printout
-        FigureCanvas.draw = MagicMock()
-        Axes3D.plot_surface = MagicMock()
-        self.plotter.figure.colorbar = MagicMock()
-
-        self.plotter.dimension = 3
-        self.plotter.data = self.data
-        self.plotter.showPlot(data=self.plotter.data.data,
-                              qx_data=self.data.qx_data,
-                              qy_data=self.data.qy_data,
-                              xmin=self.data.xmin,
-                              xmax=self.data.xmax,
-                              ymin=self.data.ymin, ymax=self.data.ymax,
-                              cmap=None, zmin=None,
-                              zmax=None)
-        self.assertTrue(Axes3D.plot_surface.called)
-        self.assertTrue(FigureCanvas.draw.called)
-
-    def testShow2DPlot(self):
-        """ Test the 2Dplot rendering and generation """
-        # Test 2D printout
-        FigureCanvas.draw_idle = MagicMock()
-        self.plotter.figure.colorbar = MagicMock()
-
-        self.plotter.dimension = 2
-        self.plotter.data = self.data
-        self.plotter.showPlot(data=self.plotter.data.data,
-                              qx_data=self.data.qx_data,
-                              qy_data=self.data.qy_data,
-                              xmin=self.data.xmin,
-                              xmax=self.data.xmax,
-                              ymin=self.data.ymin, ymax=self.data.ymax,
-                              cmap=None, zmin=None,
-                              zmax=None)
-        self.assertTrue(FigureCanvas.draw_idle.called)
-
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/PlotterBaseTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/PlotterBaseTest.py	(revision aadf0af183702570addb989ed535f1c04f06b3df)
+++ 	(revision )
@@ -1,194 +1,0 @@
-import sys
-import unittest
-from mock import patch, MagicMock
-
-from PyQt4 import QtGui
-import matplotlib.pyplot as plt
-from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
-from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
-
-####### TEMP
-import path_prepare
-#######
-
-from sas.qtgui.ScaleProperties import ScaleProperties
-from sas.qtgui.WindowTitle import WindowTitle
-#import sas.qtgui.GuiUtils as GuiUtils
-from sas.qtgui.GuiUtils import *
-import sas.qtgui.PlotHelper as PlotHelper
-
-# Tested module
-import sas.qtgui.PlotterBase as PlotterBase
-
-app = QtGui.QApplication(sys.argv)
-
-class PlotterBaseTest(unittest.TestCase):
-    '''Test the Plotter base class'''
-    def setUp(self):
-        '''create'''
-        class dummy_manager(object):
-            def communicator(self):
-                return Communicate()
-            def perspective(self):
-                return MyPerspective()
-
-        #PlotterBase.PlotterBase.contextMenuQuickPlot = MagicMock()
-        self.plotter = PlotterBase.PlotterBase(None, manager=dummy_manager(), quickplot=True)
-
-    def tearDown(self):
-        '''destroy'''
-        self.plotter = None
-        self.plotter_qp = None
-
-    def testDefaults(self):
-        """ default method variables values """
-        self.assertIsInstance(self.plotter, QtGui.QWidget)
-        self.assertIsInstance(self.plotter.canvas, FigureCanvas)
-        self.assertIsInstance(self.plotter.toolbar, NavigationToolbar)
-        self.assertIsInstance(self.plotter.properties, ScaleProperties)
-
-        self.assertEqual(self.plotter._data, [])
-        self.assertEqual(self.plotter._xscale, 'log')
-        self.assertEqual(self.plotter._yscale, 'log')
-        self.assertEqual(self.plotter.scale, 'linear')
-        self.assertFalse(self.plotter.grid_on)
-        self.assertEqual(self.plotter.x_label, 'log10(x)')
-        self.assertEqual(self.plotter.y_label, 'log10(y)')
-
-    def testData(self):
-        ''' Test the pure virtual method '''
-        with self.assertRaises(NotImplementedError):
-            self.plotter.data=[]
-
-    def testContextMenu(self):
-        ''' Test the default context menu '''
-        with self.assertRaises(NotImplementedError):
-            self.plotter.createContextMenu()
-
-    def testClean(self):
-        ''' test the graph cleanup '''
-        self.plotter.figure.delaxes = MagicMock()
-        self.plotter.clean()
-        self.assertTrue(self.plotter.figure.delaxes.called)
-
-    def testPlot(self):
-        ''' test the pure virtual method '''
-        with self.assertRaises(NotImplementedError):
-            self.plotter.plot()
-
-    def notestOnCloseEvent(self):
-        ''' test the plotter close behaviour '''
-        PlotHelper.deletePlot = MagicMock()
-        self.plotter.closeEvent(None)
-        self.assertTrue(PlotHelper.deletePlot.called)
-
-    def testOnImageSave(self):
-        ''' test the workspace save '''
-        self.plotter.toolbar.save_figure = MagicMock()
-        self.plotter.onImageSave()
-        self.assertTrue(self.plotter.toolbar.save_figure.called)
-
-    def testOnImagePrint(self):
-        ''' test the workspace print '''
-        QtGui.QPainter.end = MagicMock()
-        QtGui.QLabel.render = MagicMock()
-
-        # First, let's cancel printing
-        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
-        self.plotter.onImagePrint()
-        self.assertFalse(QtGui.QPainter.end.called)
-        self.assertFalse(QtGui.QLabel.render.called)
-
-        # Let's print now
-        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
-        self.plotter.onImagePrint()
-        self.assertTrue(QtGui.QPainter.end.called)
-        self.assertTrue(QtGui.QLabel.render.called)
-
-    def testOnClipboardCopy(self):
-        ''' test the workspace screen copy '''
-        QtGui.QClipboard.setPixmap = MagicMock()
-        self.plotter.onClipboardCopy()
-        self.assertTrue(QtGui.QClipboard.setPixmap.called)
-
-    def testOnGridToggle(self):
-        ''' test toggling the grid lines '''
-        # Check the toggle
-        orig_toggle = self.plotter.grid_on
-        
-        FigureCanvas.draw_idle = MagicMock()
-        self.plotter.onGridToggle()
-
-        self.assertTrue(FigureCanvas.draw_idle.called)
-        self.assertTrue(self.plotter.grid_on != orig_toggle)
-
-    def testDefaultContextMenu(self):
-        """ Test the right click default menu """
-
-        self.plotter.defaultContextMenu()
-
-        actions = self.plotter.contextMenu.actions()
-        self.assertEqual(len(actions), 4)
-
-        # Trigger Save Image and make sure the method is called
-        self.assertEqual(actions[0].text(), "Save Image")
-        self.plotter.toolbar.save_figure = MagicMock()
-        actions[0].trigger()
-        self.assertTrue(self.plotter.toolbar.save_figure.called)
-
-        # Trigger Print Image and make sure the method is called
-        self.assertEqual(actions[1].text(), "Print Image")
-        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
-        actions[1].trigger()
-        self.assertTrue(QtGui.QPrintDialog.exec_.called)
-
-        # Trigger Copy to Clipboard and make sure the method is called
-        self.assertEqual(actions[2].text(), "Copy to Clipboard")
-
-        # Spy on cliboard's dataChanged() signal
-        self.clipboard_called = False
-        def done():
-            self.clipboard_called = True
-        QtCore.QObject.connect(app.clipboard(), QtCore.SIGNAL("dataChanged()"), done)
-        actions[2].trigger()
-        QtGui.qApp.processEvents()
-        # Make sure clipboard got updated.
-        self.assertTrue(self.clipboard_called)
-
-    def testOnWindowsTitle(self):
-        """ Test changing the plot title"""
-        # Mock the modal dialog's response
-        QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
-        self.plotter.show()
-        # Assure the original title is none
-        self.assertEqual(self.plotter.windowTitle(), "")
-        self.plotter.manager.communicator = MagicMock()
-
-        WindowTitle.title = MagicMock(return_value="I am a new title")
-        # Change the title
-        self.plotter.onWindowsTitle()
-
-        self.assertEqual(self.plotter.windowTitle(), "I am a new title")
-
-    def testOnMplMouseDown(self):
-        """ Test what happens on mouse click down in chart """
-        pass
-
-    def testOnMplMouseUp(self):
-        """ Test what happens on mouse release in chart """
-        pass
-
-    def testOnMplMouseMotion(self):
-        """ Test what happens on mouse move in chart """
-        pass
-
-    def testOnMplPick(self):
-        """ Test what happens on mouse pick in chart """
-        pass
-
-    def testOnMplWheel(self):
-        """ Test what happens on mouse pick in chart """
-        pass
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/PlotterTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/PlotterTest.py	(revision 0268aed2269053d708f7e97fbea13db43e371ab4)
+++ 	(revision )
@@ -1,414 +1,0 @@
-import sys
-import unittest
-
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
-from mock import MagicMock
-from mock import patch
-
-####### TEMP
-import path_prepare
-#######
-from sas.sasgui.guiframe.dataFitting import Data1D
-from sas.sasgui.guiframe.dataFitting import Data2D
-from UnitTesting.TestUtils import WarningTestNotImplemented
-from sas.qtgui.LinearFit import LinearFit
-from sas.qtgui.PlotProperties import PlotProperties
-
-# Tested module
-import sas.qtgui.Plotter as Plotter
-
-app = QtGui.QApplication(sys.argv)
-
-
-class PlotterTest(unittest.TestCase):
-    '''Test the Plotter 1D class'''
-    def setUp(self):
-        '''create'''
-
-        self.plotter = Plotter.Plotter(None, quickplot=True)
-        self.data = Data1D(x=[1.0, 2.0, 3.0],
-                           y=[10.0, 11.0, 12.0],
-                           dx=[0.1, 0.2, 0.3],
-                           dy=[0.1, 0.2, 0.3])
-        self.data.title="Test data"
-        self.data.name="Test name"
-        self.data.id = 1
-
-    def tearDown(self):
-        '''destroy'''
-        self.plotter = None
-
-    def testDataProperty(self):
-        """ Adding data """
-        self.plotter.data = self.data
-
-        self.assertEqual(self.plotter.data, self.data)
-        self.assertEqual(self.plotter._title, self.data.name)
-        self.assertEqual(self.plotter.xLabel, "$()$")
-        self.assertEqual(self.plotter.yLabel, "$()$")
-
-    def testPlotWithErrors(self):
-        """ Look at the plotting with error bars"""
-        self.plotter.data = self.data
-        self.plotter.show()
-        FigureCanvas.draw = MagicMock()
-
-        self.plotter.plot(hide_error=False)
-
-        self.assertEqual(self.plotter.ax.get_xscale(), 'log')
-        self.assertTrue(FigureCanvas.draw.called)
-
-    def testPlotWithoutErrors(self):
-        """ Look at the plotting without error bars"""
-        self.plotter.data = self.data
-        self.plotter.show()
-        FigureCanvas.draw = MagicMock()
-
-        self.plotter.plot(hide_error=True)
-
-        self.assertEqual(self.plotter.ax.get_yscale(), 'log')
-        self.assertTrue(FigureCanvas.draw.called)
-
-    def testCreateContextMenuQuick(self):
-        """ Test the right click menu """
-        self.plotter.createContextMenuQuick()
-        actions = self.plotter.contextMenu.actions()
-        self.assertEqual(len(actions), 7)
-
-        # Trigger Save Image and make sure the method is called
-        self.assertEqual(actions[0].text(), "Save Image")
-        self.plotter.toolbar.save_figure = MagicMock()
-        actions[0].trigger()
-        self.assertTrue(self.plotter.toolbar.save_figure.called)
-
-        # Trigger Print Image and make sure the method is called
-        self.assertEqual(actions[1].text(), "Print Image")
-        QtGui.QPrintDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
-        actions[1].trigger()
-        self.assertTrue(QtGui.QPrintDialog.exec_.called)
-
-        # Trigger Copy to Clipboard and make sure the method is called
-        self.assertEqual(actions[2].text(), "Copy to Clipboard")
-
-        # Spy on cliboard's dataChanged() signal
-        self.clipboard_called = False
-        def done():
-            self.clipboard_called = True
-        QtCore.QObject.connect(app.clipboard(), QtCore.SIGNAL("dataChanged()"), done)
-        actions[2].trigger()
-        QtGui.qApp.processEvents()
-        # Make sure clipboard got updated.
-        #self.assertTrue(self.clipboard_called)
-
-        # Trigger Toggle Grid and make sure the method is called
-        self.assertEqual(actions[4].text(), "Toggle Grid On/Off")
-        self.plotter.ax.grid = MagicMock()
-        actions[4].trigger()
-        self.assertTrue(self.plotter.ax.grid.called)
-
-        # Trigger Change Scale and make sure the method is called
-        self.assertEqual(actions[6].text(), "Change Scale")
-        self.plotter.properties.exec_ = MagicMock(return_value=QtGui.QDialog.Rejected)
-        actions[6].trigger()
-        self.assertTrue(self.plotter.properties.exec_.called)
-
-    def testXyTransform(self):
-        """ Tests the XY transformation and new chart update """
-        self.plotter.plot(self.data)
-
-        # Transform the points
-        self.plotter.xyTransform(xLabel="x", yLabel="log10(y)")
-
-        # Assure new plot has correct labels
-        self.assertEqual(self.plotter.ax.get_xlabel(), "$()$")
-        self.assertEqual(self.plotter.ax.get_ylabel(), "$()$")
-        # ... and scale
-        self.assertEqual(self.plotter.xscale, "linear")
-        self.assertEqual(self.plotter.yscale, "log")
-        # See that just one plot is present
-        self.assertEqual(len(self.plotter.plot_dict), 1)
-        self.assertEqual(len(self.plotter.ax.collections), 1)
-
-    def testAddText(self):
-        """ Checks the functionality of adding text to graph """
-
-        self.plotter.plot(self.data)
-        self.plotter.x_click = 100.0
-        self.plotter.y_click = 100.0
-        # modify the text edit control
-        test_text = "Smoke in cabin"
-        test_font = QtGui.QFont("Arial", 16, QtGui.QFont.Bold)
-        test_color = "#00FF00"
-        self.plotter.addText.textEdit.setText(test_text)
-
-        # Return the requested font parameters
-        self.plotter.addText.font = MagicMock(return_value = test_font)
-        self.plotter.addText.color = MagicMock(return_value = test_color)
-        # Return OK from the dialog
-        self.plotter.addText.exec_ = MagicMock(return_value = QtGui.QDialog.Accepted)
-        # Add text to graph
-        self.plotter.onAddText()
-        self.plotter.show()
-        # Check if the text was added properly
-        self.assertEqual(len(self.plotter.textList), 1)
-        self.assertEqual(self.plotter.textList[0].get_text(), test_text)
-        self.assertEqual(self.plotter.textList[0].get_color(), test_color)
-        self.assertEqual(self.plotter.textList[0].get_fontproperties().get_family()[0], 'Arial')
-        self.assertEqual(self.plotter.textList[0].get_fontproperties().get_size(), 16)
-
-    def testOnRemoveText(self):
-        """ Cheks if annotations can be removed from the graph """
-
-        # Add some text
-        self.plotter.plot(self.data)
-        test_text = "Safety instructions"
-        self.plotter.addText.textEdit.setText(test_text)
-        # Return OK from the dialog
-        self.plotter.addText.exec_ = MagicMock(return_value = QtGui.QDialog.Accepted)
-        # Add text to graph
-        self.plotter.onAddText()
-        self.plotter.show()
-        # Check if the text was added properly
-        self.assertEqual(len(self.plotter.textList), 1)
-
-        # Now, remove the text
-        self.plotter.onRemoveText()
-
-        # And assure no text is displayed
-        self.assertEqual(self.plotter.textList, [])
-
-        # Attempt removal on empty and check
-        self.plotter.onRemoveText()
-        self.assertEqual(self.plotter.textList, [])
-
-    def testOnSetGraphRange(self):
-        """ Cheks if the graph can be resized for range """
-        new_x = (1,2)
-        new_y = (10,11)
-        self.plotter.plot(self.data)
-        self.plotter.show()
-        self.plotter.setRange.exec_ = MagicMock(return_value = QtGui.QDialog.Accepted)
-        self.plotter.setRange.xrange = MagicMock(return_value = new_x)
-        self.plotter.setRange.yrange = MagicMock(return_value = new_y)
-
-        # Call the tested method
-        self.plotter.onSetGraphRange()
-        # See that ranges changed accordingly
-        self.assertEqual(self.plotter.ax.get_xlim(), new_x)
-        self.assertEqual(self.plotter.ax.get_ylim(), new_y)
-
-    def testOnResetGraphRange(self):
-        """ Cheks if the graph can be reset after resizing for range """
-        # New values
-        new_x = (1,2)
-        new_y = (10,11)
-        # define the plot
-        self.plotter.plot(self.data)
-        self.plotter.show()
-
-        # mock setRange methods
-        self.plotter.setRange.exec_ = MagicMock(return_value = QtGui.QDialog.Accepted)
-        self.plotter.setRange.xrange = MagicMock(return_value = new_x)
-        self.plotter.setRange.yrange = MagicMock(return_value = new_y)
-
-        # Change the axes range
-        self.plotter.onSetGraphRange()
-
-        # Now, reset the range back
-        self.plotter.onResetGraphRange()
-
-        # See that ranges are changed
-        self.assertNotEqual(self.plotter.ax.get_xlim(), new_x)
-        self.assertNotEqual(self.plotter.ax.get_ylim(), new_y)
-
-    def testOnLinearFit(self):
-        """ Checks the response to LinearFit call """
-        self.plotter.plot(self.data)
-        self.plotter.show()
-        QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
-
-        # Just this one plot
-        self.assertEqual(len(self.plotter.plot_dict.keys()), 1)
-        self.plotter.onLinearFit(1)
-
-        # Check that exec_ got called
-        self.assertTrue(QtGui.QDialog.exec_.called)
-
-    def testOnRemovePlot(self):
-        """ Assure plots get removed when requested """
-        # Add two plots
-        self.plotter.show()
-        self.plotter.plot(self.data)
-        data2 = Data1D(x=[1.0, 2.0, 3.0],
-                       y=[11.0, 12.0, 13.0],
-                       dx=[0.1, 0.2, 0.3],
-                       dy=[0.1, 0.2, 0.3])
-        data2.title="Test data 2"
-        data2.name="Test name 2"
-        data2.id = 2
-        self.plotter.plot(data2)
-
-        # Assure the plotter window is visible
-        #self.assertTrue(self.plotter.isVisible())
-
-        # Assure we have two sets
-        self.assertEqual(len(self.plotter.plot_dict.keys()), 2)
-
-        # Delete one set
-        self.plotter.onRemovePlot(2)
-        # Assure we have two sets
-        self.assertEqual(len(self.plotter.plot_dict.keys()), 1)
-
-        self.plotter.manager = MagicMock()
-
-        # Delete the remaining set
-        self.plotter.onRemovePlot(1)
-        # Assure we have no plots
-        self.assertEqual(len(self.plotter.plot_dict.keys()), 0)
-        # Assure the plotter window is closed
-        self.assertFalse(self.plotter.isVisible())
-
-
-    def testRemovePlot(self):
-        """ Test plot removal """
-        # Add two plots
-        self.plotter.show()
-        self.plotter.plot(self.data)
-        data2 = Data1D(x=[1.0, 2.0, 3.0],
-                       y=[11.0, 12.0, 13.0],
-                       dx=[0.1, 0.2, 0.3],
-                       dy=[0.1, 0.2, 0.3])
-        data2.title="Test data 2"
-        data2.name="Test name 2"
-        data2.id = 2
-        data2._xaxis = "XAXIS"
-        data2._xunit = "furlong*fortnight^{-1}"
-        data2._yaxis = "YAXIS"
-        data2._yunit = "cake"
-        data2.hide_error = True
-        self.plotter.plot(data2)
-
-        # delete plot 1
-        self.plotter.removePlot(1)
-
-        # See that the labels didn't change
-        xl = self.plotter.ax.xaxis.label.get_text()
-        yl = self.plotter.ax.yaxis.label.get_text()
-        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$")
-        self.assertEqual(yl, "$YAXIS(cake)$")
-        # The hide_error flag should also remain
-        self.assertTrue(self.plotter.plot_dict[2].hide_error)
-
-    def testOnToggleHideError(self):
-        """ Test the error bar toggle on plots """
-        # Add two plots
-        self.plotter.show()
-        self.plotter.plot(self.data)
-        data2 = Data1D(x=[1.0, 2.0, 3.0],
-                       y=[11.0, 12.0, 13.0],
-                       dx=[0.1, 0.2, 0.3],
-                       dy=[0.1, 0.2, 0.3])
-        data2.title="Test data 2"
-        data2.name="Test name 2"
-        data2.id = 2
-        data2._xaxis = "XAXIS"
-        data2._xunit = "furlong*fortnight^{-1}"
-        data2._yaxis = "YAXIS"
-        data2._yunit = "cake"
-        error_status = True
-        data2.hide_error = error_status
-        self.plotter.plot(data2)
-
-        # Reverse the toggle
-        self.plotter.onToggleHideError(2)
-        # See that the labels didn't change
-        xl = self.plotter.ax.xaxis.label.get_text()
-        yl = self.plotter.ax.yaxis.label.get_text()
-        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$")
-        self.assertEqual(yl, "$YAXIS(cake)$")
-        # The hide_error flag should toggle
-        self.assertEqual(self.plotter.plot_dict[2].hide_error, not error_status)
-
-    def testOnFitDisplay(self):
-        """ Test the fit line display on the chart """
-        self.assertIsInstance(self.plotter.fit_result, Data1D)
-        self.assertEqual(self.plotter.fit_result.symbol, 13)
-        self.assertEqual(self.plotter.fit_result.name, "Fit")
-
-        # fudge some init data
-        fit_data = [[0.0,0.0], [5.0,5.0]]
-        # Call the method
-        self.plotter.plot = MagicMock()
-        self.plotter.onFitDisplay(fit_data)
-        self.assertTrue(self.plotter.plot.called)
-        # Look at arguments passed to .plot()
-        self.plotter.plot.assert_called_with(data=self.plotter.fit_result,
-                                             hide_error=True, marker='-')
-
-    def testReplacePlot(self):
-        """ Test the plot refresh functionality """
-        # Add original data
-        self.plotter.show()
-        self.plotter.plot(self.data)
-        # See the default labels
-        xl = self.plotter.ax.xaxis.label.get_text()
-        yl = self.plotter.ax.yaxis.label.get_text()
-        self.assertEqual(xl, "$()$")
-        self.assertEqual(yl, "$()$")
-
-        # Prepare new data
-        data2 = Data1D(x=[1.0, 2.0, 3.0],
-                       y=[11.0, 12.0, 13.0],
-                       dx=[0.1, 0.2, 0.3],
-                       dy=[0.1, 0.2, 0.3])
-        data2.title="Test data 2"
-        data2.name="Test name 2"
-        data2.id = 2
-        data2._xaxis = "XAXIS"
-        data2._xunit = "furlong*fortnight^{-1}"
-        data2._yaxis = "YAXIS"
-        data2._yunit = "cake"
-        error_status = True
-        data2.hide_error = error_status
-
-        # Replace data in plot
-        self.plotter.replacePlot(1, data2)
-
-        # See that the labels changed
-        xl = self.plotter.ax.xaxis.label.get_text()
-        yl = self.plotter.ax.yaxis.label.get_text()
-        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$")
-        self.assertEqual(yl, "$YAXIS(cake)$")
-        # The hide_error flag should be as set
-        self.assertEqual(self.plotter.plot_dict[2].hide_error, error_status)
-
-    def testOnModifyPlot(self):
-        """ Test the functionality for changing plot properties """
-        # Prepare new data
-        data2 = Data1D(x=[1.0, 2.0, 3.0],
-                       y=[11.0, 12.0, 13.0],
-                       dx=[0.1, 0.2, 0.3],
-                       dy=[0.1, 0.2, 0.3])
-        data2.title="Test data 2"
-        data2.name="Test name 2"
-        data2.id = 2
-        data2.custom_color = None
-        data2.symbol = 1
-        data2.markersize = 11
-
-        self.plotter.plot(data2)
-
-        with patch('PlotProperties.PlotProperties') as mock:
-            instance = mock.return_value
-            QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted)
-            instance.symbol.return_value = 7
-
-            self.plotter.onModifyPlot(2)
-
-            #print self.plotter.plot_dict[2].symbol
-
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/SLDCalculatorTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/SLDCalculatorTest.py	(revision 416fa8fe6ed121e335fb8f0e75cdd9a8ab89b80d)
+++ 	(revision )
@@ -1,145 +1,0 @@
-import sys
-import unittest
-import webbrowser
-
-from PyQt4 import QtGui
-from PyQt4.QtTest import QTest
-from PyQt4 import QtCore
-from mock import MagicMock
-
-####### TEMP
-import path_prepare
-#######
-
-# Local
-from SldPanel import SldResult
-from SldPanel import SldPanel
-from SldPanel import sldAlgorithm
-from GuiUtils import FormulaValidator
-
-import LocalConfig
-
-app = QtGui.QApplication(sys.argv)
-
-class SldResultTest(unittest.TestCase):
-    """ Test the simple container class"""
-    def testObjectSize(self):
-        results = SldResult(0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-                            0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
-        self.assertEqual(sys.getsizeof(results), 56)
-
-
-class SldAlgorithmTest(unittest.TestCase):
-    """ Test the periodictable wrapper """
-    def testSldAlgorithm1(self):
-        molecular_formula = "H2O"
-        mass_density = 1.0
-        wavelength = 6.0
-        
-        results = sldAlgorithm( molecular_formula,
-                                mass_density,
-                                wavelength)
-        self.assertIsInstance(results, SldResult)
-        self.assertAlmostEqual(results.neutron_length, 0.175463, 5)
-        self.assertAlmostEqual(results.neutron_inc_xs, 5.365857, 5)
-        self.assertAlmostEqual(results.neutron_abs_xs, 0.074224, 5)
-
-    def testSldAlgorithm2(self):
-        molecular_formula = "C29O[18]5+7NH[2]3"
-        mass_density = 3.0
-        wavelength = 666.0
-        
-        results = sldAlgorithm( molecular_formula,
-                                mass_density,
-                                wavelength)
-        self.assertIsInstance(results, SldResult)
-        self.assertAlmostEqual(results.neutron_length,   0.059402, 5)
-        self.assertAlmostEqual(results.neutron_inc_xs,   0.145427, 5)
-        self.assertAlmostEqual(results.neutron_abs_xs,  15.512215, 5)
-        self.assertAlmostEqual(results.neutron_sld_real, 1.3352833e-05, 5)
-        self.assertAlmostEqual(results.neutron_sld_imag, 1.1645807e-10, 5)
-
-
-class SLDCalculatorTest(unittest.TestCase):
-    '''Test the SLDCalculator'''
-    def setUp(self):
-        '''Create the SLDCalculator'''
-        self.widget = SldPanel(None)
-
-    def tearDown(self):
-        '''Destroy the DensityCalculator'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QtGui.QWidget)
-        self.assertEqual(self.widget.windowTitle(), "SLD Calculator")
-        self.assertIsInstance(self.widget.ui.editMolecularFormula.validator(), FormulaValidator)
-        self.assertEqual(self.widget.ui.editMolecularFormula.styleSheet(), '')
-        self.assertEqual(self.widget.model.columnCount(), 1)
-        self.assertEqual(self.widget.model.rowCount(), 12)
-        self.assertEqual(self.widget.sizePolicy().Policy(), QtGui.QSizePolicy.Fixed)
-
-    def testSimpleEntry(self):
-        ''' Default compound calculations '''
-
-        self.widget.show()
-
-        self.widget.ui.editMassDensity.clear()
-        self.widget.ui.editMassDensity.insert("1.0")
-        # Send tab x3
-        key = QtCore.Qt.Key_Tab
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QtGui.qApp.processEvents()
-        QTest.qWait(100)
-
-        # Assure the output fields are set
-        self.assertEqual(self.widget.ui.editNeutronIncXs.text(), '5.37')
-
-        # Change mass density
-        self.widget.ui.editWavelength.clear()
-        self.widget.ui.editWavelength.setText("666.0")
-
-        # Send shift-tab to update the molar volume field
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QtGui.qApp.processEvents()
-        QTest.qWait(100)
-
-        # Assure the molar volume field got updated
-        self.assertEqual(self.widget.ui.editNeutronAbsXs.text(), '8.24')
-
-    def testComplexEntryAndReset(self):
-        ''' User entered compound calculations and subsequent reset'''
-
-        self.widget.ui.editMolecularFormula.clear()
-        self.widget.ui.editMolecularFormula.insert("CaCO[18]3+6H2O")
-        self.widget.ui.editMassDensity.insert("5.0")
-
-        self.widget.show()
-        # Send tab x2
-        key = QtCore.Qt.Key_Tab
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.keyEvent(QTest.Press, self.widget, key, QtCore.Qt.NoModifier)
-        QTest.qWait(100)
-
-        # Assure the mass density field is set
-        self.assertEqual(self.widget.ui.editNeutronIncXs.text(), '40.6')
-
-        # Reset the widget
-        self.widget.modelReset()
-
-        self.assertEqual(self.widget.ui.editMolecularFormula.text(), "H2O")
-        self.assertEqual(self.widget.ui.editMassDensity.text(), "1")
-        self.assertEqual(self.widget.ui.editWavelength.text(), "6")
-
-    def testHelp(self):
-        """ Assure help file is shown """
-
-        # this should not rise
-        self.widget.displayHelp()
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/SasviewLoggerTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/SasviewLoggerTest.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,58 +1,0 @@
-import sys
-import unittest
-import logging
-
-from PyQt4.QtGui import *
-from PyQt4.QtCore import *
-
-# set up import paths
-import path_prepare
-
-# Local
-from SasviewLogger import XStream
-from SasviewLogger import QtHandler
-
-app = QApplication(sys.argv)
-
-class SasviewLoggerTest(unittest.TestCase):
-    def setUp(self):
-        """
-        Prepare the logger
-        """
-        self.logger = logging.getLogger(__name__)
-        handler = QtHandler()
-        handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
-        self.logger.addHandler(handler)
-        self.logger.setLevel(logging.DEBUG)
-
-        self.outHandlerGui=QTextBrowser()
-
-
-    def testQtHandler(self):
-        """
-        Test redirection of all levels of logging
-        """
-        # Attach the listeners
-        XStream.stderr().messageWritten.connect( self.outHandlerGui.insertPlainText )
-        XStream.stdout().messageWritten.connect( self.outHandlerGui.insertPlainText )
-
-        # Send the signals
-        self.logger.debug('debug message')
-        self.logger.info('info message')
-        self.logger.warning('warning message')
-        self.logger.error('error message')
-        sys.stdout.write('with stdout')
-        sys.stderr.write('with stderr')
-
-        out=self.outHandlerGui.toPlainText()
-
-        # Assure everything got logged
-        self.assertIn('DEBUG: debug message', out)
-        self.assertIn('INFO: info message', out)
-        self.assertIn('WARNING: warning message', out)
-        self.assertIn('ERROR: error message', out)
-        self.assertIn('with stdout', out)
-        self.assertIn('with stderr', out)
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/ScalePropertiesTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/ScalePropertiesTest.py	(revision 6d05e1d115a38b7805a83cb480014af70b58ef75)
+++ 	(revision )
@@ -1,60 +1,0 @@
-import sys
-import unittest
-
-from PyQt4 import QtGui
-
-# set up import paths
-import path_prepare
-
-# Local
-from ScaleProperties import ScaleProperties
-
-app = QtGui.QApplication(sys.argv)
-
-class ScalePropertiesTest(unittest.TestCase):
-    '''Test the ScaleProperties'''
-    def setUp(self):
-        '''Create the ScaleProperties'''
-
-        self.widget = ScaleProperties(None)
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QtGui.QDialog)
-        self.assertEqual(self.widget.windowTitle(), "Scale Properties")
-        self.assertEqual(self.widget.cbX.count(), 6)
-        self.assertEqual(self.widget.cbY.count(), 12)
-        self.assertEqual(self.widget.cbView.count(), 6)
-        
-    def testGetValues(self):
-        '''Test the values returned'''
-        self.assertEqual(self.widget.getValues(), ("x", "y"))
-        self.widget.cbX.setCurrentIndex(2)
-        self.widget.cbY.setCurrentIndex(4)
-        self.assertEqual(self.widget.getValues(), ("x^(4)", "y*x^(2)"))
-
-    def testSettingView(self):
-        '''Test various settings of view'''
-        self.widget.cbView.setCurrentIndex(1)
-        self.assertEqual(self.widget.getValues(), ("x", "y"))
-        self.widget.cbView.setCurrentIndex(5)
-        self.assertEqual(self.widget.getValues(), ("x", "y*x^(2)"))
-
-        # Assure the View combobox resets on the x index changes
-        self.assertNotEqual(self.widget.cbView.currentIndex(), 0)
-        self.widget.cbX.setCurrentIndex(2)
-        self.assertEqual(self.widget.cbView.currentIndex(), 0)
-
-        # Same for Y
-        self.widget.cbView.setCurrentIndex(6)
-        self.assertNotEqual(self.widget.cbView.currentIndex(), 0)
-        self.widget.cbY.setCurrentIndex(2)
-        self.assertEqual(self.widget.cbView.currentIndex(), 0)
-      
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/SetGraphRangeTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/SetGraphRangeTest.py	(revision d3ca36332a95a5caf23ee8f8223a9c9912826726)
+++ 	(revision )
@@ -1,56 +1,0 @@
-import sys
-import unittest
-
-from PyQt4 import QtGui
-
-# set up import paths
-import path_prepare
-
-# Local
-from SetGraphRange import SetGraphRange
-
-app = QtGui.QApplication(sys.argv)
-
-class SetGraphRangeTest(unittest.TestCase):
-    '''Test the SetGraphRange'''
-    def setUp(self):
-        '''Create the SetGraphRange'''
-
-        self.widget = SetGraphRange(None)
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QtGui.QDialog)
-        self.assertEqual(self.widget.windowTitle(), "Set Graph Range")
-        self.assertIsInstance(self.widget.txtXmin, QtGui.QLineEdit)
-        self.assertIsInstance(self.widget.txtXmin.validator(), QtGui.QDoubleValidator)
-        
-    def testGoodRanges(self):
-        '''Test the X range values set by caller''' 
-        self.assertEqual(self.widget.xrange(), (0.0, 0.0))
-        self.assertEqual(self.widget.yrange(), (0.0, 0.0))
-
-        new_widget = SetGraphRange(None, ("1.0", 2.0), (8.0, "-2"))
-        self.assertEqual(new_widget.xrange(), (1.0, 2.0))
-        self.assertEqual(new_widget.yrange(), (8.0, -2.0))
-
-
-    def testBadRanges(self):
-        '''Test the incorrect X range values set by caller'''
-        with self.assertRaises(ValueError):
-            new_widget = SetGraphRange(None, ("1.0", "aa"), (None, "@"))
-            self.assertEqual(new_widget.xrange(), (1.0, 0.0))
-            self.assertEqual(new_widget.yrange(), (0.0, 0.0))
-
-        with self.assertRaises(AssertionError):
-            new_widget = SetGraphRange(None, "I'm a tuple", None)
-            self.assertEqual(new_widget.xrange(), (1.0, 0.0))
-            self.assertEqual(new_widget.yrange(), (0.0, 0.0))
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/SlicerModelTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/SlicerModelTest.py	(revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ 	(revision )
@@ -1,77 +1,0 @@
-import sys
-import unittest
-from mock import MagicMock
-
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-
-# set up import paths
-import path_prepare
-
-# Local
-from SlicerModel import SlicerModel
-
-app = QtGui.QApplication(sys.argv)
-
-class SlicerModelTest(unittest.TestCase):
-    '''Test the SlicerModel'''
-    def setUp(self):
-        '''Create the SlicerModel'''
-        class SModel(SlicerModel):
-            params = {"a":1, "b":2}
-            def __init__(self):
-                SlicerModel.__init__(self)
-            def getParams(self):
-                return self.params
-            def setParams(self, par):
-                self.params = par
-        self.model = SModel()
-
-    def tearDown(self):
-        '''Destroy the model'''
-        self.model = None
-
-    def testBaseClass(self):
-        '''Assure that SlicerModel contains pure virtuals'''
-        model = SlicerModel()
-        with self.assertRaises(NotImplementedError):
-            model.setParams()
-        with self.assertRaises(NotImplementedError):
-            model.setModelFromParams()
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.model.model(), QtGui.QStandardItemModel)
-
-    def testSetModelFromParams(self):
-        '''Test the model update'''
-        # Add a row to params
-        new_dict = self.model.getParams()
-        new_dict["c"] = 3
-        self.model.setParams(new_dict)
-
-        # Call the update
-        self.model.setModelFromParams()
-
-        # Check the new model.
-        self.assertEqual(self.model.model().rowCount(), 3)
-        self.assertEqual(self.model.model().columnCount(), 2)
-
-    def testSetParamsFromModel(self):
-        ''' Test the parameters update'''
-        # First - the default model
-        self.model.setModelFromParams()
-        self.assertEqual(self.model.model().rowCount(), 2)
-        self.assertEqual(self.model.model().columnCount(), 2)
-
-        # Add a row
-        item1 = QtGui.QStandardItem("c")
-        item2 = QtGui.QStandardItem(3)
-        self.model.model().appendRow([item1, item2])
-        # Check the new model. The update should be automatic
-        self.assertEqual(self.model.model().rowCount(), 3)
-        self.assertEqual(self.model.model().columnCount(), 2)
-
-
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/SlicerParametersTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/SlicerParametersTest.py	(revision cf89ccea6959685deabb93ffb245d9b592612e5c)
+++ 	(revision )
@@ -1,110 +1,0 @@
-import sys
-import unittest
-from mock import MagicMock
-
-from PyQt4 import QtGui
-from PyQt4 import QtCore
-from PyQt4 import QtTest
-from PyQt4 import QtWebKit
-
-from mock import MagicMock
-
-# set up import paths
-import path_prepare
-
-from UnitTesting.TestUtils import QtSignalSpy
-
-# Local
-from SlicerParameters import SlicerParameters
-
-app = QtGui.QApplication(sys.argv)
-
-class SlicerParametersTest(unittest.TestCase):
-    '''Test the SlicerParameters dialog'''
-    def setUp(self):
-        '''Create the SlicerParameters dialog'''
-
-        item1 = QtGui.QStandardItem("dromekage")
-        item2 = QtGui.QStandardItem("999.0")
-        self.model = QtGui.QStandardItemModel()
-        self.model.appendRow([item1, item2])
-        self.widget = SlicerParameters(model=self.model)
-
-    def tearDown(self):
-        '''Destroy the model'''
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        #self.widget.mapper
-        self.assertIsInstance(self.widget.proxy, QtGui.QIdentityProxyModel)
-        self.assertIsInstance(self.widget.lstParams.itemDelegate(), QtGui.QStyledItemDelegate)
-        self.assertTrue(self.widget.lstParams.model().columnReadOnly(0))
-        self.assertFalse(self.widget.lstParams.model().columnReadOnly(1))
-
-        # Test the proxy model
-        self.assertEqual(self.widget.lstParams.model(), self.widget.proxy)
-        self.assertEqual(self.widget.proxy.columnCount(), 2)
-        self.assertEqual(self.widget.proxy.rowCount(), 1)
-        self.assertEqual(self.widget.model.item(0,0).text(), 'dromekage')
-        self.assertEqual(self.widget.model.item(0,1).text(), '999.0')
-
-        # Check the flags in the proxy model
-        flags = self.widget.proxy.flags(self.widget.proxy.index(0,0))
-        self.assertFalse(flags & QtCore.Qt.ItemIsEditable)
-        self.assertTrue(flags & QtCore.Qt.ItemIsSelectable)
-        self.assertTrue(flags & QtCore.Qt.ItemIsEnabled)
-
-    def testClose(self):
-        ''' Assure that clicking on Close triggers right behaviour'''
-        self.widget.show()
-
-        # Set up the spy
-        spy_close = QtSignalSpy(self.widget, self.widget.close_signal)
-        # Click on the "Close" button
-        QtTest.QTest.mouseClick(self.widget.buttonBox.button(QtGui.QDialogButtonBox.Close), QtCore.Qt.LeftButton)
-        # Check the signal
-        self.assertEqual(spy_close.count(), 1)
-        # Assure the window got closed
-        self.assertFalse(self.widget.isVisible())
-
-    def testOnHelp(self):
-        ''' Assure clicking on help returns QtWeb view on requested page'''
-        self.widget.show()
-
-        #Mock the QWebView method
-        QtWebKit.QWebView.show = MagicMock()
-        QtWebKit.QWebView.load = MagicMock()
-
-        # Invoke the action
-        self.widget.onHelp()
-
-        # Check if show() got called
-        self.assertTrue(QtWebKit.QWebView.show.called)
-
-        # Assure the filename is correct
-        self.assertIn("graph_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
-        
-    def testSetModel(self):
-        ''' Test if resetting the model works'''
-        
-        item1 = QtGui.QStandardItem("s1")
-        item2 = QtGui.QStandardItem("5.0")
-        new_model = QtGui.QStandardItemModel()
-        new_model.appendRow([item1, item2])
-        item1 = QtGui.QStandardItem("s2")
-        item2 = QtGui.QStandardItem("20.0")
-        new_model.appendRow([item1, item2])
-        # Force the new model onto the widget
-        self.widget.setModel(model=new_model)
-
-        # Test if the widget got it
-        self.assertEqual(self.widget.model.columnCount(), 2)
-        self.assertEqual(self.widget.model.rowCount(), 2)
-        self.assertEqual(self.widget.model.item(0,0).text(), 's1')
-        self.assertEqual(self.widget.model.item(1,0).text(), 's2')
-
-
-        
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/SlitSizeCalculatorTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/SlitSizeCalculatorTest.py	(revision 886d2f2c2f6b63261dcd6876da8bea5382aa8536)
+++ 	(revision )
@@ -1,103 +1,0 @@
-import sys
-import unittest
-from PyQt4 import QtGui
-from PyQt4.QtTest import QTest
-from PyQt4.QtCore import Qt
-from mock import MagicMock
-
-# set up import paths
-import path_prepare
-
-from SlitSizeCalculator import SlitSizeCalculator
-from sas.sascalc.dataloader.loader import Loader
-
-app = QtGui.QApplication(sys.argv)
-
-
-class SlitSizeCalculatorTest(unittest.TestCase):
-    """Test the SlitSizeCalculator"""
-    def setUp(self):
-        """Create the SlitSizeCalculator"""
-        self.widget = SlitSizeCalculator(None)
-
-    def tearDown(self):
-        """Destroy the SlitSizeCalculator"""
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        """Test the GUI in its default state"""
-        self.assertIsInstance(self.widget, QtGui.QWidget)
-        self.assertEqual(self.widget.windowTitle(), "Slit Size Calculator")
-        self.assertEqual(self.widget.sizePolicy().Policy(), QtGui.QSizePolicy.Fixed)
-
-    def testHelp(self):
-        """ Assure help file is shown """
-
-        # this should not rise
-        self.widget.onHelp()
-
-    def testBrowseButton(self):
-        browseButton = self.widget.browseButton
-
-        filename = "beam_profile.DAT"
-
-        # Return no files.
-        QtGui.QFileDialog.getOpenFileName = MagicMock(return_value=None)
-
-        # Click on the Browse button
-        QTest.mouseClick(browseButton, Qt.LeftButton)
-
-        # Test the getOpenFileName() dialog called once
-        self.assertTrue(QtGui.QFileDialog.getOpenFileName.called)
-        QtGui.QFileDialog.getOpenFileName.assert_called_once()
-
-        # Now, return a single file
-        QtGui.QFileDialog.getOpenFileName = MagicMock(return_value=filename)
-
-        # Click on the Load button
-        QTest.mouseClick(browseButton, Qt.LeftButton)
-        QtGui.qApp.processEvents()
-
-        # Test the getOpenFileName() dialog called once
-        self.assertTrue(QtGui.QFileDialog.getOpenFileName.called)
-        QtGui.QFileDialog.getOpenFileName.assert_called_once()
-
-
-    def testCalculateSlitSize(self):
-        """ Test slit size calculated value """
-
-        filename = "beam_profile.DAT"
-        loader = Loader()
-        data = loader.load(filename)
-
-        self.widget.calculateSlitSize(data)
-        # The value "5.5858" was obtained by manual calculation.
-        # It turns out our slit length is FWHM/2
-        self.assertAlmostEqual(float(self.widget.slit_length_out.text()), 5.5858/2, 3)
-
-    def testWrongInput(self):
-        """ Test on wrong input data """
-
-        filename = "Dec07031.ASC"
-        loader = Loader()
-        data = loader.load(filename)
-        self.assertRaisesRegexp(RuntimeError,
-                                "Slit Length cannot be computed for 2D Data",
-                                self.widget.calculateSlitSize, data)
-
-        filename = "empty_file.txt"
-        loader = Loader()
-        data = loader.load(filename)
-        self.assertRaisesRegexp(RuntimeError,
-                                "ERROR: Data hasn't been loaded correctly",
-                                self.widget.calculateSlitSize, data)
-
-        data = None
-        self.assertRaisesRegexp(RuntimeError,
-                                "ERROR: Data hasn't been loaded correctly",
-                                self.widget.calculateSlitSize, data)
-
-
-if __name__ == "__main__":
-    unittest.main()
Index: src/sas/qtgui/UnitTesting/TestUtilsTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/TestUtilsTest.py	(revision 5032ea687fa17c1323c1124c0a7aa9d80184bf0b)
+++ src/sas/qtgui/UnitTesting/TestUtilsTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -8,6 +8,6 @@
 
 # Local
-from GuiUtils import Communicate
-from UnitTesting.TestUtils import *
+from sas.qtgui.Utilities.GuiUtils import Communicate
+from sas.qtgui.UnitTesting.TestUtils import *
 
 app = QApplication(sys.argv)
Index: c/sas/qtgui/UnitTesting/WelcomePanelTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/WelcomePanelTest.py	(revision adf81b86561ec1880ff7c8551a89a4175e4486d1)
+++ 	(revision )
@@ -1,41 +1,0 @@
-import sys
-import unittest
-
-from PyQt4 import QtGui
-
-# set up import paths
-import path_prepare
-
-# Local
-from WelcomePanel import WelcomePanel
-
-app = QtGui.QApplication(sys.argv)
-
-class WelcomePanelTest(unittest.TestCase):
-    '''Test the WelcomePanel'''
-    def setUp(self):
-        '''Create the WelcomePanel'''
-
-        self.widget = WelcomePanel(None)
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.assertIsInstance(self.widget, QtGui.QDialog)
-        self.assertEqual(self.widget.windowTitle(), "Welcome")
-        
-    def testVersion(self):
-        '''Test the version string'''
-        version = self.widget.lblVersion
-        self.assertIsInstance(version, QtGui.QLabel)
-
-        self.assertIn("SasView", version.text())
-        self.assertIn("Build:", version.text())
-        self.assertIn("UTK, UMD, NIST, ORNL, ISIS, ESS, ILL and ANSTO", version.text())
-       
-if __name__ == "__main__":
-    unittest.main()
Index: c/sas/qtgui/UnitTesting/WindowTitleTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/WindowTitleTest.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
+++ 	(revision )
@@ -1,46 +1,0 @@
-import sys
-import unittest
-
-from PyQt4 import QtGui
-
-# set up import paths
-import path_prepare
-
-# Local
-from WindowTitle import WindowTitle
-
-app = QtGui.QApplication(sys.argv)
-
-class WindowTitleTest(unittest.TestCase):
-    '''Test the WindowTitle'''
-    def setUp(self):
-        '''Create the WindowTitle'''
-        self.widget = WindowTitle(None, new_title="some title")
-
-    def tearDown(self):
-        '''Destroy the GUI'''
-        self.widget.close()
-        self.widget = None
-
-    def testDefaults(self):
-        '''Test the GUI in its default state'''
-        self.widget.show()
-        self.assertIsInstance(self.widget, QtGui.QDialog)
-        self.assertEqual(self.widget.windowTitle(), "Modify Window Title")
-        
-    def testTitle(self):
-        '''Modify the title'''
-        self.widget.show()
-        app.processEvents()
-        # make sure we have the pre-set title
-        self.assertEqual(self.widget.txtTitle.text(), "some title")
-        # Clear the control and set it to something else
-        self.widget.txtTitle.clear()
-        self.widget.txtTitle.setText("5 elephants")
-        # Retrieve value
-        new_title = self.widget.title()
-        # Check
-        self.assertEqual(new_title, "5 elephants")
-       
-if __name__ == "__main__":
-    unittest.main()
Index: src/sas/qtgui/Utilities/GuiUtils.py
===================================================================
--- src/sas/qtgui/Utilities/GuiUtils.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Utilities/GuiUtils.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,750 @@
+"""
+Global defaults and various utility functions usable by the general GUI
+"""
+
+import os
+import sys
+import imp
+import warnings
+import webbrowser
+import urlparse
+
+warnings.simplefilter("ignore")
+import logging
+
+from PyQt4 import QtCore
+from PyQt4 import QtGui
+
+# Translate event handlers
+#from sas.sasgui.guiframe.events import EVT_CATEGORY
+#from sas.sasgui.guiframe.events import EVT_STATUS
+#from sas.sasgui.guiframe.events import EVT_APPEND_BOOKMARK
+#from sas.sasgui.guiframe.events import EVT_PANEL_ON_FOCUS
+#from sas.sasgui.guiframe.events import EVT_NEW_LOAD_DATA
+#from sas.sasgui.guiframe.events import EVT_NEW_COLOR
+#from sas.sasgui.guiframe.events import StatusEvent
+#from sas.sasgui.guiframe.events import NewPlotEvent
+
+from periodictable import formula as Formula
+
+from sas.sasgui.plottools import transform
+from sas.sasgui.plottools.convert_units import convert_unit
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+from sas.sascalc.dataloader.loader import Loader
+
+
+def get_app_dir():
+    """
+        The application directory is the one where the default custom_config.py
+        file resides.
+
+        :returns: app_path - the path to the applicatin directory
+    """
+    # First, try the directory of the executable we are running
+    app_path = sys.path[0]
+    if os.path.isfile(app_path):
+        app_path = os.path.dirname(app_path)
+    if os.path.isfile(os.path.join(app_path, "custom_config.py")):
+        app_path = os.path.abspath(app_path)
+        #logging.info("Using application path: %s", app_path)
+        return app_path
+
+    # Next, try the current working directory
+    if os.path.isfile(os.path.join(os.getcwd(), "custom_config.py")):
+        #logging.info("Using application path: %s", os.getcwd())
+        return os.path.abspath(os.getcwd())
+
+    # Finally, try the directory of the sasview module
+    # TODO: gui_manager will have to know about sasview until we
+    # clean all these module variables and put them into a config class
+    # that can be passed by sasview.py.
+    #logging.info(sys.executable)
+    #logging.info(str(sys.argv))
+    from sas import sasview as sasview
+    app_path = os.path.dirname(sasview.__file__)
+    #logging.info("Using application path: %s", app_path)
+    return app_path
+
+def get_user_directory():
+    """
+        Returns the user's home directory
+    """
+    userdir = os.path.join(os.path.expanduser("~"), ".sasview")
+    if not os.path.isdir(userdir):
+        os.makedirs(userdir)
+    return userdir
+
+def _find_local_config(confg_file, path):
+    """
+        Find configuration file for the current application
+    """
+    config_module = None
+    fObj = None
+    try:
+        fObj, path_config, descr = imp.find_module(confg_file, [path])
+        config_module = imp.load_module(confg_file, fObj, path_config, descr)
+    except ImportError:
+        pass
+        #logging.error("Error loading %s/%s: %s" % (path, confg_file, sys.exc_value))
+    except ValueError:
+        print "Value error"
+        pass
+    finally:
+        if fObj is not None:
+            fObj.close()
+    #logging.info("GuiManager loaded %s/%s" % (path, confg_file))
+    return config_module
+
+# Get APP folder
+PATH_APP = get_app_dir()
+DATAPATH = PATH_APP
+
+# GUI always starts from the App folder
+#os.chdir(PATH_APP)
+# Read in the local config, which can either be with the main
+# application or in the installation directory
+config = _find_local_config('local_config', PATH_APP)
+
+if config is None:
+    config = _find_local_config('local_config', os.getcwd())
+    if config is None:
+        # Didn't find local config, load the default
+        import sas.sasgui.guiframe.config as config
+        #logging.info("using default local_config")
+    else:
+        pass
+        #logging.info("found local_config in %s", os.getcwd())
+else:
+    pass
+    #logging.info("found local_config in %s", PATH_APP)
+
+from sas.sasgui.guiframe.customdir  import SetupCustom
+c_conf_dir = SetupCustom().setup_dir(PATH_APP)
+
+custom_config = _find_local_config('custom_config', c_conf_dir)
+if custom_config is None:
+    custom_config = _find_local_config('custom_config', os.getcwd())
+    if custom_config is None:
+        msgConfig = "Custom_config file was not imported"
+        #logging.info(msgConfig)
+    else:
+        pass
+        #logging.info("using custom_config in %s", os.getcwd())
+else:
+    pass
+    #logging.info("using custom_config from %s", c_conf_dir)
+
+#read some constants from config
+APPLICATION_STATE_EXTENSION = config.APPLICATION_STATE_EXTENSION
+APPLICATION_NAME = config.__appname__
+SPLASH_SCREEN_PATH = config.SPLASH_SCREEN_PATH
+WELCOME_PANEL_ON = config.WELCOME_PANEL_ON
+SPLASH_SCREEN_WIDTH = config.SPLASH_SCREEN_WIDTH
+SPLASH_SCREEN_HEIGHT = config.SPLASH_SCREEN_HEIGHT
+SS_MAX_DISPLAY_TIME = config.SS_MAX_DISPLAY_TIME
+if not WELCOME_PANEL_ON:
+    WELCOME_PANEL_SHOW = False
+else:
+    WELCOME_PANEL_SHOW = True
+try:
+    DATALOADER_SHOW = custom_config.DATALOADER_SHOW
+    TOOLBAR_SHOW = custom_config.TOOLBAR_SHOW
+    FIXED_PANEL = custom_config.FIXED_PANEL
+    if WELCOME_PANEL_ON:
+        WELCOME_PANEL_SHOW = custom_config.WELCOME_PANEL_SHOW
+    PLOPANEL_WIDTH = custom_config.PLOPANEL_WIDTH
+    DATAPANEL_WIDTH = custom_config.DATAPANEL_WIDTH
+    GUIFRAME_WIDTH = custom_config.GUIFRAME_WIDTH
+    GUIFRAME_HEIGHT = custom_config.GUIFRAME_HEIGHT
+    CONTROL_WIDTH = custom_config.CONTROL_WIDTH
+    CONTROL_HEIGHT = custom_config.CONTROL_HEIGHT
+    DEFAULT_PERSPECTIVE = custom_config.DEFAULT_PERSPECTIVE
+    CLEANUP_PLOT = custom_config.CLEANUP_PLOT
+    # custom open_path
+    open_folder = custom_config.DEFAULT_OPEN_FOLDER
+    if open_folder != None and os.path.isdir(open_folder):
+        DEFAULT_OPEN_FOLDER = os.path.abspath(open_folder)
+    else:
+        DEFAULT_OPEN_FOLDER = PATH_APP
+except AttributeError:
+    DATALOADER_SHOW = True
+    TOOLBAR_SHOW = True
+    FIXED_PANEL = True
+    WELCOME_PANEL_SHOW = False
+    PLOPANEL_WIDTH = config.PLOPANEL_WIDTH
+    DATAPANEL_WIDTH = config.DATAPANEL_WIDTH
+    GUIFRAME_WIDTH = config.GUIFRAME_WIDTH
+    GUIFRAME_HEIGHT = config.GUIFRAME_HEIGHT
+    CONTROL_WIDTH = -1
+    CONTROL_HEIGHT = -1
+    DEFAULT_PERSPECTIVE = None
+    CLEANUP_PLOT = False
+    DEFAULT_OPEN_FOLDER = PATH_APP
+
+DEFAULT_STYLE = config.DEFAULT_STYLE
+
+PLUGIN_STATE_EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS
+OPEN_SAVE_MENU = config.OPEN_SAVE_PROJECT_MENU
+VIEW_MENU = config.VIEW_MENU
+EDIT_MENU = config.EDIT_MENU
+extension_list = []
+if APPLICATION_STATE_EXTENSION is not None:
+    extension_list.append(APPLICATION_STATE_EXTENSION)
+EXTENSIONS = PLUGIN_STATE_EXTENSIONS + extension_list
+try:
+    PLUGINS_WLIST = '|'.join(config.PLUGINS_WLIST)
+except AttributeError:
+    PLUGINS_WLIST = ''
+APPLICATION_WLIST = config.APPLICATION_WLIST
+IS_WIN = True
+IS_LINUX = False
+CLOSE_SHOW = True
+TIME_FACTOR = 2
+NOT_SO_GRAPH_LIST = ["BoxSum"]
+
+class Communicate(QtCore.QObject):
+    """
+    Utility class for tracking of the Qt signals
+    """
+    # File got successfully read
+    fileReadSignal = QtCore.pyqtSignal(list)
+
+    # Open File returns "list" of paths
+    fileDataReceivedSignal = QtCore.pyqtSignal(dict)
+
+    # Update Main window status bar with "str"
+    # Old "StatusEvent"
+    statusBarUpdateSignal = QtCore.pyqtSignal(str)
+
+    # Send data to the current perspective
+    updatePerspectiveWithDataSignal = QtCore.pyqtSignal(list)
+
+    # New data in current perspective
+    updateModelFromPerspectiveSignal = QtCore.pyqtSignal(QtGui.QStandardItem)
+
+    # New theory data in current perspective
+    updateTheoryFromPerspectiveSignal = QtCore.pyqtSignal(QtGui.QStandardItem)
+
+    # New plot requested from the GUI manager
+    # Old "NewPlotEvent"
+    plotRequestedSignal = QtCore.pyqtSignal(str)
+
+    # Plot update requested from a perspective
+    plotUpdateSignal = QtCore.pyqtSignal(list)
+
+    # Progress bar update value
+    progressBarUpdateSignal = QtCore.pyqtSignal(int)
+
+    # Workspace charts added/removed
+    activeGraphsSignal = QtCore.pyqtSignal(list)
+
+    # Current workspace chart's name changed
+    activeGraphName = QtCore.pyqtSignal(tuple)
+
+    # Current perspective changed
+    perspectiveChangedSignal = QtCore.pyqtSignal(str)
+
+
+def updateModelItemWithPlot(item, update_data, name=""):
+    """
+    Adds a checkboxed row named "name" to QStandardItem
+    Adds QVariant 'update_data' to that row.
+    """
+    assert isinstance(item, QtGui.QStandardItem)
+    assert isinstance(update_data, QtCore.QVariant)
+    py_update_data = update_data.toPyObject()
+
+    # Check if data with the same ID is already present
+    for index in range(item.rowCount()):
+        plot_item = item.child(index)
+        if plot_item.isCheckable():
+            plot_data = plot_item.child(0).data().toPyObject()
+            if plot_data.id is not None and plot_data.id == py_update_data.id:
+                # replace data section in item
+                plot_item.child(0).setData(update_data)
+                plot_item.setText(name)
+                # Force redisplay
+                return
+
+    # Create the new item
+    checkbox_item = createModelItemWithPlot(update_data, name)
+
+    # Append the new row to the main item
+    item.appendRow(checkbox_item)
+
+def createModelItemWithPlot(update_data, name=""):
+    """
+    Creates a checkboxed QStandardItem named "name"
+    Adds QVariant 'update_data' to that row.
+    """
+    assert isinstance(update_data, QtCore.QVariant)
+    py_update_data = update_data.toPyObject()
+
+    checkbox_item = QtGui.QStandardItem()
+    checkbox_item.setCheckable(True)
+    checkbox_item.setCheckState(QtCore.Qt.Checked)
+    checkbox_item.setText(name)
+
+    # Add "Info" item
+    if isinstance(py_update_data, (Data1D, Data2D)):
+        # If Data1/2D added - extract Info from it
+        info_item = infoFromData(py_update_data)
+    else:
+        # otherwise just add a naked item
+        info_item = QtGui.QStandardItem("Info")
+
+    # Add the actual Data1D/Data2D object
+    object_item = QtGui.QStandardItem()
+    object_item.setData(update_data)
+
+    # Set the data object as the first child
+    checkbox_item.setChild(0, object_item)
+
+    # Set info_item as the second child
+    checkbox_item.setChild(1, info_item)
+
+    # And return the newly created item
+    return checkbox_item
+
+def updateModelItem(item, update_data, name=""):
+    """
+    Adds a simple named child to QStandardItem
+    """
+    assert isinstance(item, QtGui.QStandardItem)
+    assert isinstance(update_data, list)
+
+    # Add the actual Data1D/Data2D object
+    object_item = QtGui.QStandardItem()
+    object_item.setText(name)
+    object_item.setData(QtCore.QVariant(update_data))
+
+    # Append the new row to the main item
+    item.appendRow(object_item)
+
+
+def plotsFromCheckedItems(model_item):
+    """
+    Returns the list of plots for items in the model which are checked
+    """
+    assert isinstance(model_item, QtGui.QStandardItemModel)
+
+    plot_data = []
+    # Iterate over model looking for items with checkboxes
+    for index in range(model_item.rowCount()):
+        item = model_item.item(index)
+        if item.isCheckable() and item.checkState() == QtCore.Qt.Checked:
+            # TODO: assure item type is correct (either data1/2D or Plotter)
+            plot_data.append((item, item.child(0).data().toPyObject()))
+        # Going 1 level deeper only
+        for index_2 in range(item.rowCount()):
+            item_2 = item.child(index_2)
+            if item_2 and item_2.isCheckable() and item_2.checkState() == QtCore.Qt.Checked:
+                # TODO: assure item type is correct (either data1/2D or Plotter)
+                plot_data.append((item_2, item_2.child(0).data().toPyObject()))
+
+    return plot_data
+
+def infoFromData(data):
+    """
+    Given Data1D/Data2D object, extract relevant Info elements
+    and add them to a model item
+    """
+    assert isinstance(data, (Data1D, Data2D))
+
+    info_item = QtGui.QStandardItem("Info")
+
+    title_item = QtGui.QStandardItem("Title: " + data.title)
+    info_item.appendRow(title_item)
+    run_item = QtGui.QStandardItem("Run: " + str(data.run))
+    info_item.appendRow(run_item)
+    type_item = QtGui.QStandardItem("Type: " + str(data.__class__.__name__))
+    info_item.appendRow(type_item)
+
+    if data.path:
+        path_item = QtGui.QStandardItem("Path: " + data.path)
+        info_item.appendRow(path_item)
+
+    if data.instrument:
+        instr_item = QtGui.QStandardItem("Instrument: " + data.instrument)
+        info_item.appendRow(instr_item)
+
+    process_item = QtGui.QStandardItem("Process")
+    if isinstance(data.process, list) and data.process:
+        for process in data.process:
+            process_date = process.date
+            process_date_item = QtGui.QStandardItem("Date: " + process_date)
+            process_item.appendRow(process_date_item)
+
+            process_descr = process.description
+            process_descr_item = QtGui.QStandardItem("Description: " + process_descr)
+            process_item.appendRow(process_descr_item)
+
+            process_name = process.name
+            process_name_item = QtGui.QStandardItem("Name: " + process_name)
+            process_item.appendRow(process_name_item)
+
+    info_item.appendRow(process_item)
+
+    return info_item
+
+def openLink(url):
+    """
+    Open a URL in an external browser.
+    Check the URL first, though.
+    """
+    parsed_url = urlparse.urlparse(url)
+    if parsed_url.scheme:
+        webbrowser.open(url)
+    else:
+        msg = "Attempt at opening an invalid URL"
+        raise AttributeError, msg
+
+def retrieveData1d(data):
+    """
+    Retrieve 1D data from file and construct its text
+    representation
+    """
+    if not isinstance(data, Data1D):
+        msg = "Incorrect type passed to retrieveData1d"
+        raise AttributeError, msg
+    try:
+        xmin = min(data.x)
+        ymin = min(data.y)
+    except:
+        msg = "Unable to find min/max of \n data named %s" % \
+                    data.filename
+        #logging.error(msg)
+        raise ValueError, msg
+
+    text = data.__str__()
+    text += 'Data Min Max:\n'
+    text += 'X_min = %s:  X_max = %s\n' % (xmin, max(data.x))
+    text += 'Y_min = %s:  Y_max = %s\n' % (ymin, max(data.y))
+    if data.dy != None:
+        text += 'dY_min = %s:  dY_max = %s\n' % (min(data.dy), max(data.dy))
+    text += '\nData Points:\n'
+    x_st = "X"
+    for index in range(len(data.x)):
+        if data.dy != None and len(data.dy) > index:
+            dy_val = data.dy[index]
+        else:
+            dy_val = 0.0
+        if data.dx != None and len(data.dx) > index:
+            dx_val = data.dx[index]
+        else:
+            dx_val = 0.0
+        if data.dxl != None and len(data.dxl) > index:
+            if index == 0:
+                x_st = "Xl"
+            dx_val = data.dxl[index]
+        elif data.dxw != None and len(data.dxw) > index:
+            if index == 0:
+                x_st = "Xw"
+            dx_val = data.dxw[index]
+
+        if index == 0:
+            text += "<index> \t<X> \t<Y> \t<dY> \t<d%s>\n" % x_st
+        text += "%s \t%s \t%s \t%s \t%s\n" % (index,
+                                                data.x[index],
+                                                data.y[index],
+                                                dy_val,
+                                                dx_val)
+    return text
+
+def retrieveData2d(data):
+    """
+    Retrieve 2D data from file and construct its text
+    representation
+    """
+    if not isinstance(data, Data2D):
+        msg = "Incorrect type passed to retrieveData2d"
+        raise AttributeError, msg
+
+    text = data.__str__()
+    text += 'Data Min Max:\n'
+    text += 'I_min = %s\n' % min(data.data)
+    text += 'I_max = %s\n\n' % max(data.data)
+    text += 'Data (First 2501) Points:\n'
+    text += 'Data columns include err(I).\n'
+    text += 'ASCII data starts here.\n'
+    text += "<index> \t<Qx> \t<Qy> \t<I> \t<dI> \t<dQparal> \t<dQperp>\n"
+    di_val = 0.0
+    dx_val = 0.0
+    dy_val = 0.0
+    len_data = len(data.qx_data)
+    for index in xrange(0, len_data):
+        x_val = data.qx_data[index]
+        y_val = data.qy_data[index]
+        i_val = data.data[index]
+        if data.err_data != None:
+            di_val = data.err_data[index]
+        if data.dqx_data != None:
+            dx_val = data.dqx_data[index]
+        if data.dqy_data != None:
+            dy_val = data.dqy_data[index]
+
+        text += "%s \t%s \t%s \t%s \t%s \t%s \t%s\n" % (index,
+                                                        x_val,
+                                                        y_val,
+                                                        i_val,
+                                                        di_val,
+                                                        dx_val,
+                                                        dy_val)
+        # Takes too long time for typical data2d: Break here
+        if index >= 2500:
+            text += ".............\n"
+            break
+
+    return text
+
+def onTXTSave(data, path):
+    """
+    Save file as formatted txt
+    """
+    with open(path,'w') as out:
+        has_errors = True
+        if data.dy == None or data.dy == []:
+            has_errors = False
+        # Sanity check
+        if has_errors:
+            try:
+                if len(data.y) != len(data.dy):
+                    has_errors = False
+            except:
+                has_errors = False
+        if has_errors:
+            if data.dx != None and data.dx != []:
+                out.write("<X>   <Y>   <dY>   <dX>\n")
+            else:
+                out.write("<X>   <Y>   <dY>\n")
+        else:
+            out.write("<X>   <Y>\n")
+
+        for i in range(len(data.x)):
+            if has_errors:
+                if data.dx != None and data.dx != []:
+                    if  data.dx[i] != None:
+                        out.write("%g  %g  %g  %g\n" % (data.x[i],
+                                                        data.y[i],
+                                                        data.dy[i],
+                                                        data.dx[i]))
+                    else:
+                        out.write("%g  %g  %g\n" % (data.x[i],
+                                                    data.y[i],
+                                                    data.dy[i]))
+                else:
+                    out.write("%g  %g  %g\n" % (data.x[i],
+                                                data.y[i],
+                                                data.dy[i]))
+            else:
+                out.write("%g  %g\n" % (data.x[i],
+                                        data.y[i]))
+
+def saveData1D(data):
+    """
+    Save 1D data points
+    """
+    default_name = os.path.basename(data.filename)
+    default_name, extension = os.path.splitext(default_name)
+    default_name += "_out" + extension
+
+    wildcard = "Text files (*.txt);;"\
+                "CanSAS 1D files(*.xml)"
+    kwargs = {
+        'caption'   : 'Save As',
+        'directory' : default_name,
+        'filter'    : wildcard,
+        'parent'    : None,
+    }
+    # Query user for filename.
+    filename = QtGui.QFileDialog.getSaveFileName(**kwargs)
+
+    # User cancelled.
+    if not filename:
+        return
+
+    filename = str(filename)
+
+    #Instantiate a loader
+    loader = Loader()
+    if os.path.splitext(filename)[1].lower() == ".txt":
+        onTXTSave(data, filename)
+    if os.path.splitext(filename)[1].lower() == ".xml":
+        loader.save(filename, data, ".xml")
+
+def saveData2D(data):
+    """
+    Save data2d dialog
+    """
+    default_name = os.path.basename(data.filename)
+    default_name, _ = os.path.splitext(default_name)
+    ext_format = ".dat"
+    default_name += "_out" + ext_format
+
+    wildcard = "IGOR/DAT 2D file in Q_map (*.dat)"
+    kwargs = {
+        'caption'   : 'Save As',
+        'directory' : default_name,
+        'filter'    : wildcard,
+        'parent'    : None,
+    }
+    # Query user for filename.
+    filename = QtGui.QFileDialog.getSaveFileName(**kwargs)
+
+    # User cancelled.
+    if not filename:
+        return
+    filename = str(filename)
+    #Instantiate a loader
+    loader = Loader()
+
+    if os.path.splitext(filename)[1].lower() == ext_format:
+        loader.save(filename, data, ext_format)
+
+class FormulaValidator(QtGui.QValidator):
+    def __init__(self, parent=None):
+        super(FormulaValidator, self).__init__(parent)
+  
+    def validate(self, input, pos):
+        try:
+            Formula(str(input))
+            self._setStyleSheet("")
+            return QtGui.QValidator.Acceptable, pos
+
+        except Exception as e:
+            self._setStyleSheet("background-color:pink;")
+            return QtGui.QValidator.Intermediate, pos
+
+    def _setStyleSheet(self, value):
+        try:
+            if self.parent():
+                self.parent().setStyleSheet(value)
+        except:
+            pass
+
+def xyTransform(data, xLabel="", yLabel=""):
+    """
+    Transforms x and y in View and set the scale
+    """
+    # Changing the scale might be incompatible with
+    # currently displayed data (for instance, going
+    # from ln to log when all plotted values have
+    # negative natural logs).
+    # Go linear and only change the scale at the end.
+    xscale = 'linear'
+    yscale = 'linear'
+    # Local data is either 1D or 2D
+    if data.id == 'fit':
+        return
+
+    # control axis labels from the panel itself
+    yname, yunits = data.get_yaxis()
+    xname, xunits = data.get_xaxis()
+
+    # Goes through all possible scales
+    # self.x_label is already wrapped with Latex "$", so using the argument
+
+    # X
+    if xLabel == "x":
+        data.transformX(transform.toX, transform.errToX)
+        xLabel = "%s(%s)" % (xname, xunits)
+    if xLabel == "x^(2)":
+        data.transformX(transform.toX2, transform.errToX2)
+        xunits = convert_unit(2, xunits)
+        xLabel = "%s^{2}(%s)" % (xname, xunits)
+    if xLabel == "x^(4)":
+        data.transformX(transform.toX4, transform.errToX4)
+        xunits = convert_unit(4, xunits)
+        xLabel = "%s^{4}(%s)" % (xname, xunits)
+    if xLabel == "ln(x)":
+        data.transformX(transform.toLogX, transform.errToLogX)
+        xLabel = "\ln{(%s)}(%s)" % (xname, xunits)
+    if xLabel == "log10(x)":
+        data.transformX(transform.toX_pos, transform.errToX_pos)
+        xscale = 'log'
+        xLabel = "%s(%s)" % (xname, xunits)
+    if xLabel == "log10(x^(4))":
+        data.transformX(transform.toX4, transform.errToX4)
+        xunits = convert_unit(4, xunits)
+        xLabel = "%s^{4}(%s)" % (xname, xunits)
+        xscale = 'log'
+
+    # Y
+    if yLabel == "ln(y)":
+        data.transformY(transform.toLogX, transform.errToLogX)
+        yLabel = "\ln{(%s)}(%s)" % (yname, yunits)
+    if yLabel == "y":
+        data.transformY(transform.toX, transform.errToX)
+        yLabel = "%s(%s)" % (yname, yunits)
+    if yLabel == "log10(y)":
+        data.transformY(transform.toX_pos, transform.errToX_pos)
+        yscale = 'log'
+        yLabel = "%s(%s)" % (yname, yunits)
+    if yLabel == "y^(2)":
+        data.transformY(transform.toX2, transform.errToX2)
+        yunits = convert_unit(2, yunits)
+        yLabel = "%s^{2}(%s)" % (yname, yunits)
+    if yLabel == "1/y":
+        data.transformY(transform.toOneOverX, transform.errOneOverX)
+        yunits = convert_unit(-1, yunits)
+        yLabel = "1/%s(%s)" % (yname, yunits)
+    if yLabel == "y*x^(2)":
+        data.transformY(transform.toYX2, transform.errToYX2)
+        xunits = convert_unit(2, xunits)
+        yLabel = "%s \ \ %s^{2}(%s%s)" % (yname, xname, yunits, xunits)
+    if yLabel == "y*x^(4)":
+        data.transformY(transform.toYX4, transform.errToYX4)
+        xunits = convert_unit(4, xunits)
+        yLabel = "%s \ \ %s^{4}(%s%s)" % (yname, xname, yunits, xunits)
+    if yLabel == "1/sqrt(y)":
+        data.transformY(transform.toOneOverSqrtX,
+                                transform.errOneOverSqrtX)
+        yunits = convert_unit(-0.5, yunits)
+        yLabel = "1/\sqrt{%s}(%s)" % (yname, yunits)
+    if yLabel == "ln(y*x)":
+        data.transformY(transform.toLogXY, transform.errToLogXY)
+        yLabel = "\ln{(%s \ \ %s)}(%s%s)" % (yname, xname, yunits, xunits)
+    if yLabel == "ln(y*x^(2))":
+        data.transformY(transform.toLogYX2, transform.errToLogYX2)
+        xunits = convert_unit(2, xunits)
+        yLabel = "\ln (%s \ \ %s^{2})(%s%s)" % (yname, xname, yunits, xunits)
+    if yLabel == "ln(y*x^(4))":
+        data.transformY(transform.toLogYX4, transform.errToLogYX4)
+        xunits = convert_unit(4, xunits)
+        yLabel = "\ln (%s \ \ %s^{4})(%s%s)" % (yname, xname, yunits, xunits)
+    if yLabel == "log10(y*x^(4))":
+        data.transformY(transform.toYX4, transform.errToYX4)
+        xunits = convert_unit(4, xunits)
+        yscale = 'log'
+        yLabel = "%s \ \ %s^{4}(%s%s)" % (yname, xname, yunits, xunits)
+
+    # Perform the transformation of data in data1d->View
+    data.transformView()
+
+    return (xLabel, yLabel, xscale, yscale)
+
+def dataFromItem(item):
+    """
+    Retrieve Data1D/2D component from QStandardItem.
+    The assumption - data stored in SasView standard, in child 0
+    """
+    return item.child(0).data().toPyObject()
+
+def formatNumber(value, high=False):
+    """
+    Return a float in a standardized, human-readable formatted string.
+    This is used to output readable (e.g. x.xxxe-y) values to the panel.
+    """
+    try:
+        value = float(value)
+    except:
+        output = "NaN"
+        return output.lstrip().rstrip()
+
+    if high:
+        output = "%-6.4g" % value
+
+    else:
+        output = "%-5.3g" % value
+    return output.lstrip().rstrip()
Index: src/sas/qtgui/Utilities/IPythonWidget.py
===================================================================
--- src/sas/qtgui/Utilities/IPythonWidget.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Utilities/IPythonWidget.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,28 @@
+from qtconsole.rich_jupyter_widget import RichJupyterWidget
+from qtconsole.inprocess import QtInProcessKernelManager
+from IPython.lib import guisupport
+
+MODULES_TO_IMPORT = [
+    ('sas', 'sas'),
+    ('sasmodels', 'sasmodels'),
+    ('numpy', 'np')]
+
+class IPythonWidget(RichJupyterWidget):
+    def __init__(self, parent=None, **kwargs):
+        super(self.__class__, self).__init__(parent)
+        app = guisupport.get_app_qt4()
+
+       # Create an in-process kernel
+        kernel_manager = QtInProcessKernelManager()
+        kernel_manager.start_kernel()
+        kernel = kernel_manager.kernel
+        kernel.gui = 'qt4'
+
+        kernel_client = kernel_manager.client()
+        kernel_client.start_channels()
+
+        self.kernel_manager = kernel_manager
+        self.kernel_client = kernel_client
+
+        self.kernel_manager.kernel.shell.run_code(
+            '\n'.join('import %s as %s' % t for t in MODULES_TO_IMPORT))
Index: src/sas/qtgui/Utilities/LocalConfig.py
===================================================================
--- src/sas/qtgui/Utilities/LocalConfig.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Utilities/LocalConfig.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,147 @@
+"""
+    Application settings
+"""
+import time
+import os
+import logging
+
+from sas.sasgui.guiframe.gui_style import GUIFRAME
+import sas.sasview
+
+# Version of the application
+__appname__ = "SasView"
+__version__ = sas.sasview.__version__
+__build__ = sas.sasview.__build__
+__download_page__ = 'https://github.com/SasView/sasview/releases'
+__update_URL__ = 'http://www.sasview.org/latestversion.json'
+
+# Debug message flag
+__EVT_DEBUG__ = False
+
+# Flag for automated testing
+__TEST__ = False
+
+# Debug message should be written to a file?
+__EVT_DEBUG_2_FILE__ = False
+__EVT_DEBUG_FILENAME__ = "debug.log"
+
+# About box info
+_do_aboutbox = True
+_do_acknowledge = True
+_do_tutorial = True
+_acknowledgement_preamble =\
+'''To ensure the long term support and development of this software please''' +\
+''' remember to do the following.'''
+_acknowledgement_preamble_bullet1 =\
+'''Acknowledge its use in your publications as suggested below'''
+_acknowledgement_preamble_bullet2 =\
+'''Reference the following website: http://www.sasview.org'''
+_acknowledgement_preamble_bullet3 =\
+'''Reference the model you used if appropriate (see documentation for refs)'''
+_acknowledgement_preamble_bullet4 =\
+'''Send us your reference for our records: developers@sasview.org'''
+_acknowledgement_publications = \
+'''This work benefited from the use of the SasView application, originally
+developed under NSF award DMR-0520547.
+'''
+_acknowledgement =  \
+'''This work originally developed as part of the DANSE project funded by the NSF
+under grant DMR-0520547, and currently maintained by NIST, UMD, ORNL, ISIS, ESS
+and ILL.
+
+'''
+_homepage = "http://www.sasview.org"
+_download = __download_page__
+_authors = []
+_paper = "http://sourceforge.net/p/sasview/tickets/"
+_license = "mailto:help@sasview.org"
+
+icon_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "images"))
+
+#logging.info("icon path: %s", icon_path)
+
+media_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "media"))
+test_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "test"))
+
+_nist_logo = os.path.join(icon_path, "nist_logo.png")
+_umd_logo = os.path.join(icon_path, "umd_logo.png")
+_sns_logo = os.path.join(icon_path, "sns_logo.png")
+_isis_logo = os.path.join(icon_path, "isis_logo.png")
+_ess_logo = os.path.join(icon_path, "ess_logo.png")
+_ill_logo = os.path.join(icon_path, "ill_logo.png")
+_ansto_logo = os.path.join(icon_path, "ansto_logo.png")
+_nsf_logo = os.path.join(icon_path, "nsf_logo.png")
+_danse_logo = os.path.join(icon_path, "danse_logo.png")
+_inst_logo = os.path.join(icon_path, "utlogo.gif")
+_nist_url = "http://www.nist.gov/"
+_umd_url = "http://www.umd.edu/"
+_sns_url = "http://neutrons.ornl.gov/"
+_nsf_url = "http://www.nsf.gov"
+_isis_url = "http://www.isis.stfc.ac.uk/"
+_ess_url = "http://ess-scandinavia.eu/"
+_ill_url = "http://www.ill.eu/"
+_ansto_url = "http://www.ansto.gov.au/"
+_danse_url = "http://www.cacr.caltech.edu/projects/danse/release/index.html"
+_inst_url = "http://www.utk.edu"
+_corner_image = os.path.join(icon_path, "angles_flat.png")
+_welcome_image = os.path.join(icon_path, "SVwelcome.png")
+_copyright = "(c) 2009 - 2013, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL and ANSTO"
+
+
+#edit the list of file state your plugin can read
+APPLICATION_WLIST = 'SasView files (*.svs)|*.svs'
+APPLICATION_STATE_EXTENSION = '.svs'
+GUIFRAME_WIDTH = 1150
+GUIFRAME_HEIGHT = 840
+PLUGIN_STATE_EXTENSIONS = ['.fitv', '.inv', '.prv']
+PLUGINS_WLIST = ['Fitting files (*.fitv)|*.fitv',
+                 'Invariant files (*.inv)|*.inv',
+                 'P(r) files (*.prv)|*.prv']
+PLOPANEL_WIDTH = 415
+PLOPANEL_HEIGTH = 370
+DATAPANEL_WIDTH = 235
+DATAPANEL_HEIGHT = 700
+SPLASH_SCREEN_PATH = os.path.join(icon_path, "SVwelcome_mini.png")
+TUTORIAL_PATH = os.path.join(media_path, "Tutorial.pdf")
+DEFAULT_STYLE = GUIFRAME.MULTIPLE_APPLICATIONS|GUIFRAME.MANAGER_ON\
+                    |GUIFRAME.CALCULATOR_ON|GUIFRAME.TOOLBAR_ON
+SPLASH_SCREEN_WIDTH = 512
+SPLASH_SCREEN_HEIGHT = 366
+SS_MAX_DISPLAY_TIME = 2000
+WELCOME_PANEL_ON = True
+WELCOME_PANEL_SHOW = False
+CLEANUP_PLOT = False
+# OPEN and SAVE project menu
+OPEN_SAVE_PROJECT_MENU = True
+#VIEW MENU
+VIEW_MENU = True
+#EDIT MENU
+EDIT_MENU = True
+
+SetupIconFile_win = os.path.join(icon_path, "ball.ico")
+SetupIconFile_mac = os.path.join(icon_path, "ball.icns")
+DefaultGroupName = "."
+OutputBaseFilename = "setupSasView"
+
+FIXED_PANEL = True
+DATALOADER_SHOW = True
+CLEANUP_PLOT = False
+WELCOME_PANEL_SHOW = False
+#Show or hide toolbar at the start up
+TOOLBAR_SHOW = True
+# set a default perspective
+DEFAULT_PERSPECTIVE = 'None'
+
+# Time out for updating sasview
+UPDATE_TIMEOUT = 2
+def printEVT(message):
+    """
+    Post a debug message to console/file
+    """
+    if __EVT_DEBUG__:
+        print "%g:  %s" % (time.clock(), message)
+
+        if __EVT_DEBUG_2_FILE__:
+            out = open(__EVT_DEBUG_FILENAME__, 'a')
+            out.write("%10g:  %s\n" % (time.clock(), message))
+            out.close()
Index: src/sas/qtgui/Utilities/SasviewLogger.py
===================================================================
--- src/sas/qtgui/Utilities/SasviewLogger.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Utilities/SasviewLogger.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,62 @@
+import os
+import sys
+import logging
+
+from PyQt4 import QtCore
+
+
+class XStream(QtCore.QObject):
+    _stdout = None
+    _stderr = None
+    messageWritten = QtCore.pyqtSignal(str)
+
+    def flush(self):
+        pass
+
+    def fileno(self):
+        return -1
+
+    def write(self, msg):
+        if(not self.signalsBlocked()):
+            self.messageWritten.emit(unicode(msg))
+
+    @staticmethod
+    def stdout():
+        if(not XStream._stdout):
+            XStream._stdout = XStream()
+            sys.stdout = XStream._stdout
+        return XStream._stdout
+
+    @staticmethod
+    def stderr():
+        if(not XStream._stderr):
+            XStream._stderr = XStream()
+            sys.stderr = XStream._stderr
+        return XStream._stderr
+
+class QtHandler(logging.Handler):
+    """
+    Version of logging handler
+    "emitting" the message to custom stdout()
+    """
+    def __init__(self):
+        logging.Handler.__init__(self)
+
+    def emit(self, record):
+        record = self.format(record)
+        if record:
+            XStream.stdout().write('%s\n'%record)
+
+
+# Define the default logger
+logger = logging.getLogger()
+
+# Add the file handler
+logging.basicConfig(level=logging.INFO,
+                    format='%(asctime)s %(levelname)s %(message)s',
+                    filename=os.path.join(os.path.expanduser("~"),
+                                          'sasview.log'))
+# Add the qt-signal logger
+handler = QtHandler()
+handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
+logger.addHandler(handler)
Index: src/sas/qtgui/Utilities/UnitTesting/GuiUtilsTest.py
===================================================================
--- src/sas/qtgui/Utilities/UnitTesting/GuiUtilsTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Utilities/UnitTesting/GuiUtilsTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,443 @@
+import sys
+import unittest
+import webbrowser
+
+from PyQt4 import QtCore
+from PyQt4 import QtGui
+from mock import MagicMock
+
+# set up import paths
+import sas.qtgui.path_prepare
+
+# SV imports
+from sas.sascalc.dataloader.loader import Loader
+from sas.sasgui.guiframe.data_manager import DataManager
+from sas.sasgui.guiframe.dataFitting import Data1D
+from sas.sasgui.guiframe.dataFitting import Data2D
+
+# Tested module
+from sas.qtgui.Utilities.GuiUtils import *
+
+app = QtGui.QApplication(sys.argv)
+
+class GuiUtilsTest(unittest.TestCase):
+    '''Test the GUI Utilities methods'''
+    def setUp(self):
+        '''Empty'''
+        pass
+
+    def tearDown(self):
+        '''Empty'''
+        pass
+
+    def testDefaults(self):
+        """
+        Test all the global constants defined in the file.
+        """
+        # Should probably test the constants in the file,
+        # but this will done after trimming down GuiUtils
+        # and retaining only necessary variables.
+        pass
+
+    def testGetAppDir(self):
+        """
+        """
+        pass
+
+    def testGetUserDirectory(self):
+        """
+        Simple test of user directory getter
+        """
+        home_dir = os.path.expanduser("~")
+        self.assertIn(home_dir, get_user_directory())
+
+    def testCommunicate(self):
+        """
+        Test the container class with signal definitions
+        """
+        com = Communicate()
+
+        # All defined signals
+        list_of_signals = [
+            'fileReadSignal',
+            'fileDataReceivedSignal',
+            'statusBarUpdateSignal',
+            'updatePerspectiveWithDataSignal',
+            'updateModelFromPerspectiveSignal',
+            'plotRequestedSignal',
+            'progressBarUpdateSignal',
+            'activeGraphName',
+        ]
+
+        # Assure all signals are defined.
+        for signal in list_of_signals:
+            self.assertIn(signal, dir(com))
+
+    def testupdateModelItem(self):
+        """
+        Test the generic QModelItem update method
+        """
+        test_item = QtGui.QStandardItem()
+        test_list = ['aa', 4, True, ]
+        name = "Black Sabbath"
+
+        # update the item
+        updateModelItem(test_item, test_list, name)
+
+        # Make sure test_item got all data added
+        self.assertEqual(test_item.child(0).text(), name)
+        list_from_item = test_item.child(0).data().toList()
+        self.assertIsInstance(list_from_item, list)
+        self.assertEqual(list_from_item[0].toPyObject(), test_list[0])
+        self.assertEqual(list_from_item[1].toPyObject(), test_list[1])
+        self.assertEqual(list_from_item[2].toPyObject(), test_list[2])
+
+    def testupdateModelItemWithPlot(self):
+        """
+        Test the QModelItem checkbox update method
+        """
+        test_item = QtGui.QStandardItem()
+        test_list = ['aa','11']
+        update_data = QtCore.QVariant(test_list)
+        name = "Black Sabbath"
+
+        # update the item
+        updateModelItemWithPlot(test_item, update_data, name)
+        
+        # Make sure test_item got all data added
+        self.assertEqual(test_item.child(0).text(), name)
+        self.assertTrue(test_item.child(0).isCheckable())
+        list_from_item = test_item.child(0).child(0).data().toPyObject()
+        self.assertIsInstance(list_from_item, list)
+        self.assertEqual(str(list_from_item[0]), test_list[0])
+        self.assertEqual(str(list_from_item[1]), test_list[1])
+
+
+    def testPlotsFromCheckedItems(self):
+        """
+        Test addition of a plottable to the model
+        """
+
+        # Mockup data
+        test_list0 = "FRIDAY"
+        test_list1 = "SATURDAY"
+        test_list2 = "MONDAY"
+
+        # Main item ("file")
+        checkbox_model = QtGui.QStandardItemModel()
+        checkbox_item = QtGui.QStandardItem(True)
+        checkbox_item.setCheckable(True)
+        checkbox_item.setCheckState(QtCore.Qt.Checked)
+        test_item0 = QtGui.QStandardItem()
+        test_item0.setData(QtCore.QVariant(test_list0))
+
+        # Checked item 1
+        test_item1 = QtGui.QStandardItem(True)
+        test_item1.setCheckable(True)
+        test_item1.setCheckState(QtCore.Qt.Checked)
+        object_item = QtGui.QStandardItem()
+        object_item.setData(QtCore.QVariant(test_list1))
+        test_item1.setChild(0, object_item)
+
+        checkbox_item.setChild(0, test_item0)
+        checkbox_item.appendRow(test_item1)
+
+        # Unchecked item 2
+        test_item2 = QtGui.QStandardItem(True)
+        test_item2.setCheckable(True)
+        test_item2.setCheckState(QtCore.Qt.Unchecked)
+        object_item = QtGui.QStandardItem()
+        object_item.setData(QtCore.QVariant(test_list2))
+        test_item2.setChild(0, object_item)
+        checkbox_item.appendRow(test_item2)
+
+        checkbox_model.appendRow(checkbox_item)
+
+        # Pull out the "plottable" documents
+        plot_list = plotsFromCheckedItems(checkbox_model)
+
+        # Make sure only the checked data is present
+        # FRIDAY IN
+        self.assertIn(test_list0, plot_list[0])
+        # SATURDAY IN
+        self.assertIn(test_list1, plot_list[1])
+        # MONDAY NOT IN
+        self.assertNotIn(test_list2, plot_list[0])
+        self.assertNotIn(test_list2, plot_list[1])
+
+    def testInfoFromData(self):
+        """
+        Test Info element extraction from a plottable object
+        """
+        loader = Loader()
+        manager = DataManager()
+
+        # get Data1D
+        p_file="cyl_400_20.txt"
+        output_object = loader.load(p_file)
+        new_data = manager.create_gui_data(output_object, p_file)
+
+        # Extract Info elements into a model item
+        item = infoFromData(new_data)
+
+        # Test the item and its children
+        self.assertIsInstance(item, QtGui.QStandardItem)
+        self.assertEqual(item.rowCount(), 5)
+        self.assertEqual(item.text(), "Info")
+        self.assertIn(p_file,   item.child(0).text())
+        self.assertIn("Run",    item.child(1).text())
+        self.assertIn("Data1D", item.child(2).text())
+        self.assertIn(p_file,   item.child(3).text())
+        self.assertIn("Process",item.child(4).text())
+
+    def testOpenLink(self):
+        """
+        Opening a link in the external browser
+        """
+        good_url1 = r"http://test.test.com"
+        good_url2 = r"mailto:test@mail.com"
+        good_url3 = r"https://127.0.0.1"
+
+        bad_url1 = ""
+        bad_url2 = QtGui.QStandardItem()
+        bad_url3 = r"poop;//**I.am.a.!bad@url"
+
+        webbrowser.open = MagicMock()
+        openLink(good_url1)
+        openLink(good_url2)
+        openLink(good_url3)
+        self.assertEqual(webbrowser.open.call_count, 3)
+
+        with self.assertRaises(AttributeError):
+            openLink(bad_url1)
+        with self.assertRaises(AttributeError):
+            openLink(bad_url2)
+        with self.assertRaises(AttributeError):
+            openLink(bad_url3)
+
+    def testRetrieveData1d(self):
+        """
+        """
+        with self.assertRaises(AttributeError):
+            retrieveData1d("BOOP")
+
+        #data = Data1D()
+        #with self.assertRaises(ValueError):
+        #    retrieveData1d(data)
+
+        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0])
+
+        text = retrieveData1d(data)
+
+        self.assertIn("Temperature:", text)
+        self.assertIn("Beam_size:", text)
+        self.assertIn("X_min = 1.0:  X_max = 3.0", text)
+        self.assertIn("3.0 \t12.0 \t0.0 \t0.0", text)
+
+    def testRetrieveData2d(self):
+        """
+        """
+        with self.assertRaises(AttributeError):
+            retrieveData2d("BOOP")
+        data = Data2D(image=[1.0, 2.0, 3.0],
+                      err_image=[0.01, 0.02, 0.03],
+                      qx_data=[0.1, 0.2, 0.3],
+                      qy_data=[0.1, 0.2, 0.3])
+
+        text = retrieveData2d(data)
+
+        self.assertIn("Type:         Data2D", text)
+        self.assertIn("I_min = 1.0", text)
+        self.assertIn("I_max = 3.0", text)
+        self.assertIn("2 \t0.3 \t0.3 \t3.0 \t0.03 \t0.0 \t0.0", text)
+
+    def testOnTXTSave(self):
+        """
+        Test the file writer for saving 1d/2d data
+        """
+        path = "test123"
+        if os.path.isfile(path):
+            os.remove(path)
+
+        # Broken data
+        data = Data1D(x=[1.0, 2.0, 3.0], y=[])
+        # Expect a raise
+        with self.assertRaises(IndexError):
+            onTXTSave(data, path)
+
+        # Good data - no dX/dY
+        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0])
+        onTXTSave(data, path)
+
+        self.assertTrue(os.path.isfile(path))
+        with open(path,'r') as out:
+            data_read = out.read()
+            self.assertEqual("<X>   <Y>\n1  10\n2  11\n3  12\n", data_read)
+
+        if os.path.isfile(path):
+            os.remove(path)
+
+        # Good data - with dX/dY
+        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0],
+                      dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
+
+        onTXTSave(data, path)
+        with open(path,'r') as out:
+            data_read = out.read()
+            self.assertIn("<X>   <Y>   <dY>   <dX>\n", data_read)
+            self.assertIn("1  10  0.1  0.1\n", data_read)
+            self.assertIn("2  11  0.2  0.2\n", data_read)
+            self.assertIn("3  12  0.3  0.3\n", data_read)
+
+        if os.path.isfile(path):
+            os.remove(path)
+
+    def testSaveData1D(self):
+        """
+        Test the 1D file save method
+        """
+        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0],
+                      dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
+
+        # Test the .txt format
+        file_name = "test123_out.txt"
+        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
+        data.filename = "test123.txt"
+        saveData1D(data)
+        self.assertTrue(os.path.isfile(file_name))
+        os.remove(file_name)
+
+        # Test the .xml format
+        file_name = "test123_out.xml"
+        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
+        data.filename = "test123.xml"
+        saveData1D(data)
+        self.assertTrue(os.path.isfile(file_name))
+        os.remove(file_name)
+
+        # Test the wrong format
+        file_name = "test123_out.mp3"
+        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
+        data.filename = "test123.mp3"
+        saveData1D(data)
+        self.assertFalse(os.path.isfile(file_name))
+
+    def testSaveData2D(self):
+        """
+        Test the 1D file save method
+        """
+        data = Data2D(image=[1.0, 2.0, 3.0],
+                      err_image=[0.01, 0.02, 0.03],
+                      qx_data=[0.1, 0.2, 0.3],
+                      qy_data=[0.1, 0.2, 0.3])
+
+        # Test the .txt format
+        file_name = "test123_out.dat"
+        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
+        data.filename = "test123.dat"
+        saveData2D(data)
+        self.assertTrue(os.path.isfile(file_name))
+        os.remove(file_name)
+
+        # Test the wrong format
+        file_name = "test123_out.mp3"
+        QtGui.QFileDialog.getSaveFileName = MagicMock(return_value=file_name)
+        data.filename = "test123.mp3"
+        saveData2D(data)
+        self.assertFalse(os.path.isfile(file_name))
+
+    def testXYTransform(self):
+        """ Assure the unit/legend transformation is correct"""
+        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0],
+                      dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="y")
+        self.assertEqual(xLabel, "()")
+        self.assertEqual(xscale, "linear")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x^(2)", yLabel="1/y")
+        self.assertEqual(xLabel, "^{2}(()^{2})")
+        self.assertEqual(yLabel, "1/(()^{-1})")
+        self.assertEqual(xscale, "linear")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x^(4)", yLabel="ln(y)")
+        self.assertEqual(xLabel, "^{4}(()^{4})")
+        self.assertEqual(yLabel, "\\ln{()}()")
+        self.assertEqual(xscale, "linear")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="ln(x)", yLabel="y^(2)")
+        self.assertEqual(xLabel, "\\ln{()}()")
+        self.assertEqual(yLabel, "^{2}(()^{2})")
+        self.assertEqual(xscale, "linear")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="log10(x)", yLabel="y*x^(2)")
+        self.assertEqual(xLabel, "()")
+        self.assertEqual(yLabel, " \\ \\ ^{2}(()^{2})")
+        self.assertEqual(xscale, "log")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="log10(x^(4))", yLabel="y*x^(4)")
+        self.assertEqual(xLabel, "^{4}(()^{4})")
+        self.assertEqual(yLabel, " \\ \\ ^{4}(()^{16})")
+        self.assertEqual(xscale, "log")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="1/sqrt(y)")
+        self.assertEqual(yLabel, "1/\\sqrt{}(()^{-0.5})")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="log10(y)")
+        self.assertEqual(yLabel, "()")
+        self.assertEqual(yscale, "log")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="ln(y*x)")
+        self.assertEqual(yLabel, "\\ln{( \\ \\ )}()")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="ln(y*x^(2))")
+        self.assertEqual(yLabel, "\\ln ( \\ \\ ^{2})(()^{2})")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="ln(y*x^(4))")
+        self.assertEqual(yLabel, "\\ln ( \\ \\ ^{4})(()^{4})")
+        self.assertEqual(yscale, "linear")
+
+        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="log10(y*x^(4))")
+        self.assertEqual(yLabel, " \\ \\ ^{4}(()^{4})")
+        self.assertEqual(yscale, "log")
+
+class FormulaValidatorTest(unittest.TestCase):
+    """ Test the formula validator """
+    def setUp(self):
+        '''Create the validator'''
+        self.validator = FormulaValidator()
+
+    def tearDown(self):
+        '''Destroy the validator'''
+        self.validator = None
+
+    def testValidateGood(self):
+        """Test a valid Formula """
+        formula_good = "H24O12C4C6N2Pu"
+        self.assertEqual(self.validator.validate(formula_good, 1)[0], QtGui.QValidator.Acceptable)
+
+        formula_good = "(H2O)0.5(D2O)0.5"
+        self.assertEqual(self.validator.validate(formula_good, 1)[0], QtGui.QValidator.Acceptable)
+
+    def testValidateBad(self):
+        """Test a valid Formula """
+        formula_bad = "H24 %%%O12C4C6N2Pu"
+        self.assertRaises(self.validator.validate(formula_bad, 1)[0])
+        self.assertEqual(self.validator.validate(formula_bad, 1)[0], QtGui.QValidator.Intermediate)
+
+        formula_bad = [1]
+        self.assertEqual(self.validator.validate(formula_bad, 1)[0], QtGui.QValidator.Intermediate)
+
+
+if __name__ == "__main__":
+    unittest.main()
+
Index: src/sas/qtgui/Utilities/UnitTesting/SasviewLoggerTest.py
===================================================================
--- src/sas/qtgui/Utilities/UnitTesting/SasviewLoggerTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Utilities/UnitTesting/SasviewLoggerTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,58 @@
+import sys
+import unittest
+import logging
+
+from PyQt4.QtGui import *
+from PyQt4.QtCore import *
+
+# set up import paths
+import sas.qtgui.path_prepare
+
+# Local
+from sas.qtgui.Utilities.SasviewLogger import XStream
+from sas.qtgui.Utilities.SasviewLogger import QtHandler
+
+app = QApplication(sys.argv)
+
+class SasviewLoggerTest(unittest.TestCase):
+    def setUp(self):
+        """
+        Prepare the logger
+        """
+        self.logger = logging.getLogger(__name__)
+        handler = QtHandler()
+        handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
+        self.logger.addHandler(handler)
+        self.logger.setLevel(logging.DEBUG)
+
+        self.outHandlerGui=QTextBrowser()
+
+
+    def testQtHandler(self):
+        """
+        Test redirection of all levels of logging
+        """
+        # Attach the listeners
+        XStream.stderr().messageWritten.connect( self.outHandlerGui.insertPlainText )
+        XStream.stdout().messageWritten.connect( self.outHandlerGui.insertPlainText )
+
+        # Send the signals
+        self.logger.debug('debug message')
+        self.logger.info('info message')
+        self.logger.warning('warning message')
+        self.logger.error('error message')
+        sys.stdout.write('with stdout')
+        sys.stderr.write('with stderr')
+
+        out=self.outHandlerGui.toPlainText()
+
+        # Assure everything got logged
+        self.assertIn('DEBUG: debug message', out)
+        self.assertIn('INFO: info message', out)
+        self.assertIn('WARNING: warning message', out)
+        self.assertIn('ERROR: error message', out)
+        self.assertIn('with stdout', out)
+        self.assertIn('with stderr', out)
+
+if __name__ == "__main__":
+    unittest.main()
Index: c/sas/qtgui/WelcomePanel.py
===================================================================
--- src/sas/qtgui/WelcomePanel.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ 	(revision )
@@ -1,28 +1,0 @@
-# global
-import sys
-import os
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-from PyQt4 import QtWebKit
-
-import sas.sasview
-import sas.qtgui.LocalConfig as LocalConfig
-
-from sas.qtgui.UI.WelcomePanelUI import Ui_WelcomePanelUI
-
-class WelcomePanel(QtGui.QDialog, Ui_WelcomePanelUI):
-    def __init__(self, parent=None):
-        super(WelcomePanel, self).__init__(parent)
-        self.setupUi(self)
-
-        self.setWindowTitle("Welcome")
-
-        version = sas.sasview.__version__
-        build = sas.sasview.__build__
-
-        ver = "\nSasView %s\nBuild: %s\n%s" % (version, build, LocalConfig._copyright)
-
-        self.lblVersion.setText(ver)
-
-        # no reason to have this widget resizable
-        self.setFixedSize(self.minimumSizeHint())
Index: c/sas/qtgui/WindowTitle.py
===================================================================
--- src/sas/qtgui/WindowTitle.py	(revision edbd4b6908fb314d8766a349cf5ae5c6ff8c6cfe)
+++ 	(revision )
@@ -1,19 +1,0 @@
-"""
-Allows users to change the title of the current graph
-from "Graph_n" to any ASCII text.
-"""
-from PyQt4 import QtGui
-
-from sas.qtgui.UI.WindowTitleUI import Ui_WindowTitle
-
-class WindowTitle(QtGui.QDialog, Ui_WindowTitle):
-    """ Simple GUI for a single line text query """
-    def __init__(self, parent=None, new_title=""):
-        super(WindowTitle, self).__init__(parent)
-        self.setupUi(self)
-        self.txtTitle.setText(new_title)
-
-    def title(self):
-        """ Return the new title """
-        return self.txtTitle.text()
-
Index: c/sas/qtgui/beam_profile.DAT
===================================================================
--- src/sas/qtgui/beam_profile.DAT	(revision debf5c3b08f61c4453e07a7454242eb2d96bfe9a)
+++ 	(revision )
@@ -1,54 +1,0 @@
-                                                                                
-SAXS BOX                                                                       
-       49        30         0         0         0         0         0         0
-  0.000000E+00   0.261200E+03   0.000000E+00   0.100000E+01   0.154200E+00
-  0.100000E+01   0.155999E+01   0.000000E+00   0.000000E+00   0.000000E+00
-  0.000000E+00   0.100000E+01   0.836825E+02
-  0.754396E-01   0.975440E+00   0.938981E+02
-  0.150879E+00   0.975745E+00   0.991879E+02
-  0.226319E+00   0.975473E+00   0.767819E+02
-  0.301758E+00   0.974517E+00   0.131319E+03
-  0.377198E+00   0.973001E+00   0.817830E+02
-  0.452637E+00   0.969088E+00   0.668273E+02
-  0.528077E+00   0.967890E+00   0.934950E+02
-  0.603517E+00   0.975536E+00   0.116805E+03
-  0.678956E+00   0.982809E+00   0.966191E+02
-  0.754396E+00   0.982538E+00   0.138675E+03
-  0.829835E+00   0.985082E+00  -0.100000E+01
-  0.905275E+00   0.991786E+00  -0.100000E+01
-  0.980715E+00   0.988353E+00  -0.100000E+01
-  0.105615E+01   0.977319E+00  -0.100000E+01
-  0.113159E+01   0.973398E+00  -0.100000E+01
-  0.120703E+01   0.975829E+00  -0.100000E+01
-  0.128247E+01   0.978032E+00  -0.100000E+01
-  0.135791E+01   0.977557E+00  -0.100000E+01
-  0.143335E+01   0.976422E+00  -0.100000E+01
-  0.150879E+01   0.982926E+00  -0.100000E+01
-  0.158423E+01   0.991207E+00  -0.100000E+01
-  0.165967E+01   0.982255E+00  -0.100000E+01
-  0.173511E+01   0.968295E+00  -0.100000E+01
-  0.181055E+01   0.973161E+00  -0.100000E+01
-  0.188599E+01   0.980441E+00  -0.100000E+01
-  0.196143E+01   0.973060E+00  -0.100000E+01
-  0.203687E+01   0.967479E+00  -0.100000E+01
-  0.211231E+01   0.968228E+00  -0.100000E+01
-  0.218775E+01   0.954858E+00  -0.100000E+01
-  0.226319E+01   0.920322E+00  -0.100000E+01
-  0.233863E+01   0.870665E+00  -0.100000E+01
-  0.241407E+01   0.814629E+00  -0.100000E+01
-  0.248951E+01   0.758434E+00  -0.100000E+01
-  0.256495E+01   0.694671E+00  -0.100000E+01
-  0.264039E+01   0.621470E+00  -0.100000E+01
-  0.271583E+01   0.554105E+00  -0.100000E+01
-  0.279126E+01   0.490278E+00  -0.100000E+01
-  0.286670E+01   0.408652E+00  -0.100000E+01
-  0.294214E+01   0.321530E+00  -0.100000E+01
-  0.301758E+01   0.255968E+00  -0.100000E+01
-  0.309302E+01   0.200420E+00  -0.100000E+01
-  0.316846E+01   0.140477E+00  -0.100000E+01
-  0.324390E+01   0.907699E-01  -0.100000E+01
-  0.331934E+01   0.593287E-01  -0.100000E+01
-  0.339478E+01   0.366914E-01  -0.100000E+01
-  0.347022E+01   0.198629E-01  -0.100000E+01
-  0.354566E+01   0.120037E-01  -0.100000E+01
-  0.362110E+01   0.110363E-01  -0.100000E+01
Index: src/sas/qtgui/convertUI.py
===================================================================
--- src/sas/qtgui/convertUI.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/convertUI.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -0,0 +1,32 @@
+# Convert all .ui files in all subdirectories of the current script
+import os
+
+def pyrrc(in_file, out_file):
+    """ Run the pyrcc4 script"""
+    execute = 'pyrcc4 -py3 %s -o %s' % (in_file, out_file)
+    os.system(execute)
+
+def pyuic(in_file, out_file):
+    """ Run the pyuic4 script"""
+    execute = 'pyuic4 -o %s %s' % (out_file, in_file)
+    os.system(execute)
+
+# look for .ui files
+for root, dirs, files in os.walk("."):
+    for file in files:
+        if file.endswith(".ui"):
+            file_in = os.path.join(root, file)
+            file_out = os.path.splitext(file_in)[0]+'.py'
+            pyuic(file_in, file_out)
+
+# RC file in UI directory
+ui_root = 'UI'
+rc_file = 'main_resources.qrc'
+out_file = 'main_resources_rc.py'
+pyrrc(os.path.join(ui_root, rc_file), os.path.join(ui_root, out_file))
+
+# Images
+ui_root = 'images'
+rc_file = 'images.qrc'
+out_file = 'images_rc.py'
+pyrrc(os.path.join(ui_root, rc_file), os.path.join(ui_root, out_file))
Index: src/sas/qtgui/images/convert_rc.bat
===================================================================
--- src/sas/qtgui/images/convert_rc.bat	(revision f51ed677cd8461e82d4cf08d0c78ef678c8f9433)
+++ src/sas/qtgui/images/convert_rc.bat	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -1,3 +1,4 @@
 @echo off
+
 
 pyrcc4.exe -py3 %1.qrc -o ..\UI\%1_rc.py
Index: c/sas/qtgui/rangeSlider.py
===================================================================
--- src/sas/qtgui/rangeSlider.py	(revision 5d89f43266c67cb96a7bf395800ce4cce896c9f8)
+++ 	(revision )
@@ -1,294 +1,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-/***************************************************************************
-Name                 : RangeSlider
-Description          : A slider for ranges
-Date                 : Jun 20, 2012 
-copyright            : (C) 2012 by Giuseppe Sucameli
-email                : brush.tyler@gmail.com
-
-the code is based on RangeSlider by phil
-(see https://svn.enthought.com/enthought/browser/TraitsBackendQt/trunk/enthought/traits/ui/qt4/extra/range_slider.py) licensed under GPLv2
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- ***************************************************************************/
-"""
-
-from PyQt4 import QtGui, QtCore
-
-class RangeSlider(QtGui.QSlider):
-    """ A slider for ranges.
-    
-        This class provides a dual-slider for ranges, where there is a defined
-        maximum and minimum, as is a normal slider, but instead of having a
-        single slider value, there are 2 slider values.
-        
-        This class emits the same signals as the QSlider base class, with the 
-        exception of valueChanged. 
-
-        In addition, two new signals are emitted to catch the movement of 
-        each handle, lowValueChanged(int) and highValueChanged(int).
-    """
-    highValueChanged = QtCore.pyqtSignal(int)
-    lowValueChanged = QtCore.pyqtSignal(int)
-    def __init__(self, *args):
-        super(RangeSlider, self).__init__(*args)
-
-        self._low = self.minimum()
-        self._high = self.maximum()
-        
-        self.pressed_control = QtGui.QStyle.SC_None
-        self.hover_control = QtGui.QStyle.SC_None
-        self.click_offset = 0
-        
-        # -1 for the low, 1 for the high, 0 for both
-        self.active_slider = -1
-
-    def lowValue(self):
-        return self._low
-
-    def setLowValue(self, low):
-        if low < self.minimum():
-            low = self.minimum()
-        if low == self._low:
-            return
-
-        self._low = low
-        self.update()
-
-        if self.hasTracking():
-            self.lowValueChanged.emit(self._low)
-
-    def highValue(self):
-        return self._high
-
-    def setHighValue(self, high):
-        if high > self.maximum():
-            high = self.maximum()
-        if high == self._high:
-            return
-
-        self._high = high
-        self.update()
-
-        if self.hasTracking():
-            self.lowValueChanged.emit(self._high)
-        
-    def paintEvent(self, event):
-        # based on http://qt.gitorious.org/qt/qt/blobs/master/src/gui/widgets/qslider.cpp
-
-        painter = QtGui.QPainter(self)
-        style = QtGui.QApplication.style() 
-
-        for i, value in enumerate([self._low, self._high]):
-            opt = QtGui.QStyleOptionSlider()
-            self.initStyleOption(opt)
-
-            gr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderGroove, self)
-            sr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderHandle, self)
-
-            if self.orientation() == QtCore.Qt.Horizontal:
-                handle_length = sr.width()
-                slider_length = gr.width()
-                slider_min = gr.x()
-                slider_max = gr.right() - handle_length + 1
-            else:
-                handle_length = sr.height()
-                slider_length = gr.height()
-                slider_min = gr.y()
-                slider_max = gr.bottom() - handle_length + 1
-
-            opt.subControls = QtGui.QStyle.SC_SliderGroove | QtGui.QStyle.SC_SliderHandle
-
-            # draw the first slider with inverted appearance, then the second 
-            # slider drawn on top of the existing ones
-            if i == 0:
-                if self.orientation() == QtCore.Qt.Horizontal:
-                    opt.upsideDown = not self.invertedAppearance()
-                else:
-                    opt.upsideDown = self.invertedAppearance()
-
-                if self.orientation() == QtCore.Qt.Horizontal:
-                    opt.sliderValue = value - self.minimum()
-                    opt.sliderPosition = self.minimum() + (self.maximum() - value)
-
-                    opt.rect.setX(slider_min)
-                    opt.rect.setWidth(slider_length)
-
-                else:
-                    opt.rect.setY(slider_min)
-                    opt.rect.setHeight(slider_length)
-
-            else:
-                # do not highlight the second part when has focus to avoid 
-                # drawing of partially overlapped semi-transparent backgrounds
-                opt.state &= ~QtGui.QStyle.State_HasFocus
-
-                opt.sliderValue = 0
-                opt.sliderPosition = self.minimum()
-
-                if self.orientation() == QtCore.Qt.Horizontal:
-                    opt.upsideDown = self.invertedAppearance()
-
-                    pos = style.sliderPositionFromValue(0, self.maximum()-self.minimum(),
-                                             value-self.minimum(), slider_max - slider_min - 4,
-                                             opt.upsideDown)
-
-                    opt.rect.setX(pos + 3)
-                    opt.rect.setWidth(slider_max - pos + handle_length - 3)
-
-                else:
-                    opt.upsideDown = not self.invertedAppearance()
-
-                    pos = style.sliderPositionFromValue(0, self.maximum()-self.minimum(),
-                                             self.maximum()-value, slider_max - slider_min - 4,
-                                             opt.upsideDown)
-
-                    opt.rect.setY(slider_min-1)
-                    opt.rect.setHeight(slider_min + slider_length - pos - 2)
-
-            if self.tickPosition() != self.NoTicks:
-                opt.subControls |= QtGui.QStyle.SC_SliderTickmarks
-
-            if self.pressed_control:
-                opt.activeSubControls = self.pressed_control
-                opt.state |= QtGui.QStyle.State_Sunken
-            else:
-                opt.activeSubControls = self.hover_control
-
-            style.drawComplexControl(QtGui.QStyle.CC_Slider, opt, painter, self)
-            
-        
-    def mousePressEvent(self, event):
-        event.accept()
-        
-        style = QtGui.QApplication.style()
-        button = event.button()
-        
-        # In a normal slider control, when the user clicks on a point in the 
-        # slider's total range, but not on the slider part of the control the
-        # control would jump the slider value to where the user clicked.
-        # For this control, clicks which are not direct hits will slide both
-        # slider parts
-                
-        if button:
-            opt = QtGui.QStyleOptionSlider()
-            self.initStyleOption(opt)
-
-            self.active_slider = 0
-            mid = (self.maximum() - self.minimum()) / 2.0
-            
-            for i, value in enumerate([self._low, self._high]):
-                opt.sliderPosition = value
-                hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(), self)
-
-                if hit == style.SC_SliderHandle:
-                    self.pressed_control = hit
-
-                    # if both handles are close together, avoid locks 
-                    # choosing the one with more empty space near it
-                    if self._low + 2 >= self._high:
-                        self.active_slider = 1 if self._high < mid else -1
-                    else:
-                        self.active_slider = -1 if i == 0 else 1
-                    self.triggerAction(self.SliderMove)
-                    self.setRepeatAction(self.SliderNoAction)
-                    self.setSliderDown(True)
-                    break
-
-            if self.active_slider == 0:
-                self.pressed_control = QtGui.QStyle.SC_SliderHandle
-                self.click_offset = self.__pixelPosToRangeValue(self.__pick(event.pos()))
-                self.triggerAction(self.SliderMove)
-                self.setRepeatAction(self.SliderNoAction)
-                self.setSliderDown(True)
-        else:
-            event.ignore()
-
-    def mouseReleaseEvent(self, event):
-        if self.pressed_control != QtGui.QStyle.SC_SliderHandle:
-            event.ignore()
-            return
-
-        self.setSliderDown(False)
-        return QtGui.QSlider.mouseReleaseEvent(self, event)
-                                
-    def mouseMoveEvent(self, event):
-        if self.pressed_control != QtGui.QStyle.SC_SliderHandle:
-            event.ignore()
-            return
-        
-        event.accept()
-        new_pos = self.__pixelPosToRangeValue(self.__pick(event.pos()))
-        opt = QtGui.QStyleOptionSlider()
-        self.initStyleOption(opt)
-
-        old_click_offset = self.click_offset
-        self.click_offset = new_pos
-        
-        if self.active_slider == 0:
-            offset = new_pos - old_click_offset
-            new_low = self._low + offset
-            new_high = self._high + offset
-
-            if new_low < self.minimum():
-                diff = self.minimum() - new_low
-                new_low += diff
-                new_high += diff
-            if new_high > self.maximum():
-                diff = self.maximum() - new_high
-                new_low += diff
-                new_high += diff
-
-            self.setLowValue( new_low )
-            self.setHighValue( new_high )
-
-        elif self.active_slider < 0:
-            if new_pos > self._high:
-                new_pos = self._high
-            self.setLowValue( new_pos )
-
-        else:
-            if new_pos < self._low:
-                new_pos = self._low
-            self.setHighValue( new_pos )
-
-        if self.hasTracking():
-            self.emit(QtCore.SIGNAL('sliderMoved(int)'), new_pos)
-
-            
-    def __pick(self, pt):
-        if self.orientation() == QtCore.Qt.Horizontal:
-            return pt.x()
-        else:
-            return pt.y()
-           
-           
-    def __pixelPosToRangeValue(self, pos):
-        opt = QtGui.QStyleOptionSlider()
-        self.initStyleOption(opt)
-        style = QtGui.QApplication.style()
-        
-        gr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderGroove, self)
-        sr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderHandle, self)
-        
-        if self.orientation() == QtCore.Qt.Horizontal:
-            handle_length = sr.width()
-            slider_min = gr.x() + handle_length/2
-            slider_max = gr.right() - handle_length/2 + 1
-        else:
-            handle_length = sr.height()
-            slider_min = gr.y() + handle_length/2
-            slider_max = gr.bottom() - handle_length/2 + 1
-            
-        return self.minimum() + style.sliderValueFromPosition(0, self.maximum()-self.minimum(),
-                                            pos-slider_min, slider_max - slider_min,
-                                            opt.upsideDown)
Index: src/sas/sasgui/guiframe/local_perspectives/plotting/AnnulusSlicer.py
===================================================================
--- src/sas/sasgui/guiframe/local_perspectives/plotting/AnnulusSlicer.py	(revision 116260af576567e73b38d3209bd4fbb3eb3dc267)
+++ src/sas/sasgui/guiframe/local_perspectives/plotting/AnnulusSlicer.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -5,7 +5,7 @@
 from BaseInteractor import _BaseInteractor
 from sas.sasgui.guiframe.dataFitting import Data1D
-import sas.qtgui.GuiUtils as GuiUtils
-from sas.qtgui.GuiUtils import formatNumber
-from sas.qtgui.SlicerModel import SlicerModel
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+from sas.qtgui.Utilities.GuiUtils import formatNumber
+from sas.qtgui.Plotting.SlicerModel import SlicerModel
 
 class AnnulusInteractor(_BaseInteractor, SlicerModel):
Index: src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py
===================================================================
--- src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py	(revision 116260af576567e73b38d3209bd4fbb3eb3dc267)
+++ src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -8,6 +8,6 @@
 from BaseInteractor import _BaseInteractor
 from sas.sasgui.guiframe.dataFitting import Data1D
-import sas.qtgui.GuiUtils as GuiUtils
-from sas.qtgui.SlicerModel import SlicerModel
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+from sas.qtgui.Plotting.SlicerModel import SlicerModel
 
 MIN_PHI = 0.05
Index: src/sas/sasgui/guiframe/local_perspectives/plotting/boxSlicer.py
===================================================================
--- src/sas/sasgui/guiframe/local_perspectives/plotting/boxSlicer.py	(revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ src/sas/sasgui/guiframe/local_perspectives/plotting/boxSlicer.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -5,6 +5,6 @@
 from BaseInteractor import _BaseInteractor
 from sas.sasgui.guiframe.dataFitting import Data1D
-import sas.qtgui.GuiUtils as GuiUtils
-from sas.qtgui.SlicerModel import SlicerModel
+import sas.qtgui.Utilities.GuiUtils as GuiUtils
+from sas.qtgui.Plotting.SlicerModel import SlicerModel
 
 
Index: src/sas/sasgui/guiframe/local_perspectives/plotting/boxSum.py
===================================================================
--- src/sas/sasgui/guiframe/local_perspectives/plotting/boxSum.py	(revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ src/sas/sasgui/guiframe/local_perspectives/plotting/boxSum.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
@@ -6,5 +6,5 @@
 from PyQt4 import QtGui
 from PyQt4 import QtCore
-from sas.qtgui.GuiUtils import formatNumber
+from sas.qtgui.Utilities.GuiUtils import formatNumber
 
 from BaseInteractor import _BaseInteractor
@@ -12,5 +12,5 @@
 from sas.sascalc.dataloader.manipulations import Boxsum
 
-from sas.qtgui.SlicerModel import SlicerModel
+from sas.qtgui.Plotting.SlicerModel import SlicerModel
 
 
