Index: build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/CMakeLists.txt
===================================================================
--- build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/CMakeLists.txt	(revision c3b2327d867ba1451da79a2e9f5c4f452720a71c)
+++ build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/CMakeLists.txt	(revision c3b2327d867ba1451da79a2e9f5c4f452720a71c)
@@ -0,0 +1,58 @@
+cmake_minimum_required(VERSION 2.6)
+
+# This will install a pyinstaller-generated sasview
+project(sasview C)
+
+# Define the version of sasview being packaged
+option(SAS_VERSION "Define SASView version to package" off)
+
+if (NOT ${SAS_VERSION})
+  message(FATAL_ERROR "SASView version unspecified!\n"
+    "Please use e.g. -DSAS_VERSION=4.1 ")
+endif()
+
+# main install work is done in this function
+macro(installDir path)
+  # Main install location is defined via CMAKE_INSTALL_PREFIX
+  # - what is chosen here is a subdirectory
+  install (
+    DIRECTORY "${path}/"
+    DESTINATION "sasview/${SAS_VERSION}"
+    PATTERN "Makefile*" EXCLUDE  # skip makefiles
+    PATTERN "#*"        EXCLUDE  # skip backup files
+    PATTERN ".*"        EXCLUDE  # skip hidden files
+    PATTERN "*.out"     EXCLUDE  # skip binary files
+    PATTERN "*.*.in"    EXCLUDE  # skip configure processed template files
+    PATTERN "*"
+    PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
+    GROUP_EXECUTE GROUP_READ
+    WORLD_EXECUTE WORLD_READ
+  )
+endmacro()
+
+# CPack configuration
+set(CPACK_PACKAGE_NAME          "sasview-${SAS_VERSION}")
+set(CPACK_RESOURCE_FilE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}../../LICENSE.TXT")
+set(CPACK_PACKAGE_CONTACT       "pkwi@fysik.dtu.dk")
+
+set(CPACK_PACKAGE_VERSION       "1.0")
+set(CPACK_PACKAGE_VERSION_MAJOR "1")
+set(CPACK_PACKAGE_VERSION_MINOR "0")
+
+# Have CPack respect install prefix
+set(CPACK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+set(CPACK_PACKAGING_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+
+# Avoid e.g. /usr/local being "part" of the RPMs
+set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST
+  ${CMAKE_INSTALL_PREFIX}
+  ${CMAKE_INSTALL_PREFIX}/bin
+  ${CMAKE_INSTALL_PREFIX}/sasview
+  )
+
+installDir("${PROJECT_SOURCE_DIR}/sasview")
+
+execute_process(COMMAND ln -s ${CMAKE_INSTALL_PREFIX}/sasview/${SAS_VERSION}/sasview sasview)
+install(FILES ${CMAKE_BINARY_DIR}/sasview DESTINATION ${CMAKE_INSTALL_PREFIX}/bin/)
+
+include(CPack)
Index: build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/README.md
===================================================================
--- build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/README.md	(revision c3b2327d867ba1451da79a2e9f5c4f452720a71c)
+++ build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/README.md	(revision c3b2327d867ba1451da79a2e9f5c4f452720a71c)
@@ -0,0 +1,18 @@
+Build tools for Debian and RPM
+------------------------------
+
+How-to  build SasView Debian and RPM packages on Ubuntu using Anaconda
+  
+  - Set up conda environment using the environment.yml file
+  - Use pyopencl from conda 
+  - Do not use pyopencl from pip - this will cause pyinstaller to fail finding pyopencl 
+  - Copy CMakelist.txt to the sasview/build_tools folder
+
+
+Known Issues:
+-------------
+  - pyopencl from conda is not the newest version
+  - To bypass one could build new pyopencl package based on the pip pyopencl package 
+  - Windows, OSX, Linux all have different versions of pyopencl available  on conda  
+
+
Index: build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/environment.yml
===================================================================
--- build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/environment.yml	(revision c3b2327d867ba1451da79a2e9f5c4f452720a71c)
+++ build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/environment.yml	(revision c3b2327d867ba1451da79a2e9f5c4f452720a71c)
@@ -0,0 +1,127 @@
+name: sasviewqt_new
+channels: !!python/tuple
+- !!python/unicode
+  'defaults'
+dependencies:
+- anaconda::alabaster=0.7.9=py27_0
+- anaconda::astroid=1.4.7=py27_0
+- anaconda::babel=2.3.4=py27_0
+- anaconda::backports=1.0=py27_0
+- anaconda::backports_abc=0.5=py27_0
+- anaconda::cairo=1.12.18=6
+- anaconda::decorator=4.0.10=py27_1
+- anaconda::docutils=0.12=py27_2
+- anaconda::enum34=1.1.6=py27_0
+- anaconda::fontconfig=2.11.1=6
+- anaconda::freetype=2.5.5=1
+- anaconda::funcsigs=1.0.2=py27_0
+- anaconda::get_terminal_size=1.0.0=py27_0
+- anaconda::glib=2.43.0=1
+- anaconda::harfbuzz=0.9.39=1
+- anaconda::html5lib=0.999=py27_0
+- anaconda::imagesize=0.7.1=py27_0
+- anaconda::ipykernel=4.5.2=py27_0
+- anaconda::ipython=5.1.0=py27_0
+- anaconda::ipython-qtconsole=4.0.1=py27_0
+- anaconda::ipython_genutils=0.1.0=py27_0
+- anaconda::jbig=2.1=0
+- anaconda::jinja2=2.8=py27_1
+- anaconda::jpeg=8d=2
+- anaconda::jupyter_client=4.4.0=py27_0
+- anaconda::jupyter_core=4.2.1=py27_0
+- anaconda::lazy-object-proxy=1.2.1=py27_0
+- anaconda::libffi=3.2.1=0
+- anaconda::libgfortran=3.0.0=1
+- anaconda::libiconv=1.14=0
+- anaconda::libpng=1.6.17=0
+- anaconda::libsodium=1.0.10=0
+- anaconda::libtiff=4.0.6=2
+- anaconda::libxml2=2.9.4=0
+- anaconda::libxslt=1.1.28=0
+- anaconda::lxml=3.6.4=py27_0
+- anaconda::markupsafe=0.23=py27_2
+- anaconda::mkl=11.3.3=0
+- anaconda::mock=2.0.0=py27_0
+- anaconda::openssl=1.0.2j=0
+- anaconda::pango=1.39.0=1
+- anaconda::path.py=8.2.1=py27_0
+- anaconda::pathlib2=2.1.0=py27_0
+- anaconda::pbr=1.10.0=py27_0
+- anaconda::pexpect=4.0.1=py27_0
+- anaconda::pickleshare=0.7.4=py27_0
+- anaconda::pillow=3.4.2=py27_0
+- anaconda::pip=9.0.1=py27_1
+- anaconda::pixman=0.32.6=0
+- anaconda::prompt_toolkit=1.0.9=py27_0
+- anaconda::ptyprocess=0.5.1=py27_0
+- anaconda::py2cairo=1.10.0=py27_2
+- anaconda::pygments=2.1.3=py27_0
+- anaconda::pylint=1.5.4=py27_1
+- anaconda::pyparsing=2.0.3=py27_0
+- anaconda::pyqt=4.11.4=py27_4
+- anaconda::python=2.7.12=1
+- anaconda::python-dateutil=2.4.2=py27_0
+- anaconda::pytz=2016.10=py27_0
+- anaconda::pyzmq=16.0.2=py27_0
+- anaconda::qt=4.8.7=4
+- anaconda::qtconsole=4.2.1=py27_0
+- anaconda::readline=6.2=2
+- anaconda::reportlab=3.3.0=py27_0
+- anaconda::setuptools=19.2=py27_0
+- anaconda::simplegeneric=0.8.1=py27_1
+- anaconda::singledispatch=3.4.0.3=py27_0
+- anaconda::sip=4.18=py27_0
+- anaconda::six=1.10.0=py27_0
+- anaconda::snowballstemmer=1.2.1=py27_0
+- anaconda::sphinx=1.4.8=py27_0
+- anaconda::sqlite=3.13.0=0
+- anaconda::ssl_match_hostname=3.4.0.2=py27_1
+- anaconda::tk=8.5.18=0
+- anaconda::tornado=4.4.2=py27_0
+- anaconda::traitlets=4.3.1=py27_0
+- anaconda::wcwidth=0.1.7=py27_0
+- anaconda::wheel=0.29.0=py27_0
+- anaconda::wrapt=1.10.8=py27_0
+- anaconda::wxpython=3.0.0.0=py27_2
+- anaconda::xz=5.2.2=0
+- anaconda::zeromq=4.1.5=0
+- anaconda::zlib=1.2.8=3
+- h5py=2.5.0=np19py27_3
+- hdf5=1.8.15.1=3
+- matplotlib=1.4.3=np19py27_2
+- numpy=1.9.3=py27_3
+- py=1.4.31=py27_0
+- pytest=3.0.5=py27_0
+- scipy=0.17.1=np19py27_1
+- timrudge::appdirs=1.4.0=py27_0
+- timrudge::mako=1.0.1=py27_0
+- timrudge::pyopencl=2014.1=np19py27_0
+- timrudge::pytools=2014.3.5=py27_0
+- pip:
+  - backports-abc==0.5
+  - backports.shutil-get-terminal-size==1.0.0
+  - backports.ssl-match-hostname==3.4.0.2
+  - bumps==0.7.6
+  - cffi==1.9.1
+  - constantly==15.1.0
+  - incremental==16.10.1
+  - ipython-genutils==0.1.0
+  - jupyter-client==4.4.0
+  - jupyter-core==4.2.1
+  - periodictable==1.4.1
+  - pisa==3.0.33
+  - prompt-toolkit==1.0.9
+  - pycparser==2.17
+  - pyinstaller==3.2
+  - pypdf2==1.26.0
+  - qt4reactor==1.6
+  - sasmodels==0.94
+  - sasview==4.0
+  - stdeb==0.8.5
+  - twisted==16.5.0
+  - unittest-xml-reporting==2.1.0
+  - wxpython-common==3.0.0.0
+  - xhtml2pdf==0.0.6
+  - zope.interface==4.3.2
+prefix: /home/vagrant/miniconda2/envs/sasviewqt_new
+
Index: build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/jenkins_linux_deb_rpm_build.sh
===================================================================
--- build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/jenkins_linux_deb_rpm_build.sh	(revision c3b2327d867ba1451da79a2e9f5c4f452720a71c)
+++ build_tools/Vagrant/Ubuntu1404/Build_deb_rpm/jenkins_linux_deb_rpm_build.sh	(revision c3b2327d867ba1451da79a2e9f5c4f452720a71c)
@@ -0,0 +1,107 @@
+# This build script is tested for Ubuntu build VM
+# This build script generates SasView Debian and RPM packages 
+
+export PATH=$PATH:/usr/local/bin/
+
+PYTHON=${PYTHON:-`which python`}
+EASY_INSTALL=${EASY_INSTALL:-`which easy_install`}
+PYLINT=${PYLINT:-`which pylint`}
+
+export PYTHONPATH=$PYTHONPATH:$WORKSPACE/sasview/utils
+export PYTHONPATH=$PYTHONPATH:$WORKSPACE/sasview/sasview-install
+
+
+cd $WORKSPACE
+
+
+# SET SASVIEW GITHASH
+cd $WORKSPACE
+cd sasview/sasview
+githash=$( git rev-parse HEAD )
+sed -i.bak s/GIT_COMMIT/$githash/g __init__.py
+
+
+# SASMODLES
+cd $WORKSPACE
+cd sasmodels
+
+rm -rf build
+rm -rf dist
+
+$PYTHON setup.py clean
+$PYTHON setup.py build
+
+
+# SASMODLES - BUILD DOCS
+cd  doc
+make html
+
+cd $WORKSPACE
+cd sasmodels
+$PYTHON setup.py bdist_egg
+
+
+# SASVIEW
+cd $WORKSPACE
+cd sasview
+rm -rf sasview-install
+mkdir  sasview-install
+rm -rf utils
+mkdir  utils
+rm -rf dist
+rm -rf build
+
+
+# INSTALL SASMODELS
+cd $WORKSPACE
+cd sasmodels
+cd dist
+$EASY_INSTALL -d $WORKSPACE/sasview/utils sasmodels*.egg
+
+
+# BUILD SASVIEW
+cd $WORKSPACE
+cd sasview
+$PYTHON setup.py clean
+$PYTHON setup.py build docs bdist_egg
+
+
+# INSTALL SASVIEW
+cd $WORKSPACE
+cd sasview
+cd dist
+$EASY_INSTALL -d $WORKSPACE/sasview/sasview-install sasview*.egg
+
+
+# TEST
+cd $WORKSPACE
+cd sasview
+cd test
+$PYTHON utest_sasview.py
+
+## PYLINT
+cd $WORKSPACE
+cd sasview
+$PYLINT --rcfile "build_tools/pylint.rc" -f parseable sasview-install/sasview*.egg/sas sasview | tee  test/sasview.txt
+
+# PYINSTALLER - SASVIEW
+cd $WORKSPACE
+cd sasview
+cd sasview
+pyinstaller ./sasview.spec
+
+# CMake Debian RPM package - SASVIEW
+cd $WORKSPACE
+cd sasview
+cd sasview
+cd dist
+cp $WORKSPACE/sasview/build_tools/CMakeLists.txt . 
+mkdir tmp
+cd tmp
+cmake .. -DSAS_VERSION=4.1 -DCMAKE_INSTALL_PREFIX=/usr/local
+cpack -G DEB
+cpack -G RPM
+
+# Back to WORKSPACE
+cd $WORKSPACE
+
Index: build_tools/Vagrant/Ubuntu1404/README.md
===================================================================
--- build_tools/Vagrant/Ubuntu1404/README.md	(revision e84ccf57052f81b796f647b3de00d554469a8318)
+++ build_tools/Vagrant/Ubuntu1404/README.md	(revision 95d32b78ba5ae7c946ddf728c88471627f9095a1)
@@ -1,42 +1,51 @@
-How to setup VM SasViewQt Ubuntu1404 developer env using Vagrant
+Ubuntu Vagrant Setup for SasViewQt 
+----------------------------------
+
+How-to setup VM SasViewQt Ubuntu1404 developer env using Vagrant
 
 A: Provision VM
+---------------
 
 B: Log on to VM - Setup Anaconda
-01) Install miniconda: $ bash ./Miniconda2-latest-Linux-x86_64.sh
-02) Export miniconda path: $ export PATH=/home/vagrant/miniconda2/bin:$PATH 
-03) Make sasviewqt env in minicona: conda env create -f environment.yml
+--------------------------------
+
+1. Install miniconda: $ bash ./Miniconda2-latest-Linux-x86_64.sh
+2. Export miniconda path: $ export PATH=/home/vagrant/miniconda2/bin:$PATH 
+3. Make sasviewqt env in minicona: conda env create -f environment.yml
 
 C: Build SasView
-04) clone sasview: git clone https://github.com/SasView/sasview
-05) clone sasmodels: git clone https://github.com/SasView/sasmodels
-06) show sasview branch: git remote show origin
-07) checkout ESS_GUI: git checkout ESS_GUI
-08) build sasmodels: python setup.py build
-09) build sasmodels doc: make html
-10) build sasview: python setup.py build
-11) build sasview: python setup.py docs
-12) run sasview: python run.py
-12) cd SasView/sasview/src/sas/qtgui
-13) make gui: ./make_ui.sh
-14) python run.py / python Main_Window.py depending on on your cloned githash
+----------------
+1. clone sasview: git clone https://github.com/SasView/sasview
+2. clone sasmodels: git clone https://github.com/SasView/sasmodels
+3. show sasview branch: git remote show origin
+4. checkout ESS\_GUI: git checkout ESS\_GUI
+5. build sasmodels: python setup.py build
+6. build sasmodels doc: make html
+7. build sasview: python setup.py build
+8. build sasview: python setup.py docs
+9. run sasview: python run.py
+10. cd SasView/sasview/src/sas/qtgui
+11. make gui: ./make_ui.sh
+12. python run.py / python Main\_Window.py depending on on your cloned githash
 
 Tips:
-export PATH=/home/vagrant/miniconda2/bin:$PATH
+----
 
-conda env export > environment.yml
-conda env create -f environment.yml
+   - $ export PATH=/home/vagrant/miniconda2/bin:$PATH
+   - $ conda env export > environment.yml
+   - $ conda env create -f environment.yml
 
+To activate this environment, use:
 
-# To activate this environment, use:
-# > source activate sasviewqt
-#
-# To deactivate this environment, use:
-# > source deactivate sasviewqt
+   - $ source activate sasviewqt
 
+To deactivate this environment, use:
+
+   - $ source deactivate sasviewqt
 
 
 Known problems:
-libxml2 not installed.
+---------------
 
+   - libxml2 not installed.
 
Index: src/sas/qtgui/DataExplorer.py
===================================================================
--- src/sas/qtgui/DataExplorer.py	(revision 253e71709965f90b7bc2117d8f92970d57be3756)
+++ src/sas/qtgui/DataExplorer.py	(revision 253e71709965f90b7bc2117d8f92970d57be3756)
@@ -80,4 +80,5 @@
         self.communicator.fileReadSignal.connect(self.loadFromURL)
         self.communicator.activeGraphsSignal.connect(self.updateGraphCombo)
+        self.communicator.activeGraphName.connect(self.updatePlotName)
         self.cbgraph.editTextChanged.connect(self.enableGraphCombo)
         self.cbgraph.currentIndexChanged.connect(self.enableGraphCombo)
@@ -368,4 +369,13 @@
         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):
         """
@@ -411,8 +421,9 @@
                 raise AttributeError, msg
 
+
         if plots and \
-           hasattr(new_plot, 'data') and \
-           len(new_plot.data.x) > 0:
-            self.plotAdd(new_plot)
+            hasattr(new_plot, 'data') and \
+            isinstance(new_plot.data, Data1D):
+                self.plotAdd(new_plot)
 
     def plotAdd(self, new_plot):
@@ -436,6 +447,4 @@
         """
         Add data set(s) to the existing matplotlib chart
-
-        TODO: Add 2D-functionality
         """
         # new plot data
@@ -443,6 +452,5 @@
 
         # old plot data
-        plot_id = self.cbgraph.currentText()
-        plot_id = int(plot_id[5:])
+        plot_id = self.cbgraph.currentIndex() + 1
 
         assert plot_id in PlotHelper.currentPlots(), "No such plot: Graph%s"%str(plot_id)
Index: src/sas/qtgui/GUITests.py
===================================================================
--- src/sas/qtgui/GUITests.py	(revision 64f1e93f1ae889a528e0186e82bbbc473c1cc6ee)
+++ src/sas/qtgui/GUITests.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -10,4 +10,5 @@
 from UnitTesting import TestUtilsTest
 from UnitTesting import PlotHelperTest
+from UnitTesting import PlotterBaseTest
 from UnitTesting import PlotterTest
 from UnitTesting import Plotter2DTest
@@ -16,4 +17,5 @@
 from UnitTesting import KiessigCalculatorTest
 from UnitTesting import DensityCalculatorTest
+from UnitTesting import WindowTitleTest
 
 def suite():
@@ -28,4 +30,5 @@
         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'),
@@ -34,4 +37,5 @@
         unittest.makeSuite(KiessigCalculatorTest.KiessigCalculatorTest, 'test'),
         unittest.makeSuite(DensityCalculatorTest.DensityCalculatorTest, 'test'),
+        unittest.makeSuite(WindowTitleTest.WindowTitleTest, 'test'),
     )
     return unittest.TestSuite(suites)
Index: src/sas/qtgui/GuiUtils.py
===================================================================
--- src/sas/qtgui/GuiUtils.py	(revision 8548d7394b7d5bccb2adcbf40bfba40d97186d70)
+++ src/sas/qtgui/GuiUtils.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -229,4 +229,7 @@
     activeGraphsSignal = QtCore.pyqtSignal(list)
 
+    # Current workspace chart's name changed
+    activeGraphName = QtCore.pyqtSignal(tuple)
+
 
 def updateModelItemWithPlot(item, update_data, name=""):
Index: src/sas/qtgui/PlotUtilities.py
===================================================================
--- src/sas/qtgui/PlotUtilities.py	(revision 31c5b583d8c577c4ed72be87d22d34ec2ed50c04)
+++ src/sas/qtgui/PlotUtilities.py	(revision fecfe283c4a23a8b1ec879117e43b24a7fce28a4)
@@ -13,5 +13,5 @@
     """
     # No qx or qy given in a vector format
-    if qx_data == None or qy_data == None \
+    if qx_data is None or qy_data is None \
             or qx_data.ndim != 1 or qy_data.ndim != 1:
         return data
@@ -72,5 +72,5 @@
     """
     # No qx or qy given in a vector format
-    if qx_data == None or qy_data == None \
+    if qx_data is None or qy_data is None \
             or qx_data.ndim != 1 or qy_data.ndim != 1:
         return data
Index: src/sas/qtgui/Plotter.py
===================================================================
--- src/sas/qtgui/Plotter.py	(revision 416fa8fe6ed121e335fb8f0e75cdd9a8ab89b80d)
+++ src/sas/qtgui/Plotter.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -8,6 +8,10 @@
 
 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
 
     @property
@@ -23,5 +27,5 @@
         self.title(title=value.title)
 
-    def plot(self, marker=None, linestyle=None):
+    def plot(self, marker=None, linestyle=None, hide_error=False):
         """
         Plot self._data
@@ -34,12 +38,21 @@
 
         if linestyle == None:
-            linestyle = '-'
-
-        # plot data with title
-        ax.plot(self._data.view.x,
-                self._data.view.y,
-                marker=marker,
-                linestyle=linestyle,
-                label=self._title)
+            linestyle = ''
+
+        # plot data with/without errorbars
+        if hide_error:
+            ax.plot(self._data.view.x, self._data.view.y,
+                    marker=marker,
+                    linestyle=linestyle,
+                    label=self._title)
+        else:
+            ax.errorbar(self._data.view.x, self._data.view.y,
+                        yerr=self._data.view.dx, xerr=None,
+                        capsize=2, linestyle='',
+                        barsabove=False,
+                        marker=marker,
+                        lolims=False, uplims=False,
+                        xlolims=False, xuplims=False,
+                        label=self._title)
 
         # Now add the legend with some customizations.
@@ -55,20 +68,51 @@
 
         # Include scaling (log vs. linear)
-        ax.set_yscale(self.xscale)
         ax.set_xscale(self.xscale)
+        ax.set_yscale(self.yscale)
 
         # refresh canvas
         self.canvas.draw()
 
+    def contextMenu(self):
+        """
+        Define common context menu and associated actions for the MPL widget
+        """
+        self.defaultContextMenu()
+
+        # Additional menu items
+        self.contextMenu.addSeparator()
+        self.actionModifyGraphAppearance =\
+            self.contextMenu.addAction("Modify Graph Appearance")
+        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.actionModifyGraphAppearance.triggered.connect(self.onModifyGraph)
+        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 contextMenuQuickPlot(self):
         """
         Define context menu and associated actions for the quickplot MPL widget
         """
-        # Actions
-        self.contextMenu = QtGui.QMenu(self)
-        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()
+        # Default actions
+        self.defaultContextMenu()
+
+        # Additional actions
         self.actionToggleGrid = self.contextMenu.addAction("Toggle Grid On/Off")
         self.contextMenu.addSeparator()
@@ -76,7 +120,4 @@
 
         # Define the callbacks
-        self.actionSaveImage.triggered.connect(self.onImageSave)
-        self.actionPrintImage.triggered.connect(self.onImagePrint)
-        self.actionCopyToClipboard.triggered.connect(self.onClipboardCopy)
         self.actionToggleGrid.triggered.connect(self.onGridToggle)
         self.actionChangeScale.triggered.connect(self.onScaleChange)
@@ -89,4 +130,39 @@
             xLabel, yLabel = self.properties.getValues()
             self.xyTransform(xLabel, yLabel)
+
+    def onModifyGraph(self):
+        """
+        Show a dialog allowing chart manipulations
+        """
+        print ("onModifyGraph")
+        pass
+
+    def onAddText(self):
+        """
+        Show a dialog allowing adding custom text to the chart
+        """
+        print("onAddText")
+        pass
+
+    def onRemoveText(self):
+        """
+        Remove the most recent added text
+        """
+        print("onRemoveText")
+        pass
+
+    def onSetGraphRange(self):
+        """
+        Show a dialog allowing setting the chart ranges
+        """
+        print("onSetGraphRange")
+        pass
+
+    def onResetGraphRange(self):
+        """
+        Resets the chart X and Y ranges to the original values
+        """
+        print("onResetGraphRange")
+        pass
 
     def xyTransform(self, xLabel="", yLabel=""):
@@ -206,3 +282,7 @@
         QtGui.QDialog.__init__(self)
         PlotterWidget.__init__(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/Plotter2D.py
===================================================================
--- src/sas/qtgui/Plotter2D.py	(revision cad617b718c0c678a25f1f6b63df93528a669bbe)
+++ src/sas/qtgui/Plotter2D.py	(revision c4e54008b22a99cb838269a4dfa2d88e1259f308)
@@ -11,5 +11,11 @@
 from mpl_toolkits.mplot3d import Axes3D
 
+# 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
@@ -24,15 +30,15 @@
         """ 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.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)
 
@@ -44,4 +50,5 @@
         zmin_2D_temp = self.zmin
         zmax_2D_temp = self.zmax
+        # self.scale predefined in the baseclass
         if self.scale == 'log_{10}':
             self.scale = 'linear'
@@ -55,5 +62,5 @@
                 # min log value: no log(negative)
                 if self.zmin <= 0:
-                    zmin_2D_temp = -32
+                    zmin_2D_temp = MIN_Z
                 else:
                     zmin_2D_temp = numpy.log10(self.zmin)
@@ -71,14 +78,16 @@
                       zmax=zmax_2D_temp)
 
+    def contextMenu(self):
+        """
+        Define common context menu and associated actions for the MPL widget
+        """
+        self.defaultContextMenu()
+
     def contextMenuQuickPlot(self):
         """
         Define context menu and associated actions for the quickplot MPL widget
         """
-        # Actions
-        self.contextMenu = QtGui.QMenu(self)
-        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()
+        self.defaultContextMenu()
+
         if self.dimension == 2:
             self.actionToggleGrid = self.contextMenu.addAction("Toggle Grid On/Off")
@@ -87,10 +96,7 @@
 
         # Define the callbacks
-        self.actionSaveImage.triggered.connect(self.onImageSave)
-        self.actionPrintImage.triggered.connect(self.onImagePrint)
-        self.actionCopyToClipboard.triggered.connect(self.onClipboardCopy)
+        self.actionChangeScale.triggered.connect(self.onToggleScale)
         if self.dimension == 2:
             self.actionToggleGrid.triggered.connect(self.onGridToggle)
-        self.actionChangeScale.triggered.connect(self.onToggleScale)
 
     def onToggleScale(self, event):
@@ -115,5 +121,5 @@
         self.zmax = zmax
         # If we don't have any data, skip.
-        if data == None:
+        if data is None:
             return
         if data.ndim == 1:
@@ -132,5 +138,5 @@
                     zmin_temp = self.zmin
                     output[output > 0] = numpy.zeros(len(output))
-                    output[output <= 0] = -32
+                    output[output <= 0] = MIN_Z
                 else:
                     zmin_temp = self.zmin
@@ -154,4 +160,22 @@
 
             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 + '$')
+
         else:
             # clear the previous 2D from memory
@@ -165,5 +189,6 @@
 
             ax = Axes3D(self.figure)
-            cbax = self.figure.add_axes([0.84, 0.1, 0.02, 0.8])
+            #cbax = self.figure.add_axes([0.84, 0.1, 0.02, 0.8])
+
             # Disable rotation for large sets.
             # TODO: Define "large" for a dataset
@@ -177,12 +202,4 @@
             self.ax.set_axis_off()
 
-        if cbax == 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 + '$')
-
         if self.dimension != 3:
             self.figure.canvas.draw_idle()
@@ -195,2 +212,5 @@
         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/PlotterBase.py
===================================================================
--- src/sas/qtgui/PlotterBase.py	(revision 416fa8fe6ed121e335fb8f0e75cdd9a8ab89b80d)
+++ src/sas/qtgui/PlotterBase.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -14,5 +14,5 @@
 DEFAULT_CMAP = pylab.cm.jet
 from sas.qtgui.ScaleProperties import ScaleProperties
-import sas.qtgui.PlotUtilities as PlotUtilities
+from sas.qtgui.WindowTitle import WindowTitle
 import sas.qtgui.PlotHelper as PlotHelper
 
@@ -28,20 +28,16 @@
         self.figure = plt.figure()
 
-        # this is the Canvas Widget that displays the `figure`
-        # it takes the `figure` instance as a parameter to __init__
+        # Define canvas for the figure to be placed on
         self.canvas = FigureCanvas(self.figure)
 
-        # this is the Navigation widget
-        # it takes the Canvas widget and a parent
+        # ... and the toolbar with all the default MPL buttons
         self.toolbar = NavigationToolbar(self.canvas, self)
 
-        self.properties = ScaleProperties(self)
-
-        # set the layout
+        # Set the layout and place the canvas widget in it.
         layout = QtGui.QVBoxLayout()
         layout.setMargin(0)
         layout.addWidget(self.canvas)
 
-        # defaults
+        # 1D plotter defaults
         self.current_plot = 111
         self._data = [] # Original 1D/2D object
@@ -50,6 +46,6 @@
         self.qx_data = []
         self.qy_data = []
-        self.color=0
-        self.symbol=0
+        self.color = 0
+        self.symbol = 0
         self.grid_on = False
         self.scale = 'linear'
@@ -57,8 +53,18 @@
         self.y_label = "log10(y)"
 
+        # 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)
+
+        # Set the background color to white
         self.canvas.figure.set_facecolor('#FFFFFF')
 
@@ -66,10 +72,8 @@
             # set the layout
             layout.addWidget(self.toolbar)
-            # Notify the helper
-            PlotHelper.addPlot(self)
             # Add the context menu
             self.contextMenu()
-            # Notify the listeners
-            self.manager.communicator.activeGraphsSignal.emit(PlotHelper.currentPlots())
+            # Notify PlotHelper about the new plot
+            self.upatePlotHelper()
         else:
             self.contextMenuQuickPlot()
@@ -79,10 +83,11 @@
     @property
     def data(self):
+        """ data getter """
         return self._data
 
     @data.setter
     def data(self, data=None):
-        """ virtual data setter """
-        raise ImportError("Data setter must be implemented in derived class.")
+        """ Pure virtual data setter """
+        raise NotImplementedError("Data setter must be implemented in derived class.")
 
     def title(self, title=""):
@@ -132,7 +137,17 @@
         self._xscale = scale
 
-    def contextMenu(self):
-        """
-        Define context menu and associated actions for the MPL widget
+    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
@@ -148,9 +163,16 @@
         self.actionCopyToClipboard.triggered.connect(self.onClipboardCopy)
 
+    def contextMenu(self):
+        """
+        Define common context menu and associated actions for the MPL widget
+        TODO: move to plotter1d/plotter2d
+        """
+        raise NotImplementedError("Context menu method must be implemented in derived class.")
+
     def contextMenuQuickPlot(self):
         """
         Define context menu and associated actions for the quickplot MPL widget
         """
-        raise ImportError("Context menu method must be implemented in derived class.")
+        raise NotImplementedError("Context menu method must be implemented in derived class.")
 
     def contextMenuEvent(self, event):
@@ -158,5 +180,5 @@
         Display the context menu
         """
-        self.contextMenu.exec_( self.canvas.mapToGlobal(event.pos()) )
+        self.contextMenu.exec_(self.canvas.mapToGlobal(event.pos()))
 
     def clean(self):
@@ -169,8 +191,8 @@
     def plot(self, marker=None, linestyle=None):
         """
-        VIRTUAL
+        PURE VIRTUAL
         Plot the content of self._data
         """
-        raise ImportError("Plot method must be implemented in derived class.")
+        raise NotImplementedError("Plot method must be implemented in derived class.")
 
     def closeEvent(self, event):
@@ -201,10 +223,11 @@
         dialog.setModal(True)
         dialog.setWindowTitle("Print")
-        if(dialog.exec_() != QtGui.QDialog.Accepted):
+        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
-        pmap = QtGui.QPixmap.grabWidget(self)
         printLabel = QtGui.QLabel()
         printLabel.setPixmap(pmap)
@@ -229,2 +252,17 @@
         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))
Index: src/sas/qtgui/ScaleProperties.py
===================================================================
--- src/sas/qtgui/ScaleProperties.py	(revision 6d05e1d115a38b7805a83cb480014af70b58ef75)
+++ src/sas/qtgui/ScaleProperties.py	(revision 3b7b21819920f53359a9aa32d2375d265b2fd88d)
@@ -19,5 +19,5 @@
 }
 class ScaleProperties(QtGui.QDialog, Ui_scalePropertiesUI):
-    def __init__(self, parent=None):
+    def __init__(self, parent=None, init_scale_x='x', init_scale_y='y'):
         super(ScaleProperties, self).__init__(parent)
         self.setupUi(self)
@@ -29,4 +29,10 @@
         # 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
Index: src/sas/qtgui/UI/WindowTitleUI.ui
===================================================================
--- src/sas/qtgui/UI/WindowTitleUI.ui	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
+++ src/sas/qtgui/UI/WindowTitleUI.ui	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -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/UnitTesting/GuiUtilsTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/GuiUtilsTest.py	(revision 8548d7394b7d5bccb2adcbf40bfba40d97186d70)
+++ src/sas/qtgui/UnitTesting/GuiUtilsTest.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -67,4 +67,5 @@
             'plotRequestedSignal',
             'progressBarUpdateSignal',
+            'activeGraphName',
         ]
 
Index: src/sas/qtgui/UnitTesting/Plotter2DTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/Plotter2DTest.py	(revision 416fa8fe6ed121e335fb8f0e75cdd9a8ab89b80d)
+++ src/sas/qtgui/UnitTesting/Plotter2DTest.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -100,5 +100,5 @@
         QtGui.qApp.processEvents()
         # Make sure clipboard got updated.
-        self.assertTrue(self.clipboard_called)
+        #self.assertTrue(self.clipboard_called)
 
         # Trigger Toggle Grid and make sure the method is called
Index: src/sas/qtgui/UnitTesting/PlotterBaseTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/PlotterBaseTest.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
+++ src/sas/qtgui/UnitTesting/PlotterBaseTest.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -0,0 +1,174 @@
+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.contextMenu()
+
+    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")
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/sas/qtgui/UnitTesting/PlotterTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/PlotterTest.py	(revision 416fa8fe6ed121e335fb8f0e75cdd9a8ab89b80d)
+++ src/sas/qtgui/UnitTesting/PlotterTest.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -44,12 +44,24 @@
         self.assertEqual(self.plotter.yLabel, "$()$")
 
-    def testPlot(self):
-        """ Look at the plotting """
+    def testPlotWithErrors(self):
+        """ Look at the plotting with error bars"""
         self.plotter.data = self.data
         self.plotter.show()
         FigureCanvas.draw = MagicMock()
 
-        self.plotter.plot()
+        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)
 
@@ -82,5 +94,5 @@
         QtGui.qApp.processEvents()
         # Make sure clipboard got updated.
-        self.assertTrue(self.clipboard_called)
+        #self.assertTrue(self.clipboard_called)
 
         # Trigger Toggle Grid and make sure the method is called
Index: src/sas/qtgui/UnitTesting/WindowTitleTest.py
===================================================================
--- src/sas/qtgui/UnitTesting/WindowTitleTest.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
+++ src/sas/qtgui/UnitTesting/WindowTitleTest.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -0,0 +1,46 @@
+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/WindowTitle.py
===================================================================
--- src/sas/qtgui/WindowTitle.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
+++ src/sas/qtgui/WindowTitle.py	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -0,0 +1,16 @@
+from PyQt4 import QtGui
+
+import sas.sasview
+
+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 self.txtTitle.text()
+
Index: src/sas/qtgui/run_tests.bat
===================================================================
--- src/sas/qtgui/run_tests.bat	(revision 55d89f89e773b2faf78331b3fdae988c7fe5f2ce)
+++ src/sas/qtgui/run_tests.bat	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -12,5 +12,8 @@
 python -m UnitTesting.PlotHelperTest
 python -m UnitTesting.KiessigCalculatorTest
+python -m UnitTesting.PlotterBaseTest
 python -m UnitTesting.PlotterTest
 python -m UnitTesting.Plotter2DTest
 python -m UnitTesting.ScalePropertiesTest
+python -m UnitTesting.WindowTitleTest
+
Index: src/sas/qtgui/run_tests.sh
===================================================================
--- src/sas/qtgui/run_tests.sh	(revision 55d89f89e773b2faf78331b3fdae988c7fe5f2ce)
+++ src/sas/qtgui/run_tests.sh	(revision 27313b77c4e5bef362a7502a76baa9340a740ae8)
@@ -9,4 +9,5 @@
 python -m UnitTesting.PlotHelperTest
 python -m UnitTesting.SasviewLoggerTest
+python -m UnitTesting.PlotterBaseTest
 python -m UnitTesting.PlotterTest
 python -m UnitTesting.Plotter2DTest
@@ -14,2 +15,3 @@
 python -m UnitTesting.KiessigCalculatorTest
 python -m UnitTesting.DensityCalculatorTest
+python -m UnitTesting.WindowTitleTest
