From 308e541ee426b9d94518b06e124efdeeed9ecbab Mon Sep 17 00:00:00 2001
From: Gennady Pospelov <g.pospelov@fz-juelich.de>
Date: Wed, 8 Jun 2016 10:58:40 +0200
Subject: [PATCH] New JobSelectorActions which isolates actions related to
 run/removal of jobs.

---
 .../Views/JobWidgets/JobSelectorActions.cpp   |  99 ++++++++
 .../Views/JobWidgets/JobSelectorActions.h     |  54 +++++
 .../Views/JobWidgets/JobSelectorWidget.cpp    |  26 +--
 .../Views/JobWidgets/JobSelectorWidget.h      |  29 ++-
 .../Views/JobWidgets/JobViewActivities.h      |   4 +-
 GUI/coregui/Views/JobWidgets/JobViewDocks.cpp |   2 +-
 GUI/coregui/coregui.qrc                       |   1 +
 GUI/coregui/images/toolbar16light_run.svg     | 212 ++++++++++++++++++
 8 files changed, 395 insertions(+), 32 deletions(-)
 create mode 100644 GUI/coregui/Views/JobWidgets/JobSelectorActions.cpp
 create mode 100644 GUI/coregui/Views/JobWidgets/JobSelectorActions.h
 create mode 100644 GUI/coregui/images/toolbar16light_run.svg

diff --git a/GUI/coregui/Views/JobWidgets/JobSelectorActions.cpp b/GUI/coregui/Views/JobWidgets/JobSelectorActions.cpp
new file mode 100644
index 00000000000..6d136b0d3fc
--- /dev/null
+++ b/GUI/coregui/Views/JobWidgets/JobSelectorActions.cpp
@@ -0,0 +1,99 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      coregui/Views/JobWidgets/JobSelectorActions.cpp
+//! @brief     Implements class JobSelectorActions
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2016
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov
+//! @authors   Walter Van Herck, Joachim Wuttke
+//
+// ************************************************************************** //
+
+#include "JobSelectorActions.h"
+#include "JobModel.h"
+#include "StyledToolBar.h"
+#include "JobItem.h"
+#include <QAction>
+#include <QItemSelectionModel>
+#include <QDebug>
+
+JobSelectorActions::JobSelectorActions(JobModel *jobModel, QObject *parent)
+    : QObject(parent)
+    , m_runJobAction(0)
+    , m_removeJobAction(0)
+    , m_selectionModel(0)
+    , m_jobModel(jobModel)
+{
+    m_runJobAction = new QAction(QStringLiteral("Run"), this);
+    m_runJobAction->setIcon(QIcon(":/images/toolbar16light_run.svg"));
+    m_runJobAction->setToolTip("Run currently selected job");
+    connect(m_runJobAction, SIGNAL(triggered()), this, SLOT(onRunJob()));
+
+    // plot properties button
+    m_removeJobAction = new QAction(QStringLiteral("Remove"), this);
+    m_removeJobAction->setIcon(QIcon(":/images/toolbar16light_recycle.svg"));
+    m_removeJobAction->setToolTip("Remove currently selected job.");
+    connect(m_removeJobAction, SIGNAL(triggered()), this, SLOT(onRemoveJob()));
+}
+
+void JobSelectorActions::setSelectionModel(QItemSelectionModel *selectionModel)
+{
+    m_selectionModel = selectionModel;
+}
+
+//! Adds local actions to the external toolbar
+
+void JobSelectorActions::setToolBar(StyledToolBar *toolBar)
+{
+    toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+    toolBar->addAction(m_runJobAction);
+    toolBar->addAction(m_removeJobAction);
+}
+
+void JobSelectorActions::onRunJob()
+{
+    QModelIndexList indexList = m_selectionModel->selectedIndexes();
+    foreach(QModelIndex index, indexList) {
+        if(canRunJob(index))
+            m_jobModel->runJob(index);
+    }
+}
+
+void JobSelectorActions::onRemoveJob()
+{
+    qDebug() << "JobSelectorActions::onRemoveJob()";
+    Q_ASSERT(m_selectionModel);
+    QModelIndexList indexList = m_selectionModel->selectedIndexes();
+
+    while(indexList.size()) {
+        if(canRemoveJob(indexList.first())) {
+            m_jobModel->removeJob(indexList.first());
+            indexList = m_selectionModel->selectedIndexes();
+        }
+    }
+
+}
+
+bool JobSelectorActions::canRunJob(const QModelIndex &index) const
+{
+    if(!index.isValid()) return false;
+
+    const JobItem *jobItem = m_jobModel->getJobItemForIndex(index);
+    if(jobItem->isRunning()) return false;
+    return true;
+}
+
+bool JobSelectorActions::canRemoveJob(const QModelIndex &index) const
+{
+    if(!index.isValid()) return false;
+
+    const JobItem *jobItem = m_jobModel->getJobItemForIndex(index);
+    if(jobItem->isRunning()) return false;
+
+    return true;
+}
diff --git a/GUI/coregui/Views/JobWidgets/JobSelectorActions.h b/GUI/coregui/Views/JobWidgets/JobSelectorActions.h
new file mode 100644
index 00000000000..717cc7611d9
--- /dev/null
+++ b/GUI/coregui/Views/JobWidgets/JobSelectorActions.h
@@ -0,0 +1,54 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      coregui/Views/JobWidgets/JobSelectorActions.h
+//! @brief     Declares class JobSelectorActions
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2016
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov
+//! @authors   Walter Van Herck, Joachim Wuttke
+//
+// ************************************************************************** //
+
+#ifndef JOBSELECTORACTIONS_H
+#define JOBSELECTORACTIONS_H
+
+#include "WinDllMacros.h"
+#include <QObject>
+
+class QAction;
+class JobModel;
+class QItemSelectionModel;
+class QModelIndex;
+
+//! The JobSelectorActions class contains actions to run/remove jobs. Actions are used by the
+//! toolbar and JobSelectorTree's context menu.
+
+class BA_CORE_API_ JobSelectorActions : public QObject {
+    Q_OBJECT
+public:
+    JobSelectorActions(JobModel *jobModel, QObject *parent = 0);
+
+    void setSelectionModel(QItemSelectionModel *selectionModel);
+    void setToolBar(class StyledToolBar *toolBar);
+
+public slots:
+    void onRunJob();
+    void onRemoveJob();
+
+private:
+    bool canRunJob(const QModelIndex &index) const;
+    bool canRemoveJob(const QModelIndex &index) const;
+
+    QAction *m_runJobAction;
+    QAction *m_removeJobAction;
+    QItemSelectionModel *m_selectionModel;
+    JobModel *m_jobModel;
+};
+
+#endif
+
diff --git a/GUI/coregui/Views/JobWidgets/JobSelectorWidget.cpp b/GUI/coregui/Views/JobWidgets/JobSelectorWidget.cpp
index 9270e1ade84..beb4663fcc8 100644
--- a/GUI/coregui/Views/JobWidgets/JobSelectorWidget.cpp
+++ b/GUI/coregui/Views/JobWidgets/JobSelectorWidget.cpp
@@ -16,33 +16,32 @@
 
 #include "JobSelectorWidget.h"
 #include "JobModel.h"
+#include "JobSelectorActions.h"
+#include "mainwindow_constants.h"
 #include "JobItem.h"
 #include "JobPropertiesWidget.h"
 #include "JobListWidget.h"
-#include "styledbar.h"
+#include "StyledToolBar.h"
 #include "minisplitter.h"
-#include "progressbar.h"
-#include <QSplitter>
-#include <QListView>
-#include <QPushButton>
-#include <QVBoxLayout>
 #include <QHBoxLayout>
-#include <QDebug>
 
-JobSelectorWidget::JobSelectorWidget(JobModel *model, QWidget *parent)
+JobSelectorWidget::JobSelectorWidget(JobModel *jobModel, QWidget *parent)
     : QWidget(parent)
-    , m_jobModel(0)
     , m_splitter(new Manhattan::MiniSplitter(this))
+    , m_toolBar(new StyledToolBar(this))
+    , m_jobSelectorActions(new JobSelectorActions(jobModel, this))
     , m_jobListWidget(new JobListWidget(this))
     , m_jobProperties(new JobPropertiesWidget(this))
+    , m_jobModel(0)
 {
-    setModel(model);
+    setModel(jobModel);
 
     setMinimumSize(128, 600);
     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
-    setWindowTitle(QLatin1String("Job Selector"));
+    setWindowTitle(Constants::JobSelectorWidgetName);
 
     m_splitter->setOrientation(Qt::Vertical);
+    m_splitter->addWidget(m_toolBar);
     m_splitter->addWidget(m_jobListWidget);
     m_splitter->addWidget(m_jobProperties);
     m_splitter->setChildrenCollapsible(true);
@@ -52,8 +51,10 @@ JobSelectorWidget::JobSelectorWidget(JobModel *model, QWidget *parent)
     mainLayout->setSpacing(0);
     mainLayout->addWidget(m_splitter);
     setLayout(mainLayout);
-}
 
+    m_jobSelectorActions->setSelectionModel(m_jobListWidget->getSelectionModel());
+    m_jobSelectorActions->setToolBar(m_toolBar);
+}
 
 void JobSelectorWidget::setModel(JobModel *model)
 {
@@ -67,7 +68,6 @@ void JobSelectorWidget::setModel(JobModel *model)
 void JobSelectorWidget::makeJobItemSelected(JobItem *item)
 {
     Q_ASSERT(item);
-    //qDebug() << "JobSelectorWidget::makeJobItemSelected(NJobItem *item)" << item;
     QModelIndex index = m_jobModel->indexOfItem(item);
     Q_ASSERT(index.isValid());
     m_jobListWidget->makeJobItemSelected(index);
diff --git a/GUI/coregui/Views/JobWidgets/JobSelectorWidget.h b/GUI/coregui/Views/JobWidgets/JobSelectorWidget.h
index 46e21436bf4..7d05b9e6d2e 100644
--- a/GUI/coregui/Views/JobWidgets/JobSelectorWidget.h
+++ b/GUI/coregui/Views/JobWidgets/JobSelectorWidget.h
@@ -3,7 +3,7 @@
 //  BornAgain: simulate and fit scattering at grazing incidence
 //
 //! @file      coregui/Views/JobWidgets/JobSelectorWidget.h
-//! @brief     Implements class JobSelectorWidget
+//! @brief     Declares class JobSelectorWidget
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
@@ -22,18 +22,16 @@
 
 class JobModel;
 class JobItem;
-class JobPropertiesWidget;
-class QSplitter;
-class QPushButton;
-class JobListWidget;
-
-//! Widget to select JobQueueItem in a list and display its properties
-//! Left side of JobQueueView
-//! Contains two widgets: JobListWidget (top) and JobQueueProperties(buttom)
+
+//! The JobSelectorWidget class represents left panel of JobView. Contains a tree to select jobs
+//! on the top and job property editor at the bottom.
+
 class BA_CORE_API_ JobSelectorWidget : public QWidget
 {
+    Q_OBJECT
+
 public:
-    explicit JobSelectorWidget(JobModel *model, QWidget *parent = 0);
+    explicit JobSelectorWidget(JobModel *jobModel, QWidget *parent = 0);
 
     void setModel(JobModel *model);
 
@@ -44,13 +42,12 @@ public slots:
     void makeJobItemSelected(JobItem *);
 
 private:
+    class QSplitter *m_splitter;
+    class StyledToolBar *m_toolBar;
+    class JobSelectorActions *m_jobSelectorActions;
+    class JobListWidget *m_jobListWidget;
+    class JobPropertiesWidget *m_jobProperties;
     JobModel *m_jobModel;
-    QSplitter *m_splitter;
-    JobListWidget *m_jobListWidget;
-    JobPropertiesWidget *m_jobProperties;
 };
 
-
-
-
 #endif
diff --git a/GUI/coregui/Views/JobWidgets/JobViewActivities.h b/GUI/coregui/Views/JobWidgets/JobViewActivities.h
index e407c2e0f8e..757615220aa 100644
--- a/GUI/coregui/Views/JobWidgets/JobViewActivities.h
+++ b/GUI/coregui/Views/JobWidgets/JobViewActivities.h
@@ -23,8 +23,8 @@
 #include <QMap>
 #include <QVector>
 
-//! The JobViewActivities class is a helper static class to get list of activities,
-//! and JobView's dock Ids which should be shown/hidden during current activity.
+//! The JobViewActivities class is a helper static class to get info related to JobView activities
+//! (JobViewActivity, RealTimeActivity and FittingActivity).
 
 class BA_CORE_API_ JobViewActivities {
 
diff --git a/GUI/coregui/Views/JobWidgets/JobViewDocks.cpp b/GUI/coregui/Views/JobWidgets/JobViewDocks.cpp
index c2055a148e7..1ef727147d8 100644
--- a/GUI/coregui/Views/JobWidgets/JobViewDocks.cpp
+++ b/GUI/coregui/Views/JobWidgets/JobViewDocks.cpp
@@ -152,7 +152,7 @@ void JobViewDocks::initJobWidgets(JobModel *jobModel)
     m_jobView->setCentralWidget(centralWidget());
 }
 
-//! Init docks for JobView
+//! Init docks for JobView.
 
 void JobViewDocks::initDocks()
 {
diff --git a/GUI/coregui/coregui.qrc b/GUI/coregui/coregui.qrc
index 4cf67f82ceb..90ccec01306 100644
--- a/GUI/coregui/coregui.qrc
+++ b/GUI/coregui/coregui.qrc
@@ -44,5 +44,6 @@
         <file>images/toolbar16light_recycle.svg</file>
         <file>images/toolbar16light_newitem.svg</file>
         <file>images/toolbar16light_cloneitem.svg</file>
+        <file>images/toolbar16light_run.svg</file>
     </qresource>
 </RCC>
diff --git a/GUI/coregui/images/toolbar16light_run.svg b/GUI/coregui/images/toolbar16light_run.svg
new file mode 100644
index 00000000000..25e053a19c2
--- /dev/null
+++ b/GUI/coregui/images/toolbar16light_run.svg
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="16"
+   height="16"
+   id="svg2985"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="toolbar16light_run.svg">
+  <defs
+     id="defs2987">
+    <linearGradient
+       id="linearGradient4824">
+      <stop
+         id="stop4826"
+         offset="0"
+         style="stop-color:#0f0f0f;stop-opacity:1;" />
+      <stop
+         id="stop4828"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+    </linearGradient>
+    <inkscape:path-effect
+       effect="spiro"
+       id="path-effect3138"
+       is_visible="true" />
+    <linearGradient
+       id="linearGradient4619">
+      <stop
+         style="stop-color:#c3c3c3;stop-opacity:1;"
+         offset="0"
+         id="stop4621" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop4623" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4592">
+      <stop
+         style="stop-color:#c3c3c3;stop-opacity:1;"
+         offset="0"
+         id="stop4594" />
+      <stop
+         style="stop-color:#fafafa;stop-opacity:0.98039216;"
+         offset="1"
+         id="stop4596" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4619"
+       id="linearGradient4708"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.90913729,12.020815)"
+       x1="11"
+       y1="12"
+       x2="11"
+       y2="6" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4619"
+       id="linearGradient4724"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(4.3671751,0,0,0.36023659,-29.207084,18.152322)"
+       x1="11"
+       y1="12"
+       x2="11"
+       y2="6" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4619"
+       id="linearGradient3048"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.62685746,0,0,1,-8.55667,-29.093836)"
+       x1="22"
+       y1="38"
+       x2="22"
+       y2="26" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4619"
+       id="linearGradient3969"
+       x1="10.956502"
+       y1="34.109333"
+       x2="9.2564144"
+       y2="37.1903"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4619"
+       id="linearGradient3994"
+       gradientUnits="userSpaceOnUse"
+       x1="10.956502"
+       y1="34.109333"
+       x2="9.2564144"
+       y2="37.1903"
+       gradientTransform="translate(0,-32)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3943"
+       id="linearGradient3949"
+       x1="25.773111"
+       y1="32.89315"
+       x2="4.6256304"
+       y2="8.9645777"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.34150193,0,0,0.37023412,-0.46255915,31.030441)" />
+    <linearGradient
+       id="linearGradient3943">
+      <stop
+         style="stop-color:#c3c3c3;stop-opacity:1;"
+         offset="0"
+         id="stop3945" />
+      <stop
+         style="stop-color:#f9f9f9;stop-opacity:1;"
+         offset="1"
+         id="stop3947" />
+    </linearGradient>
+    <filter
+       id="filter3044"
+       style="color-interpolation-filters:sRGB"
+       inkscape:label="Drop Shadow">
+      <feFlood
+         id="feFlood3046"
+         flood-opacity="0.75"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3048"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3050"
+         stdDeviation="0.5"
+         result="blur" />
+      <feOffset
+         id="feOffset3052"
+         dx="0.5"
+         dy="0.5"
+         result="offset" />
+      <feComposite
+         id="feComposite3054"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="28"
+     inkscape:cx="-2.4821427"
+     inkscape:cy="2.93477"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="2466"
+     inkscape:window-height="1365"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:snap-global="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3012"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2990">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,-32)">
+    <path
+       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:Sans;-inkscape-font-specification:Sans;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3949);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:8.04157448;marker:none;enable-background:accumulate"
+       d="m 1.9680935,34.395558 c -0.6036613,0.03184 -0.9110113,0.615807 -0.9124868,1.039132 l -0.017249,4.522813 -0.017249,4.429313 c 0.00148,0.296392 0.2597574,0.923196 0.6271801,1.070963 0.3674227,0.14777 0.8473516,0.147515 1.2144525,-6.3e-4 l 5.898527,-2.379662 5.8022567,-2.420957 c 0.363889,-0.149222 0.457583,-0.416409 0.457583,-0.711396 0,-0.294987 -0.0937,-0.620321 -0.457583,-0.769542 L 8.7612693,36.83752 2.8627423,34.457871 c -0.210113,-0.08517 -0.6524515,-0.07481 -0.8946488,-0.06231 z"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccccscccscccc"
+       id="path2999" />
+  </g>
+</svg>
-- 
GitLab