From 6f60bcf07675f74d2fb5097e4a9e73b4de454c3c Mon Sep 17 00:00:00 2001
From: Samuel Jackson <samueljackson@outlook.com>
Date: Mon, 5 Dec 2016 15:20:52 +0000
Subject: [PATCH] Refs #17969 Make UI more user friendly

This commit adds:
 - Icons and info for different types of windows/workspaces
 - A progress bar for workspace saving
 - A better, more flexible window layout
---
 MantidPlot/CMakeLists.txt                     |   1 +
 MantidPlot/src/ApplicationWindow.cpp          |   4 +-
 MantidPlot/src/Graph3D.cpp                    |   5 -
 MantidPlot/src/Graph3D.h                      |   1 -
 MantidPlot/src/Mantid/MantidMatrix.cpp        |   5 -
 MantidPlot/src/Mantid/MantidMatrix.h          |   2 -
 MantidPlot/src/Matrix.cpp                     |   5 -
 MantidPlot/src/Matrix.h                       |   1 -
 MantidPlot/src/MdiSubWindow.cpp               |   9 +-
 MantidPlot/src/MdiSubWindow.h                 |   3 +
 MantidPlot/src/MultiLayer.cpp                 |   5 -
 MantidPlot/src/MultiLayer.h                   |   1 -
 MantidPlot/src/Note.cpp                       |   5 -
 MantidPlot/src/Note.h                         |   1 -
 MantidPlot/src/ProjectSave.ui                 | 285 ++++++++++++------
 MantidPlot/src/ProjectSaveView.cpp            |  99 ++++--
 MantidPlot/src/ProjectSaveView.h              |  14 +-
 MantidPlot/src/ProjectSerialiser.cpp          |  10 +
 MantidPlot/src/ProjectSerialiser.h            |  11 +-
 MantidPlot/src/Table.cpp                      |   5 -
 MantidPlot/src/Table.h                        |   2 -
 MantidQt/API/inc/MantidQtAPI/WindowIcons.h    |   6 +-
 MantidQt/API/src/WindowIcons.cpp              |  27 +-
 .../MantidQtSliceViewer/SliceViewerWindow.h   |   2 +
 .../SliceViewer/src/SliceViewerWindow.cpp     |   7 +-
 .../inc/MantidQtSpectrumViewer/SpectrumView.h |   2 +
 MantidQt/SpectrumViewer/src/SpectrumView.cpp  |   5 +
 27 files changed, 342 insertions(+), 181 deletions(-)

diff --git a/MantidPlot/CMakeLists.txt b/MantidPlot/CMakeLists.txt
index edf5e35d3a7..a1d78761159 100644
--- a/MantidPlot/CMakeLists.txt
+++ b/MantidPlot/CMakeLists.txt
@@ -537,6 +537,7 @@ set ( QTIPLOT_MOC_FILES src/ApplicationWindow.h
                         src/PolynomFitDialog.h
                         src/PolynomialFit.h
                         src/ProjectSaveView.h
+                        src/ProjectSerialiser.h
                         src/PythonScript.h
                         src/PythonScripting.h
                         src/QwtPieCurve.h
diff --git a/MantidPlot/src/ApplicationWindow.cpp b/MantidPlot/src/ApplicationWindow.cpp
index a62a8c74e48..3b5349ffa23 100644
--- a/MantidPlot/src/ApplicationWindow.cpp
+++ b/MantidPlot/src/ApplicationWindow.cpp
@@ -6050,8 +6050,8 @@ void ApplicationWindow::prepareSaveProject()
       windows.push_back(win);
   }
 
-  ProjectSerialiser serialiser(this, currentFolder());
-  m_projectSaveView = new MantidQt::MantidWidgets::ProjectSaveView(projectname, serialiser, windows, this);
+  auto serialiser = new ProjectSerialiser(this, currentFolder());
+  m_projectSaveView = new MantidQt::MantidWidgets::ProjectSaveView(projectname, *serialiser, windows, this);
   connect(m_projectSaveView, SIGNAL(projectSaved()), this, SLOT(postSaveProject()));
   m_projectSaveView->show();
 }
diff --git a/MantidPlot/src/Graph3D.cpp b/MantidPlot/src/Graph3D.cpp
index 024809c5364..91405067f51 100644
--- a/MantidPlot/src/Graph3D.cpp
+++ b/MantidPlot/src/Graph3D.cpp
@@ -3103,11 +3103,6 @@ std::string Graph3D::saveToProject(ApplicationWindow *app) {
   return tsv.outputLines();
 }
 
-std::string Graph3D::getWindowName()
-{
-  return name().toStdString();
-}
-
 std::vector<std::string> Graph3D::getWorkspaceNames()
 {
     // wsName is actually "Workspace workspacename", so we chop off
diff --git a/MantidPlot/src/Graph3D.h b/MantidPlot/src/Graph3D.h
index 34acc7f16bd..51e9b5733c1 100644
--- a/MantidPlot/src/Graph3D.h
+++ b/MantidPlot/src/Graph3D.h
@@ -303,7 +303,6 @@ public slots:
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
   std::string saveToProject(ApplicationWindow *app) override;
-  std::string getWindowName() override;
   std::vector<std::string> getWorkspaceNames() override;
 
   void zoomChanged(double);
diff --git a/MantidPlot/src/Mantid/MantidMatrix.cpp b/MantidPlot/src/Mantid/MantidMatrix.cpp
index 41a95160f4f..88284434e0a 100644
--- a/MantidPlot/src/Mantid/MantidMatrix.cpp
+++ b/MantidPlot/src/Mantid/MantidMatrix.cpp
@@ -1244,11 +1244,6 @@ std::vector<std::string> MantidMatrix::getWorkspaceNames()
   return { m_strName };
 }
 
-std::string MantidMatrix::getWindowName()
-{
-  return objectName().toStdString();
-}
-
 /**
  * Creates a MantidMatrixTabExtension of a specified type
  * @param type: the type of the tab extension
diff --git a/MantidPlot/src/Mantid/MantidMatrix.h b/MantidPlot/src/Mantid/MantidMatrix.h
index ed1f27c23ce..a3621023dd0 100644
--- a/MantidPlot/src/Mantid/MantidMatrix.h
+++ b/MantidPlot/src/Mantid/MantidMatrix.h
@@ -159,8 +159,6 @@ public:
   std::string saveToProject(ApplicationWindow *app) override;
   /// Returns a list of workspace names that are used by this window
   std::vector<std::string> getWorkspaceNames() override;
-  /// Returns the user friendly name of the window
-  std::string getWindowName() override;
 
   /// returns the workspace name
   const std::string &getWorkspaceName();
diff --git a/MantidPlot/src/Matrix.cpp b/MantidPlot/src/Matrix.cpp
index e6a6c2e5cc4..7850e05ae5c 100644
--- a/MantidPlot/src/Matrix.cpp
+++ b/MantidPlot/src/Matrix.cpp
@@ -1705,11 +1705,6 @@ std::string Matrix::saveToProject(ApplicationWindow *app) {
   return tsv.outputLines();
 }
 
-std::string Matrix::getWindowName()
-{
-  return objectName().toStdString();
-}
-
 std::vector<std::string> Matrix::getWorkspaceNames()
 {
   return {};
diff --git a/MantidPlot/src/Matrix.h b/MantidPlot/src/Matrix.h
index e237d6b44f5..a08bab1733d 100644
--- a/MantidPlot/src/Matrix.h
+++ b/MantidPlot/src/Matrix.h
@@ -262,7 +262,6 @@ public slots:
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
   std::string saveToProject(ApplicationWindow *app) override;
-  std::string getWindowName() override;
   std::vector<std::string> getWorkspaceNames() override;
 
   // selection operations
diff --git a/MantidPlot/src/MdiSubWindow.cpp b/MantidPlot/src/MdiSubWindow.cpp
index e77677560a8..15fefcd18f3 100644
--- a/MantidPlot/src/MdiSubWindow.cpp
+++ b/MantidPlot/src/MdiSubWindow.cpp
@@ -91,6 +91,7 @@ void MdiSubWindow::init(QWidget *parent, const QString &label,
             SLOT(changeToFloating(MdiSubWindow *)));
   }
 }
+
 void MdiSubWindow::updateCaption() {
   switch (d_caption_policy) {
   case Name:
@@ -144,9 +145,15 @@ std::vector<std::string> MdiSubWindow::getWorkspaceNames()
 
 std::string MdiSubWindow::getWindowName()
 {
-  return "";
+  return objectName().toStdString();
 }
 
+std::string MdiSubWindow::getWindowType()
+{
+  return metaObject()->className();
+}
+
+
 void MdiSubWindow::resizeEvent(QResizeEvent *e) {
   emit resizedWindow(this);
   MdiSubWindowParent_t::resizeEvent(e);
diff --git a/MantidPlot/src/MdiSubWindow.h b/MantidPlot/src/MdiSubWindow.h
index 7812bd22979..8850e82f31d 100644
--- a/MantidPlot/src/MdiSubWindow.h
+++ b/MantidPlot/src/MdiSubWindow.h
@@ -145,6 +145,7 @@ public:
   ApplicationWindow *applicationWindow() { return d_app; }
   /// Get the pointer to Folder
   Folder *folder() { return d_folder; }
+
 public slots:
 
   //! Return the window label
@@ -286,6 +287,8 @@ public: // non-slot methods
   std::vector<std::string> getWorkspaceNames() override;
   /// Returns the user friendly name of the window
   std::string getWindowName() override;
+  /// Get the window type as a string
+  std::string getWindowType() override;
 
 signals:
   //! Emitted when the window was closed
diff --git a/MantidPlot/src/MultiLayer.cpp b/MantidPlot/src/MultiLayer.cpp
index 23ea2104b1b..42cf1e6dfbc 100644
--- a/MantidPlot/src/MultiLayer.cpp
+++ b/MantidPlot/src/MultiLayer.cpp
@@ -1869,11 +1869,6 @@ std::string MultiLayer::saveToProject(ApplicationWindow *app) {
   return tsv.outputLines();
 }
 
-std::string MultiLayer::getWindowName()
-{
-  return objectName().toStdString();
-}
-
 std::vector<std::string> MultiLayer::getWorkspaceNames()
 {
   std::vector<std::string> names;
diff --git a/MantidPlot/src/MultiLayer.h b/MantidPlot/src/MultiLayer.h
index 78e268cfa3a..6c702c17c9a 100644
--- a/MantidPlot/src/MultiLayer.h
+++ b/MantidPlot/src/MultiLayer.h
@@ -113,7 +113,6 @@ public:
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
   std::string saveToProject(ApplicationWindow *app) override;
-  std::string getWindowName() override;
   std::vector<std::string> getWorkspaceNames() override;
 
   void setCommonAxisScales();
diff --git a/MantidPlot/src/Note.cpp b/MantidPlot/src/Note.cpp
index 8a9d878b54b..b90af286a6b 100644
--- a/MantidPlot/src/Note.cpp
+++ b/MantidPlot/src/Note.cpp
@@ -196,11 +196,6 @@ std::string Note::saveToProject(ApplicationWindow *app) {
   return tsv.outputLines();
 }
 
-std::string Note::getWindowName()
-{
-  return name().toStdString();
-}
-
 std::vector<std::string> Note::getWorkspaceNames()
 {
   return {};
diff --git a/MantidPlot/src/Note.h b/MantidPlot/src/Note.h
index ddcf4184d18..57e822dde0a 100644
--- a/MantidPlot/src/Note.h
+++ b/MantidPlot/src/Note.h
@@ -53,7 +53,6 @@ public:
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
   std::string saveToProject(ApplicationWindow *app) override;
-  std::string getWindowName() override;
   std::vector<std::string> getWorkspaceNames() override;
 
   void setName(const QString &name);
diff --git a/MantidPlot/src/ProjectSave.ui b/MantidPlot/src/ProjectSave.ui
index c161b796ace..b76c4458be3 100644
--- a/MantidPlot/src/ProjectSave.ui
+++ b/MantidPlot/src/ProjectSave.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1195</width>
-    <height>746</height>
+    <width>1062</width>
+    <height>602</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -16,113 +16,198 @@
   <property name="modal">
    <bool>true</bool>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
+  <layout class="QVBoxLayout" name="verticalLayout_8">
    <item>
     <layout class="QGridLayout" name="gridLayout">
-     <item row="1" column="3">
-      <widget class="QPushButton" name="btnBrowseFilePath">
-       <property name="text">
-        <string>Browse</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="0">
-      <widget class="QLabel" name="label_4">
-       <property name="text">
-        <string>Project Location</string>
+     <property name="sizeConstraint">
+      <enum>QLayout::SetDefaultConstraint</enum>
+     </property>
+     <item row="1" column="0" colspan="3">
+      <widget class="QSplitter" name="splitter">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
        </property>
+       <widget class="QWidget" name="verticalLayoutWidget_2">
+        <layout class="QVBoxLayout" name="verticalLayout_3">
+         <item>
+          <widget class="QLabel" name="label">
+           <property name="text">
+            <string>Workspaces</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QTreeWidget" name="workspaceList">
+           <column>
+            <property name="text">
+             <string>Name</string>
+            </property>
+           </column>
+           <column>
+            <property name="text">
+             <string>Type</string>
+            </property>
+           </column>
+           <column>
+            <property name="text">
+             <string>Size</string>
+            </property>
+           </column>
+           <item>
+            <property name="text">
+             <string>ws1</string>
+            </property>
+            <property name="checkState">
+             <enum>Checked</enum>
+            </property>
+            <property name="text">
+             <string>Matrix</string>
+            </property>
+            <property name="text">
+             <string>10mb</string>
+            </property>
+           </item>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="verticalLayoutWidget">
+        <layout class="QVBoxLayout" name="verticalLayout">
+         <item>
+          <widget class="QSplitter" name="splitter_2">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <widget class="QWidget" name="verticalLayoutWidget_3">
+            <layout class="QVBoxLayout" name="verticalLayout_5">
+             <item>
+              <widget class="QLabel" name="label_2">
+               <property name="text">
+                <string>Included Windows</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QTreeWidget" name="includedWindows">
+               <column>
+                <property name="text">
+                 <string>Name</string>
+                </property>
+               </column>
+               <column>
+                <property name="text">
+                 <string>Type</string>
+                </property>
+               </column>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+           <widget class="QWidget" name="verticalLayoutWidget_4">
+            <layout class="QVBoxLayout" name="verticalLayout_6">
+             <item>
+              <widget class="QLabel" name="label_3">
+               <property name="text">
+                <string>Excluded Windows</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QTreeWidget" name="excludedWindows">
+               <column>
+                <property name="text">
+                 <string>Name</string>
+                </property>
+               </column>
+               <column>
+                <property name="text">
+                 <string>Type</string>
+                </property>
+               </column>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </widget>
+         </item>
+        </layout>
+       </widget>
       </widget>
      </item>
-     <item row="2" column="0">
-      <widget class="QLabel" name="label">
-       <property name="text">
-        <string>Workspaces</string>
+     <item row="2" column="0" colspan="3">
+      <layout class="QHBoxLayout" name="horizontalLayout_2">
+       <property name="sizeConstraint">
+        <enum>QLayout::SetFixedSize</enum>
        </property>
-      </widget>
-     </item>
-     <item row="3" column="0" rowspan="3">
-      <widget class="QTreeWidget" name="workspaceList">
-       <column>
-        <property name="text">
-         <string>Name</string>
-        </property>
-       </column>
-       <column>
-        <property name="text">
-         <string>Size</string>
-        </property>
-       </column>
        <item>
-        <property name="text">
-         <string>ws1</string>
-        </property>
-        <property name="checkState">
-         <enum>Checked</enum>
-        </property>
-        <property name="text">
-         <string>10mb</string>
-        </property>
+        <widget class="QProgressBar" name="saveProgressBar">
+         <property name="value">
+          <number>24</number>
+         </property>
+        </widget>
        </item>
-      </widget>
-     </item>
-     <item row="1" column="0" colspan="3">
-      <widget class="QLineEdit" name="projectPath"/>
-     </item>
-     <item row="5" column="1" colspan="3">
-      <widget class="QTreeWidget" name="excludedWindows">
-       <column>
-        <property name="text">
-         <string notr="true">1</string>
-        </property>
-       </column>
-      </widget>
-     </item>
-     <item row="3" column="1" colspan="3">
-      <widget class="QTreeWidget" name="includedWindows">
-       <column>
-        <property name="text">
-         <string>Name</string>
-        </property>
-       </column>
-       <column>
-        <property name="text">
-         <string>Type</string>
-        </property>
-       </column>
-       <column>
-        <property name="text">
-         <string>Size</string>
-        </property>
-       </column>
-      </widget>
-     </item>
-     <item row="4" column="1">
-      <widget class="QLabel" name="label_3">
-       <property name="text">
-        <string>Excluded Windows</string>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="1">
-      <widget class="QLabel" name="label_2">
-       <property name="text">
-        <string>Included Windows</string>
-       </property>
-      </widget>
-     </item>
-     <item row="6" column="3">
-      <widget class="QPushButton" name="btnSave">
-       <property name="text">
-        <string>Save</string>
-       </property>
-      </widget>
+       <item>
+        <spacer name="horizontalSpacer">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>40</width>
+           <height>0</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QPushButton" name="btnCancel">
+         <property name="text">
+          <string>Cancel</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="btnSave">
+         <property name="text">
+          <string>Save</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
      </item>
-     <item row="6" column="2">
-      <widget class="QPushButton" name="btnCancel">
-       <property name="text">
-        <string>Cancel</string>
-       </property>
-      </widget>
+     <item row="0" column="0" colspan="3">
+      <layout class="QVBoxLayout" name="verticalLayout_7">
+       <item>
+        <widget class="QLabel" name="label_4">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>Project Location</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <property name="sizeConstraint">
+          <enum>QLayout::SetFixedSize</enum>
+         </property>
+         <item>
+          <widget class="QLineEdit" name="projectPath"/>
+         </item>
+         <item>
+          <widget class="QPushButton" name="btnBrowseFilePath">
+           <property name="text">
+            <string>Browse</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+      </layout>
      </item>
     </layout>
    </item>
diff --git a/MantidPlot/src/ProjectSaveView.cpp b/MantidPlot/src/ProjectSaveView.cpp
index b67f0ec3b95..27c92675b04 100644
--- a/MantidPlot/src/ProjectSaveView.cpp
+++ b/MantidPlot/src/ProjectSaveView.cpp
@@ -1,6 +1,8 @@
 #include "MantidQtAPI/IProjectSerialisable.h"
 #include "MantidQtMantidWidgets/ProjectSavePresenter.h"
 #include "MantidQtAPI/FileDialogHandler.h"
+#include "MantidQtAPI/WindowIcons.h"
+
 #include "ProjectSaveView.h"
 
 using namespace MantidQt::API;
@@ -21,14 +23,9 @@ ProjectSaveView::ProjectSaveView(const QString& projectName,
   if(!checkIfNewProject(projectName))
     m_ui.projectPath->setText(projectName);
 
-  //Connect signal to listen for when workspaces are changed (checked/unchecked)
-  connect(m_ui.workspaceList,
-          SIGNAL(itemChanged(QTreeWidgetItem *, int)), this,
-          SLOT(workspaceItemChanged(QTreeWidgetItem*, int)));
+  m_ui.saveProgressBar->setValue(0);
 
-  connect(m_ui.btnBrowseFilePath, SIGNAL(clicked(bool)), this, SLOT(findFilePath()));
-  connect(m_ui.btnSave, SIGNAL(clicked(bool)), this, SLOT(save(bool)));
-  connect(m_ui.btnCancel, SIGNAL(clicked(bool)), this, SLOT(close()));
+  connectSignals();
 }
 
 // IProjectSaveView interface implementations
@@ -59,28 +56,34 @@ void ProjectSaveView::setProjectPath(const QString &path)
  m_ui.projectPath->setText(path);
 }
 
-void ProjectSaveView::updateWorkspacesList(const std::vector<std::string> &workspaces)
+void ProjectSaveView::updateWorkspacesList(const std::vector<WorkspaceInfo> &workspaces)
 {
   m_ui.workspaceList->clear();
-  for (auto name : workspaces) {
-    addWorkspaceItem(name);
+  for (auto info : workspaces) {
+    addWorkspaceItem(info);
   }
+
+  resizeWidgetColumns(m_ui.workspaceList);
 }
 
-void ProjectSaveView::updateIncludedWindowsList(const std::vector<std::string> &windows)
+void ProjectSaveView::updateIncludedWindowsList(const std::vector<WindowInfo> &windows)
 {
   m_ui.includedWindows->clear();
-  for (auto name : windows) {
-    addWindowItem(m_ui.includedWindows, name);
+  for (auto info : windows) {
+    addWindowItem(m_ui.includedWindows, info);
   }
+
+  resizeWidgetColumns(m_ui.includedWindows);
 }
 
-void ProjectSaveView::updateExcludedWindowsList(const std::vector<std::string> &windows)
+void ProjectSaveView::updateExcludedWindowsList(const std::vector<WindowInfo> &windows)
 {
   m_ui.excludedWindows->clear();
-  for (auto name : windows) {
-    addWindowItem(m_ui.excludedWindows, name);
+  for (auto info: windows) {
+    addWindowItem(m_ui.excludedWindows, info);
   }
+
+  resizeWidgetColumns(m_ui.excludedWindows);
 }
 
 void ProjectSaveView::removeFromIncludedWindowsList(const std::vector<std::string> &windows)
@@ -126,6 +129,13 @@ std::vector<std::string> ProjectSaveView::getItemsWithCheckState(const Qt::Check
 void ProjectSaveView::save(bool checked)
 {
   UNUSED_ARG(checked);
+
+  if(m_ui.projectPath->text().isEmpty()) {
+    QMessageBox::warning(this, "Project Save",
+                         "Please choose a valid file path", QMessageBox::Ok);
+    return;
+  }
+
   m_presenter->notify(ProjectSavePresenter::Notification::PrepareProjectFolder);
   auto wsNames = getCheckedWorkspaceNames();
   auto windowNames = getIncludedWindowNames();
@@ -133,6 +143,8 @@ void ProjectSaveView::save(bool checked)
   auto compress = filePath.endsWith(".gz");
 
   m_serialiser.save(filePath, wsNames, windowNames, compress);
+  emit projectSaved();
+
   close();
 }
 
@@ -173,18 +185,30 @@ void ProjectSaveView::removeItem(QTreeWidget *widget, const std::string &name)
   }
 }
 
-void ProjectSaveView::addWindowItem(QTreeWidget *widget, const std::string &name)
+void ProjectSaveView::addWindowItem(QTreeWidget *widget, const WindowInfo &info)
 {
-  auto it = new QTreeWidgetItem(widget);
-  it->setText(0, QString::fromStdString(name));
-  widget->addTopLevelItem(it);
+  QStringList lst;
+  WindowIcons icons;
+  lst << QString::fromStdString(info.name);
+  lst << QString::fromStdString(info.type);
+
+  auto item = new QTreeWidgetItem(lst);
+  if(!info.icon_id.empty())
+    item->setIcon(0, icons.getIcon(info.type));
+  widget->addTopLevelItem(item);
 }
 
-void ProjectSaveView::addWorkspaceItem(const std::string &name)
+void ProjectSaveView::addWorkspaceItem(const WorkspaceInfo &info)
 {
-  QStringList lst(QString::fromStdString(name));
-  lst.append("0");
-  QTreeWidgetItem *item = new QTreeWidgetItem(lst);
+  QStringList lst;
+  lst << QString::fromStdString(info.name);
+  lst << QString::fromStdString(info.type);
+  lst << QString::fromStdString(info.size);
+  lst << QString::number(info.numWindows);
+
+  auto item = new QTreeWidgetItem(lst);
+  if(!info.icon_id.empty())
+    item->setIcon(0, getQPixmap(info.icon_id));
   item->setCheckState(0, Qt::CheckState::Checked);
   m_ui.workspaceList->addTopLevelItem(item);
 }
@@ -195,7 +219,32 @@ bool ProjectSaveView::checkIfNewProject(const QString &projectName) const
       projectName.endsWith(".opj", Qt::CaseInsensitive) ||
       projectName.endsWith(".ogm", Qt::CaseInsensitive) ||
       projectName.endsWith(".ogw", Qt::CaseInsensitive) ||
-      projectName.endsWith(".ogg", Qt::CaseInsensitive));
+           projectName.endsWith(".ogg", Qt::CaseInsensitive));
+}
+
+void ProjectSaveView::resizeWidgetColumns(QTreeWidget *widget)
+{
+  for (int i = 0; i < widget->topLevelItemCount(); ++i)
+    widget->resizeColumnToContents(i);
+}
+
+void ProjectSaveView::connectSignals()
+{
+  //Connect signal to listen for when workspaces are changed (checked/unchecked)
+  connect(m_ui.workspaceList,
+          SIGNAL(itemChanged(QTreeWidgetItem *, int)), this,
+          SLOT(workspaceItemChanged(QTreeWidgetItem*, int)));
+
+  connect(m_ui.btnBrowseFilePath, SIGNAL(clicked(bool)), this, SLOT(findFilePath()));
+  connect(m_ui.btnSave, SIGNAL(clicked(bool)), this, SLOT(save(bool)));
+  connect(m_ui.btnCancel, SIGNAL(clicked(bool)), this, SLOT(close()));
+
+  connect(&m_serialiser, SIGNAL(setProgressBarRange(int, int)),
+          m_ui.saveProgressBar, SLOT(setRange(int, int)));
+  connect(&m_serialiser, SIGNAL(setProgressBarValue(int)),
+          m_ui.saveProgressBar, SLOT(setValue(int)));
+  connect(&m_serialiser, SIGNAL(setProgressBarText(QString)),
+          m_ui.saveProgressBar, SLOT(setText(QString)));
 }
 
 }
diff --git a/MantidPlot/src/ProjectSaveView.h b/MantidPlot/src/ProjectSaveView.h
index 522039bd010..925eff6f07f 100644
--- a/MantidPlot/src/ProjectSaveView.h
+++ b/MantidPlot/src/ProjectSaveView.h
@@ -58,9 +58,9 @@ public:
   QString getProjectPath() override;
   void setProjectPath(const QString& path) override;
 
-  void updateWorkspacesList(const std::vector<std::string>& workspaces) override;
-  void updateIncludedWindowsList(const std::vector<std::string>& windows) override;
-  void updateExcludedWindowsList(const std::vector<std::string>& windows) override;
+  void updateWorkspacesList(const std::vector<WorkspaceInfo>& workspaces) override;
+  void updateIncludedWindowsList(const std::vector<WindowInfo>& windows) override;
+  void updateExcludedWindowsList(const std::vector<WindowInfo>& windows) override;
   void removeFromIncludedWindowsList(const std::vector<std::string>& windows) override;
   void removeFromExcludedWindowsList(const std::vector<std::string>& windows) override;
 
@@ -76,13 +76,15 @@ private:
     std::vector<std::string> getIncludedWindowNames() const;
     std::vector<std::string> getItemsWithCheckState(const Qt::CheckState state) const;
     void removeItem(QTreeWidget* widget, const std::string &name);
-    void addWindowItem(QTreeWidget* widget, const std::string &name);
-    void addWorkspaceItem(const std::string &name);
+    void addWindowItem(QTreeWidget* widget, const WindowInfo &info);
+    void addWorkspaceItem(const WorkspaceInfo &info);
     bool checkIfNewProject(const QString& projectName) const;
+    void resizeWidgetColumns(QTreeWidget* widget);
+    void connectSignals();
 
     std::vector<MantidQt::API::IProjectSerialisable*> m_serialisableWindows;
     std::unique_ptr<ProjectSavePresenter> m_presenter;
-    MantidQt::API::ProjectSerialiser  m_serialiser;
+    MantidQt::API::ProjectSerialiser&  m_serialiser;
     Ui::ProjectSave m_ui;
 };
 }
diff --git a/MantidPlot/src/ProjectSerialiser.cpp b/MantidPlot/src/ProjectSerialiser.cpp
index 6e9f2b28b01..f64fef9d207 100644
--- a/MantidPlot/src/ProjectSerialiser.cpp
+++ b/MantidPlot/src/ProjectSerialiser.cpp
@@ -46,6 +46,10 @@ void ProjectSerialiser::save(const QString &projectName,
   QFileInfo fileInfo(projectName);
   window->workingDir = fileInfo.absoluteDir().absolutePath();
 
+  // update any listening progress bars
+  emit setProgressBarRange(0, static_cast<int>(wsNames.size()));
+  emit setProgressBarValue(0);
+
   save(m_currentFolder, projectName, compress);
 }
 
@@ -425,6 +429,9 @@ QString ProjectSerialiser::saveWorkspaces() {
   wsNames = "<mantidworkspaces>\n";
   wsNames += "WorkspaceNames";
 
+  emit setProgressBarText(QString("Saving Workspaces"));
+
+  int count = 0;
   auto workspaceItems = AnalysisDataService::Instance().getObjectNames();
   for (auto &itemIter : workspaceItems) {
     QString wsName = QString::fromStdString(itemIter);
@@ -457,6 +464,9 @@ QString ProjectSerialiser::saveWorkspaces() {
       std::string fileName(workingDir + "//" + wsName.toStdString() + ".nxs");
       window->mantidUI->savedatainNexusFormat(fileName, wsName.toStdString());
     }
+
+    // update listening progress bars
+    emit setProgressBarValue(++count);
   }
   wsNames += "\n</mantidworkspaces>\n";
   return wsNames;
diff --git a/MantidPlot/src/ProjectSerialiser.h b/MantidPlot/src/ProjectSerialiser.h
index 37147315185..7161fb3a28c 100644
--- a/MantidPlot/src/ProjectSerialiser.h
+++ b/MantidPlot/src/ProjectSerialiser.h
@@ -49,7 +49,8 @@ class ApplicationWindow;
 namespace MantidQt {
 namespace API {
 
-class ProjectSerialiser {
+class ProjectSerialiser : public QObject {
+  Q_OBJECT
 public:
   /// Create a new serialiser with the current application window
   explicit ProjectSerialiser(ApplicationWindow *window);
@@ -66,6 +67,14 @@ public:
   /// Open the script window and load scripts from string
   void openScriptWindow(const QStringList &files);
 
+signals:
+  /// Set the curret progress of serialisation
+  void setProgressBarRange(int min, int max);
+  /// Set the forcasted range of things to do when saving
+  void setProgressBarValue(int value);
+  /// Set what is currently happening to listening progress bars
+  void setProgressBarText(QString text);
+
 private:
   // Instance Variables
 
diff --git a/MantidPlot/src/Table.cpp b/MantidPlot/src/Table.cpp
index 4a2d535b833..03422d1010e 100644
--- a/MantidPlot/src/Table.cpp
+++ b/MantidPlot/src/Table.cpp
@@ -3181,11 +3181,6 @@ std::vector<std::string> Table::getWorkspaceNames()
   return {};
 }
 
-std::string Table::getWindowName()
-{
-  return objectName().toStdString();
-}
-
 std::string Table::saveTableMetadata() {
   MantidQt::API::TSVSerialiser tsv;
   tsv.writeLine("header");
diff --git a/MantidPlot/src/Table.h b/MantidPlot/src/Table.h
index b85dc2676c6..86e5633340f 100644
--- a/MantidPlot/src/Table.h
+++ b/MantidPlot/src/Table.h
@@ -396,8 +396,6 @@ public slots:
                   const int fileVersion);
   /// Returns a list of workspace names that are used by this window
   std::vector<std::string> getWorkspaceNames() override;
-  /// Returns the user friendly name of the window
-  std::string getWindowName() override;
 
   void restore(const QStringList &lst) override;
 
diff --git a/MantidQt/API/inc/MantidQtAPI/WindowIcons.h b/MantidQt/API/inc/MantidQtAPI/WindowIcons.h
index 9117ec707d5..535fb43c0a5 100644
--- a/MantidQt/API/inc/MantidQtAPI/WindowIcons.h
+++ b/MantidQt/API/inc/MantidQtAPI/WindowIcons.h
@@ -3,7 +3,7 @@
 
 #include "DllOption.h"
 #include <QMap>
-#include <QPixmap>
+#include <QIcon>
 
 namespace MantidQt {
 namespace API {
@@ -16,13 +16,15 @@ public:
   WindowIcons();
 
   /// Returns an icon for the given ID
-  QPixmap getIcon(const std::string &windowID) const;
+  QIcon getIcon(const std::string &windowID) const;
   /// Returns an icon ID for the given window ID
   std::string getIconID(const std::string &windowID) const;
 
 private:
   /// Defines the mapping between ID & pixmap name
   void initInternalLookup();
+  /// Build a icon object from an image file
+  QIcon makeIconFromFile(const std::string &path) const;
 
   /// Internal map instance
   QMap<std::string, std::string> m_idToPixmapName;
diff --git a/MantidQt/API/src/WindowIcons.cpp b/MantidQt/API/src/WindowIcons.cpp
index 34bf11a9362..c019589cf31 100644
--- a/MantidQt/API/src/WindowIcons.cpp
+++ b/MantidQt/API/src/WindowIcons.cpp
@@ -19,8 +19,13 @@ WindowIcons::WindowIcons() : m_idToPixmapName() { initInternalLookup(); }
  * @param windowID A string giving the ID for a window
  * @throws std::runtime_error if no icon can be found
  */
-QPixmap WindowIcons::getIcon(const std::string &windowID) const {
-  return getQPixmap(m_idToPixmapName.value(windowID));
+QIcon WindowIcons::getIcon(const std::string &windowID) const {
+  auto value = m_idToPixmapName.value(windowID);
+  if(QString::fromStdString(value).endsWith(".png")) {
+    return makeIconFromFile(value);
+  } else {
+    return getQPixmap(value);
+  }
 }
 
 /**
@@ -43,12 +48,24 @@ std::string WindowIcons::getIconID(const std::string &windowID) const
  */
 void WindowIcons::initInternalLookup() {
   m_idToPixmapName.clear();
-  m_idToPixmapName["Matrix"] = "mantid_matrix_xpm";
+  m_idToPixmapName["Matrix"] = "matrix_xpm";
+  m_idToPixmapName["MantidMatrix"] = "mantid_matrix_xpm";
   m_idToPixmapName["Table"] = "worksheet_xpm";
   m_idToPixmapName["Note"] = "note_xpm";
-  m_idToPixmapName["Graph"] = "graph_xpm";
-  m_idToPixmapName["3D Graph"] = "trajectory_xpm";
+  m_idToPixmapName["MultiLayer"] = "graph_xpm";
+  m_idToPixmapName["Graph3D"] = "trajectory_xpm";
   m_idToPixmapName["Workspace"] = "mantid_matrix_xpm";
+  m_idToPixmapName["SliceViewer"] = ":/SliceViewer/icons/SliceViewerWindow_icon.png";
+  m_idToPixmapName["VSIWindow"] = ":/VatesSimpleGuiViewWidgets/icons/pvIcon.png";
+}
+
+QIcon WindowIcons::makeIconFromFile(const std::string &path) const
+{
+    QIcon icon;
+    icon.addFile(
+        QString::fromStdString(path),
+        QSize(), QIcon::Normal, QIcon::Off);
+    return icon;
 }
 }
 }
diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewerWindow.h b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewerWindow.h
index 759d074c31c..0f4beca61f2 100644
--- a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewerWindow.h
+++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewerWindow.h
@@ -47,6 +47,8 @@ public:
   std::string getWindowName() override;
   /// Get the workspaces associated with this window
   std::vector<std::string> getWorkspaceNames() override;
+  /// Get the window type as a string
+  std::string getWindowType() override;
 
 private:
   void setLineViewerValues(QPointF start2D, QPointF end2D, double width);
diff --git a/MantidQt/SliceViewer/src/SliceViewerWindow.cpp b/MantidQt/SliceViewer/src/SliceViewerWindow.cpp
index 1e11bfb79e3..6b42cc95fa1 100644
--- a/MantidQt/SliceViewer/src/SliceViewerWindow.cpp
+++ b/MantidQt/SliceViewer/src/SliceViewerWindow.cpp
@@ -537,7 +537,7 @@ std::string SliceViewerWindow::saveToProject(ApplicationWindow *app) {
 
 std::string SliceViewerWindow::getWindowName()
 {
-  return "SliceViewer";
+  return "Slice Viewer (" + m_wsName + ")";
 }
 
 std::vector<std::string> SliceViewerWindow::getWorkspaceNames()
@@ -545,5 +545,10 @@ std::vector<std::string> SliceViewerWindow::getWorkspaceNames()
   return { m_ws->name() };
 }
 
+std::string SliceViewerWindow::getWindowType()
+{
+  return "SliceViewer";
+}
+
 } // namespace SliceViewer
 } // namespace MantidQt
diff --git a/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/SpectrumView.h b/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/SpectrumView.h
index a4ba23078ef..6ff82e82631 100644
--- a/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/SpectrumView.h
+++ b/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/SpectrumView.h
@@ -86,6 +86,8 @@ public:
   std::string getWindowName() override;
   /// Get the workspaces associated with this window
   std::vector<std::string> getWorkspaceNames() override;
+  /// Get the window type as a string
+  std::string getWindowType() override;
 
 signals:
   void spectrumDisplayChanged(SpectrumDisplay *);
diff --git a/MantidQt/SpectrumViewer/src/SpectrumView.cpp b/MantidQt/SpectrumViewer/src/SpectrumView.cpp
index 46de1879a6f..8c68bed8b2f 100644
--- a/MantidQt/SpectrumViewer/src/SpectrumView.cpp
+++ b/MantidQt/SpectrumViewer/src/SpectrumView.cpp
@@ -402,6 +402,11 @@ std::vector<std::string> SpectrumView::getWorkspaceNames()
   return names;
 }
 
+std::string SpectrumView::getWindowType()
+{
+  return "SpectrumView";
+}
+
 void SpectrumView::changeTracking(bool on) {
   if (m_spectrumDisplay.isEmpty()) {
     return;
-- 
GitLab