From c01c2b67b29c3a72d2ad698ed74763447b7374c0 Mon Sep 17 00:00:00 2001
From: Walter Van Herck <w.van.herck@fz-juelich.de>
Date: Wed, 19 Feb 2014 14:09:19 +0100
Subject: [PATCH] Implemented deleting from context menu

---
 GUI/coregui/Models/LayerItem.cpp              |   2 +-
 GUI/coregui/Models/MultiLayerItem.cpp         |   1 +
 GUI/coregui/Models/ParameterizedItem.cpp      |  13 +-
 GUI/coregui/Models/ParameterizedItem.h        |  16 +--
 GUI/coregui/Models/ParticleDecorationItem.cpp |   2 +-
 GUI/coregui/Models/SessionModel.cpp           |  13 +-
 GUI/coregui/Views/SampleView.cpp              | 116 ++++++++++++++----
 GUI/coregui/Views/SampleView.h                |  36 ++++--
 GUI/coregui/Views/SampleViewComponents.cpp    |   1 +
 GUI/coregui/utils/GUIHelpers.cpp              |  98 +++++++++++++++
 GUI/coregui/utils/GUIHelpers.h                |  37 ++++++
 11 files changed, 281 insertions(+), 54 deletions(-)
 create mode 100644 GUI/coregui/utils/GUIHelpers.cpp
 create mode 100644 GUI/coregui/utils/GUIHelpers.h

diff --git a/GUI/coregui/Models/LayerItem.cpp b/GUI/coregui/Models/LayerItem.cpp
index 1a2372396b1..373fe206f04 100644
--- a/GUI/coregui/Models/LayerItem.cpp
+++ b/GUI/coregui/Models/LayerItem.cpp
@@ -19,7 +19,7 @@ LayerItem::LayerItem()
     : ParameterizedItem(QString("Layer"))
 {
     m_parameters[QString("Thickness")] = 0.0;
-    m_valid_parents.append(QString("MultiLayer"));
+    m_valid_children.append(QString("ParticleDecoration"));
 }
 
 LayerItem::~LayerItem()
diff --git a/GUI/coregui/Models/MultiLayerItem.cpp b/GUI/coregui/Models/MultiLayerItem.cpp
index 9ce4a44008a..4963c953a70 100644
--- a/GUI/coregui/Models/MultiLayerItem.cpp
+++ b/GUI/coregui/Models/MultiLayerItem.cpp
@@ -20,6 +20,7 @@ MultiLayerItem::MultiLayerItem()
     : ParameterizedItem(QString("MultiLayer"))
 {
     m_parameters[QString("Cross Correlation Length")] = 0.0;
+    m_valid_children.append(QString("Layer"));
 }
 
 MultiLayerItem::~MultiLayerItem()
diff --git a/GUI/coregui/Models/ParameterizedItem.cpp b/GUI/coregui/Models/ParameterizedItem.cpp
index 236da75bc77..fd71ec61d02 100644
--- a/GUI/coregui/Models/ParameterizedItem.cpp
+++ b/GUI/coregui/Models/ParameterizedItem.cpp
@@ -27,7 +27,7 @@ ParameterizedItem::~ParameterizedItem()
 {
 }
 
-double ParameterizedItem::getParameterValue(QString name)
+double ParameterizedItem::getParameterValue(const QString &name) const
 {
     if (!m_parameters.contains(name)) {
         throw Exceptions::RuntimeErrorException("ParameterizedItem::getParameterValue: "
@@ -36,7 +36,7 @@ double ParameterizedItem::getParameterValue(QString name)
     return m_parameters[name];
 }
 
-void ParameterizedItem::setParameter(QString name, double value)
+void ParameterizedItem::setParameter(const QString &name, double value)
 {
     if (!m_parameters.contains(name)) {
         throw Exceptions::RuntimeErrorException("ParameterizedItem::getParameterValue: "
@@ -45,13 +45,8 @@ void ParameterizedItem::setParameter(QString name, double value)
     m_parameters[name] = value;
 }
 
-bool ParameterizedItem::acceptsAsChild(ParameterizedItem *child)
+bool ParameterizedItem::acceptsAsChild(const QString &child_name) const
 {
-    return child->isValidParent(this->text());
-}
-
-bool ParameterizedItem::isValidParent(QString parentName)
-{
-    return m_valid_parents.contains(parentName);
+    return m_valid_children.contains(child_name);
 }
 
diff --git a/GUI/coregui/Models/ParameterizedItem.h b/GUI/coregui/Models/ParameterizedItem.h
index 89d39e15994..563be4172bb 100644
--- a/GUI/coregui/Models/ParameterizedItem.h
+++ b/GUI/coregui/Models/ParameterizedItem.h
@@ -27,10 +27,10 @@ public:
     ~ParameterizedItem();
 
     //! retrieves the parameter's value
-    double getParameterValue(QString name);
+    double getParameterValue(const QString &name) const;
 
     //! sets the parameter's value, if it exists
-    void setParameter(QString name, double value);
+    void setParameter(const QString &name, double value);
 
     //! retrieves the whole list of paramaters
     QMap<QString, double> &getParameters() {
@@ -39,14 +39,16 @@ public:
 
     //! indicates if the passed item can be set as
     //! a child item
-    bool acceptsAsChild(ParameterizedItem *child);
+    bool acceptsAsChild(const QString &child_name) const;
+
+    //! get list of acceptable child object names
+    QList<QString> getAcceptableChildren() const {
+        return m_valid_children;
+    }
 protected:
-    QList<QString> m_valid_parents;
+    QList<QString> m_valid_children;
     QMap<QString, double> m_parameters;
 private:
-    //! indicates if the item name, passed as argument
-    //! can be the current item's parent
-    bool isValidParent(QString parentName);
 };
 
 
diff --git a/GUI/coregui/Models/ParticleDecorationItem.cpp b/GUI/coregui/Models/ParticleDecorationItem.cpp
index 2a103755b7e..387d7a6d406 100644
--- a/GUI/coregui/Models/ParticleDecorationItem.cpp
+++ b/GUI/coregui/Models/ParticleDecorationItem.cpp
@@ -18,7 +18,7 @@
 ParticleDecorationItem::ParticleDecorationItem()
     : ParameterizedItem(QString("ParticleDecoration"))
 {
-    m_valid_parents.append(QString("Layer"));
+//    m_valid_children.append(QString(""));
 }
 
 
diff --git a/GUI/coregui/Models/SessionModel.cpp b/GUI/coregui/Models/SessionModel.cpp
index 3dcbdf8d4c0..b3b109bc923 100644
--- a/GUI/coregui/Models/SessionModel.cpp
+++ b/GUI/coregui/Models/SessionModel.cpp
@@ -48,21 +48,20 @@ void SessionModel::initialize()
 
 QStandardItem *SessionModel::createNewItem(QStandardItem *parent, QString model_type)
 {
-    ParameterizedItem *new_item = ItemFactory::createItem(model_type);
-    if (!new_item) {
-        return 0;
-    }
-
     // Check if child is allowed to be added to parent
     if (parent!=invisibleRootItem())
     {
         ParameterizedItem *p_par_parent = dynamic_cast<ParameterizedItem *>(parent);
-        if (!p_par_parent || !p_par_parent->acceptsAsChild(new_item)) {
-            delete new_item;
+        if (!p_par_parent || !p_par_parent->acceptsAsChild(model_type)) {
             return 0;
         }
     }
 
+    ParameterizedItem *new_item = ItemFactory::createItem(model_type);
+    if (!new_item) {
+        return 0;
+    }
+
     parent->appendRow(new_item);
     return new_item;
 }
diff --git a/GUI/coregui/Views/SampleView.cpp b/GUI/coregui/Views/SampleView.cpp
index 591136ce970..5dd348be528 100644
--- a/GUI/coregui/Views/SampleView.cpp
+++ b/GUI/coregui/Views/SampleView.cpp
@@ -3,7 +3,7 @@
 #include "SampleDesigner.h"
 #include "SampleToolBar.h"
 #include "MaterialBrowser.h"
-#include "SessionModel.h"
+#include "GUIHelpers.h"
 
 
 #include <QDockWidget>
@@ -13,6 +13,7 @@
 #include <QToolBar>
 #include <QAction>
 #include <QToolButton>
+#include <QMenu>
 
 
 #include <iostream>
@@ -28,7 +29,7 @@ SampleView::SampleView(QWidget *parent)
     , m_sampleDesigner(new SampleDesigner(this))
     , m_toolBar(0)
 {
-    setObjectName(QLatin1String("SampleView"));
+    setObjectName(tr("SampleView"));
 
     setCentralWidget(m_sampleDesigner->getCentralWidget());
 
@@ -53,7 +54,11 @@ SampleView::SampleView(QWidget *parent)
     }
     resetToDefaultLayout();
 
-    initActions();
+    createActions();
+
+
+
+    connectSignals();
 
 }
 
@@ -76,38 +81,35 @@ void SampleView::initSubWindows()
 
     m_subWindows[WidgetBoxSubWindow] = SampleViewComponents::createWidgetBox(m_sampleDesigner, this);
 
-    SessionModel *session_model = new SessionModel();
+    m_session = new SessionModel();
     // Temporary for testing
-    QStandardItem *multilayer = session_model->insertNewItem("MultiLayer", QModelIndex());
-    QStandardItem *layer = session_model->insertNewItem("Layer", multilayer->index());
-    session_model->insertNewItem("ParticleDecoration", layer->index());
-    session_model->insertNewItem("Layer", QModelIndex());
+    QStandardItem *multilayer = m_session->insertNewItem("MultiLayer", QModelIndex());
+    QStandardItem *layer = m_session->insertNewItem("Layer", multilayer->index());
+    m_session->insertNewItem("ParticleDecoration", layer->index());
+    m_session->insertNewItem("Layer", QModelIndex());
     // END temporary
-    m_subWindows[SampleTreeView] = SampleViewComponents::createTreeView(session_model, this);
+    m_tree_view = SampleViewComponents::createTreeView(m_session, this);
+    m_subWindows[SampleTreeView] = m_tree_view;
 
     m_subWindows[PropertyEditorSubWindow] = SampleViewComponents::createPropertyEditor(m_sampleDesigner, this);
 
     SampleInfoStreamInterface *ae = SampleViewComponents::createInfoStream(this);
     ae->setWindowTitle(tr("Info Stream"));
-    ae->setObjectName(QLatin1String("InfoStream"));
+    ae->setObjectName(tr("InfoStream"));
     m_subWindows[InfoSubWindow] = ae;
 }
 
-
-void SampleView::initActions()
+void SampleView::createActions()
 {
-    // toolBar should be initialized after MaterialBrowser
-    m_toolBar = new SampleToolBar(this);
-    connect(m_toolBar, SIGNAL(zoomOut()), m_sampleDesigner->getView(), SLOT(zoomOut()));
-    connect(m_toolBar, SIGNAL(zoomIn()), m_sampleDesigner->getView(), SLOT(zoomIn()));
-    connect(m_toolBar, SIGNAL(zoomFit()), m_sampleDesigner->getView(), SLOT(zoomFit()));
-    connect(m_toolBar, SIGNAL(clearAll()), m_sampleDesigner->getView(), SLOT(clearAll()));
-    connect(m_toolBar, SIGNAL(sceneToISample()), m_sampleDesigner, SLOT(sceneToISample()));
+    addAct = new QAction(tr("Add"), this);
+    addAct->setStatusTip(tr("Add a new object"));
+    connect(addAct, SIGNAL(triggered()), this, SLOT(addItem()));
 
-    addToolBar(m_toolBar);
+    delAct = new QAction(tr("Delete"), this);
+    delAct->setStatusTip(tr("Delete current object"));
+    connect(delAct, SIGNAL(triggered()), this, SLOT(deleteItem()));
 }
 
-
 void SampleView::resetToDefaultLayout()
 {
     setTrackingEnabled(false);
@@ -131,3 +133,75 @@ void SampleView::resetToDefaultLayout()
     setTrackingEnabled(true);
 }
 
+void SampleView::addItem()
+{
+}
+
+void SampleView::deleteItem()
+{
+    QModelIndex currentIndex = getTreeView()->currentIndex();
+    if (currentIndex.isValid()) {
+        QStandardItem *item = getSessionModel()->itemFromIndex(currentIndex);
+        QString name = item->text();
+        int rows = item->rowCount();
+        QString message;
+        if (rows == 0)
+            message = tr("<p>Delete '%1'").arg(name);
+        else if (rows == 1)
+            message = tr("<p>Delete '%1' and its child (and "
+                         "grandchildren etc.)").arg(name);
+        else if (rows > 1)
+            message = tr("<p>Delete '%1' and its %2 children (and "
+                         "grandchildren etc.)").arg(name).arg(rows);
+        if (!GUIHelpers::okToDelete(this, tr("Delete"), message)) return;
+        getSessionModel()->removeRow(currentIndex.row(), currentIndex.parent());
+        setDirty();
+        updateUi();
+    }
+}
+
+void SampleView::showContextMenu(const QPoint &pnt)
+{
+    QList<QAction *> actions;
+    if (getTreeView()->indexAt(pnt).isValid()) {
+        actions.append(delAct);
+    }
+    if (actions.count() > 0) {
+        QMenu::exec(actions, getTreeView()->mapToGlobal(pnt));
+    }
+}
+
+void SampleView::updateUi()
+{
+}
+
+
+void SampleView::connectSignals()
+{
+    // toolBar should be initialized after MaterialBrowser
+    m_toolBar = new SampleToolBar(this);
+    connect(m_toolBar, SIGNAL(zoomOut()), m_sampleDesigner->getView(), SLOT(zoomOut()));
+    connect(m_toolBar, SIGNAL(zoomIn()), m_sampleDesigner->getView(), SLOT(zoomIn()));
+    connect(m_toolBar, SIGNAL(zoomFit()), m_sampleDesigner->getView(), SLOT(zoomFit()));
+    connect(m_toolBar, SIGNAL(clearAll()), m_sampleDesigner->getView(), SLOT(clearAll()));
+    connect(m_toolBar, SIGNAL(sceneToISample()), m_sampleDesigner, SLOT(sceneToISample()));
+
+    // connect context menu for tree view
+    QTreeView *tree_view = static_cast<QTreeView *>(m_subWindows[SampleTreeView]);
+    connect(tree_view, SIGNAL(customContextMenuRequested(const QPoint &)),
+            this, SLOT(showContextMenu(const QPoint &)));
+
+    addToolBar(m_toolBar);
+}
+
+SessionModel *SampleView::getSessionModel()
+{
+    return m_session;
+}
+
+QTreeView *SampleView::getTreeView()
+{
+    return m_tree_view;
+}
+
+
diff --git a/GUI/coregui/Views/SampleView.h b/GUI/coregui/Views/SampleView.h
index 20487d1caf7..70500a309d9 100644
--- a/GUI/coregui/Views/SampleView.h
+++ b/GUI/coregui/Views/SampleView.h
@@ -6,6 +6,9 @@
 #include <QMainWindow>
 #include <QDockWidget>
 #include <QTreeView>
+#include <QAction>
+
+#include "SessionModel.h"
 
 
 class SampleDesignerInterface;
@@ -22,10 +25,10 @@ public:
 
     enum SubWindows
     {
-        WidgetBoxSubWindow,
-        SampleTreeView,
-        PropertyEditorSubWindow,
-        InfoSubWindow,
+        WidgetBoxSubWindow,         // drag & drop items
+        SampleTreeView,             // a tree view
+        PropertyEditorSubWindow,    // property editor
+        InfoSubWindow,              // status/info display
         NumberOfSubWindows
     };
 
@@ -35,17 +38,34 @@ public:
 
 public slots:
     void resetToDefaultLayout();
+    void addItem();
+    void deleteItem();
 //    void materialEditorCall();
 
+protected slots:
+    void showContextMenu(const QPoint &pnt);
+    void setDirty(bool dirty=true) { setWindowModified(dirty); }
+    void updateUi();
+
 private:
     void initSubWindows();
-    void initActions();
+    void createActions();
+    void connectSignals();
+
+    SessionModel *getSessionModel();
+    QTreeView *getTreeView();
 
-    MaterialBrowser *m_materialBrowser;
-    SampleDesigner *m_sampleDesigner;
-    SampleToolBar *m_toolBar;
+    MaterialBrowser *m_materialBrowser;  // material editor
+    SampleDesigner *m_sampleDesigner;    // main sample view
+    SampleToolBar *m_toolBar;            // toolbar
     QWidget *m_subWindows[NumberOfSubWindows];
     QDockWidget *m_dockWidgets[NumberOfSubWindows];
+
+    QAction *addAct;
+    QAction *delAct;
+
+    SessionModel *m_session;
+    QTreeView *m_tree_view;
 };
 
 
diff --git a/GUI/coregui/Views/SampleViewComponents.cpp b/GUI/coregui/Views/SampleViewComponents.cpp
index e7dcbf2fb16..0c7e0481e1e 100644
--- a/GUI/coregui/Views/SampleViewComponents.cpp
+++ b/GUI/coregui/Views/SampleViewComponents.cpp
@@ -46,6 +46,7 @@ QTreeView *SampleViewComponents::createTreeView(SessionModel *session_model, QWi
     tree_view->setAllColumnsShowFocus(true);
     tree_view->setWindowTitle(QString("Object Tree View"));
     tree_view->setObjectName(QString("ObjectTree"));
+    tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
     return tree_view;
 }
 
diff --git a/GUI/coregui/utils/GUIHelpers.cpp b/GUI/coregui/utils/GUIHelpers.cpp
new file mode 100644
index 00000000000..55d06bb4101
--- /dev/null
+++ b/GUI/coregui/utils/GUIHelpers.cpp
@@ -0,0 +1,98 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      utils/GUIHelpers.cpp
+//! @brief     Implements GUI helper functions.
+//!
+//! @homepage  http://apps.jcns.fz-juelich.de/BornAgain
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2013
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#include "GUIHelpers.h"
+
+#include <QApplication>
+#include <QMessageBox>
+#include <QPushButton>
+
+namespace GUIHelpers {
+
+void information(QWidget *parent, const QString &title, const QString &text, const QString &detailedText)
+{
+    QScopedPointer<QMessageBox> messageBox(new QMessageBox(parent));
+    if (parent)
+        messageBox->setWindowModality(Qt::WindowModal);
+    messageBox->setWindowTitle(QString("%1 - %2")
+            .arg(QApplication::applicationName()).arg(title));
+    messageBox->setText(text);
+    if (!detailedText.isEmpty())
+        messageBox->setInformativeText(detailedText);
+    messageBox->setIcon(QMessageBox::Information);
+    messageBox->addButton(QMessageBox::Ok);
+    messageBox->exec();
+}
+
+
+void warning(QWidget *parent, const QString &title, const QString &text, const QString &detailedText)
+{
+    QScopedPointer<QMessageBox> messageBox(new QMessageBox(parent));
+    if (parent)
+        messageBox->setWindowModality(Qt::WindowModal);
+    messageBox->setWindowTitle(QString("%1 - %2")
+            .arg(QApplication::applicationName()).arg(title));
+    messageBox->setText(text);
+    if (!detailedText.isEmpty())
+        messageBox->setInformativeText(detailedText);
+    messageBox->setIcon(QMessageBox::Warning);
+    messageBox->addButton(QMessageBox::Ok);
+    messageBox->exec();
+}
+
+
+bool question(QWidget *parent, const QString &title, const QString &text, const QString &detailedText, const QString &yesText, const QString &noText)
+{
+    QScopedPointer<QMessageBox> messageBox(new QMessageBox(parent));
+    if (parent)
+        messageBox->setWindowModality(Qt::WindowModal);
+    messageBox->setWindowTitle(QString("%1 - %2")
+            .arg(QApplication::applicationName()).arg(title));
+    messageBox->setText(text);
+    if (!detailedText.isEmpty())
+        messageBox->setInformativeText(detailedText);
+    messageBox->setIcon(QMessageBox::Question);
+    QAbstractButton *yesButton = messageBox->addButton(yesText,
+            QMessageBox::AcceptRole);
+    messageBox->addButton(noText, QMessageBox::RejectRole);
+    messageBox->setDefaultButton(
+            qobject_cast<QPushButton*>(yesButton));
+    messageBox->exec();
+    return messageBox->clickedButton() == yesButton;
+}
+
+
+bool okToDelete(QWidget *parent, const QString &title, const QString &text, const QString &detailedText)
+{
+    QScopedPointer<QMessageBox> messageBox(new QMessageBox(parent));
+    if (parent)
+        messageBox->setWindowModality(Qt::WindowModal);
+    messageBox->setIcon(QMessageBox::Question);
+    messageBox->setWindowTitle(QString("%1 - %2")
+            .arg(QApplication::applicationName()).arg(title));
+    messageBox->setText(text);
+    if (!detailedText.isEmpty())
+        messageBox->setInformativeText(detailedText);
+    QAbstractButton *deleteButton = messageBox->addButton(
+            QObject::tr("&Delete"), QMessageBox::AcceptRole);
+    messageBox->addButton(QObject::tr("Do &Not Delete"),
+                          QMessageBox::RejectRole);
+    messageBox->setDefaultButton(
+            qobject_cast<QPushButton*>(deleteButton));
+    messageBox->exec();
+    return messageBox->clickedButton() == deleteButton;
+}
+
+} // namespace GUIHelpers
diff --git a/GUI/coregui/utils/GUIHelpers.h b/GUI/coregui/utils/GUIHelpers.h
new file mode 100644
index 00000000000..2ed035c90df
--- /dev/null
+++ b/GUI/coregui/utils/GUIHelpers.h
@@ -0,0 +1,37 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      utils/GUIHelpers.h
+//! @brief     Defines GUI helper functions.
+//!
+//! @homepage  http://apps.jcns.fz-juelich.de/BornAgain
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2013
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#ifndef GUIHELPERS_H
+#define GUIHELPERS_H
+
+#include <QWidget>
+#include <QString>
+
+namespace GUIHelpers
+{
+void information(QWidget *parent, const QString &title,
+        const QString &text, const QString &detailedText=QString());
+void warning(QWidget *parent, const QString &title,
+        const QString &text, const QString &detailedText=QString());
+bool question(QWidget *parent, const QString &title,
+        const QString &text, const QString &detailedText=QString(),
+        const QString &yesText=QObject::tr("&Yes"),
+        const QString &noText=QObject::tr("&No"));
+bool okToDelete(QWidget *parent, const QString &title,
+        const QString &text, const QString &detailedText=QString());
+};
+
+#endif // GUIHELPERS_H
+
-- 
GitLab