From 8e852b19ae113d97fc31783bec630cfd9c0cd256 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Wed, 2 Dec 2015 01:29:20 +0100 Subject: [PATCH] refs #525, specialized model class for DB entities and improved funtions in view base class * will allow to highlight entities * nested custom menus * moved displayAutomatically() menus in view base class * fixed which menus are displayed for aircraft models * also changed to QStandardItem model to see if this is causing any trouble (the real bigger changes will follow in #530) --- src/blackgui/menudelegate.h | 23 +++- .../models/aircraftmodellistmodel.cpp | 3 +- src/blackgui/models/aircraftmodellistmodel.h | 14 ++- src/blackgui/models/listmodelbase.cpp | 13 ++- src/blackgui/models/listmodelbase.h | 34 +++--- src/blackgui/models/modelswithdbkey.cpp | 52 +++++++++ src/blackgui/models/modelswithdbkey.h | 54 +++++++++ src/blackgui/views/aircraftmodelview.cpp | 104 ++++++++++-------- src/blackgui/views/aircraftmodelview.h | 38 ++++--- src/blackgui/views/viewbase.cpp | 81 +++++++++++++- src/blackgui/views/viewbase.h | 54 ++++++--- 11 files changed, 362 insertions(+), 108 deletions(-) create mode 100644 src/blackgui/models/modelswithdbkey.cpp create mode 100644 src/blackgui/models/modelswithdbkey.h diff --git a/src/blackgui/menudelegate.h b/src/blackgui/menudelegate.h index 13db7d042..7a0157fc1 100644 --- a/src/blackgui/menudelegate.h +++ b/src/blackgui/menudelegate.h @@ -26,12 +26,33 @@ namespace BlackGui //! Display custom menu virtual void customMenu(QMenu &menu) const = 0; + //! Set nested delegate + void setNestedDelegate(IMenuDelegate *nestedDelegate) { m_nestedDelegate = nestedDelegate; } + + //! Nested delegate + IMenuDelegate *getNestedDelegate() const { return m_nestedDelegate; } + //! Destructor virtual ~IMenuDelegate() {} protected: //! Constructor - IMenuDelegate(QWidget *parent = nullptr) : QObject(parent) {} + IMenuDelegate(QWidget *parent = nullptr, bool separatorAtEnd = false) : + QObject(parent), m_separatorAtEnd(separatorAtEnd) {} + + //! Delegate down one level + void nestedCustomMenu(QMenu &menu) const + { + if (!m_nestedDelegate) + { + if (m_separatorAtEnd) { menu.addSeparator(); } + return; + } + m_nestedDelegate->customMenu(menu); + } + + IMenuDelegate *m_nestedDelegate = nullptr; //!< nested delegate if any + bool m_separatorAtEnd = false; //!< at end, terminate with seperator }; } // ns diff --git a/src/blackgui/models/aircraftmodellistmodel.cpp b/src/blackgui/models/aircraftmodellistmodel.cpp index b31ee9d1a..47ee10da0 100644 --- a/src/blackgui/models/aircraftmodellistmodel.cpp +++ b/src/blackgui/models/aircraftmodellistmodel.cpp @@ -21,7 +21,7 @@ namespace BlackGui namespace Models { CAircraftModelListModel::CAircraftModelListModel(AircraftModelMode mode, QObject *parent) : - CListModelBase("CAircraftModelListModel", parent) + CModelsWithDbKeysBase("CAircraftModelListModel", parent) { this->setAircraftModelMode(mode); @@ -40,6 +40,7 @@ namespace BlackGui { case NotSet: case OwnSimulatorModel: + case StashModel: this->m_columns.addColumn(CColumn::standardString("model", { CAircraftModel::IndexModelString})); this->m_columns.addColumn(CColumn::standardString("description", { CAircraftModel::IndexDescription})); this->m_columns.addColumn(CColumn::standardString("name", { CAircraftModel::IndexName})); diff --git a/src/blackgui/models/aircraftmodellistmodel.h b/src/blackgui/models/aircraftmodellistmodel.h index b9fca68d9..1d24e17b1 100644 --- a/src/blackgui/models/aircraftmodellistmodel.h +++ b/src/blackgui/models/aircraftmodellistmodel.h @@ -14,7 +14,7 @@ #include "blackgui/blackguiexport.h" #include "blackmisc/simulation/aircraftmodellist.h" -#include "blackgui/models/listmodelbase.h" +#include "blackgui/models/modelswithdbkey.h" #include namespace BlackGui @@ -23,7 +23,7 @@ namespace BlackGui { //! Aircraft model list model class BLACKGUI_EXPORT CAircraftModelListModel : - public CListModelBase + public CModelsWithDbKeysBase { public: //! How to display @@ -34,7 +34,8 @@ namespace BlackGui OwnSimulatorModel, ///< model existing with my sim MappedModel, ///< Model based on mapping operation Database, ///< Database entry - VPilotRuleModel ///< vPilot rule turned into model + VPilotRuleModel, ///< vPilot rule turned into model + StashModel ///< stashed models }; //! Constructor @@ -55,6 +56,12 @@ namespace BlackGui //! Highlight the DB models void setHighlightDbData(bool highlightDbData) { m_highlightDbData = highlightDbData; } + //! Highlight stashed models + bool highlightStashedModels() const { return m_highlightStashedData; } + + //! Highlight stashed models + void setHighlightStashedModels(bool highlightStashedModels) { m_highlightStashedData = highlightStashedModels; } + protected: //! \copydoc QAbstractItemModel::data virtual QVariant data(const QModelIndex &index, int role) const override; @@ -62,6 +69,7 @@ namespace BlackGui private: AircraftModelMode m_mode = NotSet; //!< current mode bool m_highlightDbData = false; + bool m_highlightStashedData = false; }; } // ns } // ns diff --git a/src/blackgui/models/listmodelbase.cpp b/src/blackgui/models/listmodelbase.cpp index 4562e2e7a..b80777e96 100644 --- a/src/blackgui/models/listmodelbase.cpp +++ b/src/blackgui/models/listmodelbase.cpp @@ -67,7 +67,7 @@ namespace BlackGui QModelIndex CListModelBaseNonTemplate::index(int row, int column, const QModelIndex &parent) const { Q_UNUSED(parent); - return QAbstractItemModel::createIndex(row, column); + return QStandardItemModel::createIndex(row, column); } QModelIndex CListModelBaseNonTemplate::parent(const QModelIndex &child) const @@ -105,7 +105,7 @@ namespace BlackGui Qt::ItemFlags CListModelBaseNonTemplate::flags(const QModelIndex &index) const { - Qt::ItemFlags f = QAbstractItemModel::flags(index); + Qt::ItemFlags f = QStandardItemModel::flags(index); if (!index.isValid()) { return f; } bool editable = this->m_columns.isEditable(index); f = editable ? (f | Qt::ItemIsEditable) : (f ^ Qt::ItemIsEditable); @@ -132,7 +132,7 @@ namespace BlackGui Qt::DropActions CListModelBaseNonTemplate::supportedDropActions() const { - return QAbstractItemModel::supportedDropActions(); + return QStandardItemModel::supportedDropActions(); } QStringList CListModelBaseNonTemplate::mimeTypes() const @@ -157,12 +157,17 @@ namespace BlackGui } CListModelBaseNonTemplate::CListModelBaseNonTemplate(const QString &translationContext, QObject *parent) - : QAbstractItemModel(parent), m_columns(translationContext), m_sortedColumn(-1), m_sortOrder(Qt::AscendingOrder) + : QStandardItemModel(parent), m_columns(translationContext), m_sortedColumn(-1), m_sortOrder(Qt::AscendingOrder) { // non unique default name, set translation context as default this->setObjectName(translationContext); } + template + CListModelBase::CListModelBase(const QString &translationContext, QObject *parent) + : CListModelBaseNonTemplate(translationContext, parent) + { } + template int CListModelBase::rowCount(const QModelIndex &parentIndex) const { diff --git a/src/blackgui/models/listmodelbase.h b/src/blackgui/models/listmodelbase.h index 4ba5c62c7..8e9ce60c2 100644 --- a/src/blackgui/models/listmodelbase.h +++ b/src/blackgui/models/listmodelbase.h @@ -16,7 +16,7 @@ #include "blackgui/models/columns.h" #include "blackgui/models/modelfilter.h" #include "blackmisc/worker.h" -#include +#include #include #include #include @@ -27,7 +27,7 @@ namespace BlackGui namespace Models { //! Non templated base class, allows Q_OBJECT and signals to be used - class BLACKGUI_EXPORT CListModelBaseNonTemplate : public QAbstractItemModel + class BLACKGUI_EXPORT CListModelBaseNonTemplate : public QStandardItemModel { Q_OBJECT @@ -38,16 +38,16 @@ namespace BlackGui //! Destructor virtual ~CListModelBaseNonTemplate() {} - //! \copydoc QAbstractItemModel::columnCount() + //! \copydoc QStandardItemModel::columnCount() virtual int columnCount(const QModelIndex &modelIndex = QModelIndex()) const override; - //! \copydoc QAbstractItemModel::headerData() + //! \copydoc QStandardItemModel::headerData() virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - //! \copydoc QAbstractItemModel::headerData() + //! \copydoc QStandardItemModel::headerData() virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; - //! \copydoc QAbstractItemModel::parent() + //! \copydoc QStandardItemModel::parent() virtual QModelIndex parent(const QModelIndex &child) const override; //! Column to property index @@ -78,16 +78,16 @@ namespace BlackGui //! Translation context virtual const QString &getTranslationContext() const; - //! \copydoc QAbstractItemModel::flags + //! \copydoc QStandardItemModel::flags virtual Qt::ItemFlags flags(const QModelIndex &index) const override; - //! \copydoc QAbstractItemModel::supportedDragActions + //! \copydoc QStandardItemModel::supportedDragActions virtual Qt::DropActions supportedDragActions() const override; - //! \copydoc QAbstractItemModel::supportedDropActions + //! \copydoc QStandardItemModel::supportedDropActions virtual Qt::DropActions supportedDropActions() const override; - //! \copydoc QAbstractItemModel::supportedDropActions + //! \copydoc QStandardItemModel::supportedDropActions virtual QStringList mimeTypes() const override; //! Mark as about to be destroyed, normally marked from view @@ -140,14 +140,14 @@ namespace BlackGui //! Used container data const ContainerType &container() const; - //! \copydoc QAbstractItemModel::data() + //! \copydoc QStandardItemModel::data() virtual QVariant data(const QModelIndex &index, int role) const override; - //! \copydoc QAbstractItemModel::setData() + //! \copydoc QStandardItemModel::setData() //! \sa CListModelBaseNonTemplate::flags virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - //! \copydoc QAbstractItemModel::rowCount() + //! \copydoc QStandardItemModel::rowCount() virtual int rowCount(const QModelIndex &parentIndex = QModelIndex()) const override; //! Update by new container @@ -172,7 +172,7 @@ namespace BlackGui //! Sort by given sort order \sa getSortColumn() \sa getSortOrder() void sort(); - //! \copydoc QAbstractItemModel::sort() + //! \copydoc QStandardItemModel::sort() virtual void sort(int column, Qt::SortOrder order) override; //! Truncate to given number @@ -211,7 +211,7 @@ namespace BlackGui //! Empty? virtual bool isEmpty() const; - //! \copydoc QAbstractItemModel::mimeData + //! \copydoc QStandardItemModel::mimeData virtual QMimeData *mimeData(const QModelIndexList &indexes) const override; //! Filter available @@ -227,9 +227,7 @@ namespace BlackGui std::unique_ptr > m_filter; //!< Used filter //! \copydoc CListModelBaseNonTemplate::CListModelBaseNonTemplate - CListModelBase(const QString &translationContext, QObject *parent = nullptr) - : CListModelBaseNonTemplate(translationContext, parent) - { } + CListModelBase(const QString &translationContext, QObject *parent = nullptr); //! \copydoc CModelBaseNonTemplate::performUpdateContainer virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort) override; diff --git a/src/blackgui/models/modelswithdbkey.cpp b/src/blackgui/models/modelswithdbkey.cpp new file mode 100644 index 000000000..490c3e64b --- /dev/null +++ b/src/blackgui/models/modelswithdbkey.cpp @@ -0,0 +1,52 @@ +/* Copyright (C) 2015 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "modelswithdbkey.h" +#include "allmodelcontainers.h" + +namespace BlackGui +{ + namespace Models + { + template + CModelsWithDbKeysBase::CModelsWithDbKeysBase(const QString &translationContext, QObject *parent) : + CListModelBase(translationContext, parent) + { } + + template + QVariant CModelsWithDbKeysBase::data(const QModelIndex &index, int role) const + { + if (role == Qt::BackgroundRole) + { + if (isHighlightIndex(index)) { return QBrush(m_highlightColor); } + } + return CListModelBase::data(index, role); + } + + template + KeyType CModelsWithDbKeysBase::dbKeyForIndex(const QModelIndex &index) const + { + if (!index.isValid()) { return ObjectType::invalidDbKey(); } + return this->at(index).getDbKey(); + } + + template + bool CModelsWithDbKeysBase::isHighlightIndex(const QModelIndex &index) const + { + if (!index.isValid()) { return false; } + if (m_highlightIntKeys.isEmpty()) { return false; } + return m_highlightIntKeys.contains(dbKeyForIndex(index)); + } + + // see here for the reason of thess forward instantiations + // http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html + template class CModelsWithDbKeysBase; + + } // namespace +} // namespace diff --git a/src/blackgui/models/modelswithdbkey.h b/src/blackgui/models/modelswithdbkey.h new file mode 100644 index 000000000..f8ae3e106 --- /dev/null +++ b/src/blackgui/models/modelswithdbkey.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2015 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKGUI_MODELSWITHDBKEY_H +#define BLACKGUI_MODELSWITHDBKEY_H + +#include "listmodelbase.h" + +namespace BlackGui +{ + namespace Models + { + //! Base class for models with DB keys + template + class CModelsWithDbKeysBase : public CListModelBase + { + public: + //! Destructor + virtual ~CModelsWithDbKeysBase() {} + + //! Keys to be highlighted + void setHighlightDbKeys(const QList &keys) { m_highlightIntKeys = keys; } + + //! Set color for highlighting + void setHighlightColor(QColor color) { m_highlightColor = color; } + + //! \copydoc CListModelBase::data + virtual QVariant data(const QModelIndex &index, int role) const override; + + //! DB key for given index + KeyType dbKeyForIndex(const QModelIndex &index) const; + + //! Highlight index + bool isHighlightIndex(const QModelIndex &index) const; + + protected: + //! \copydoc CListModelBase::CListModelBase + CModelsWithDbKeysBase(const QString &translationContext, QObject *parent = nullptr); + + private: + QList m_highlightIntKeys; //!< keys to be highlighted + QColor m_highlightColor = Qt::green; + }; + } // namespace +} // namespace +#endif // guard diff --git a/src/blackgui/views/aircraftmodelview.cpp b/src/blackgui/views/aircraftmodelview.cpp index 48df9ff3c..36ca57295 100644 --- a/src/blackgui/views/aircraftmodelview.cpp +++ b/src/blackgui/views/aircraftmodelview.cpp @@ -30,64 +30,46 @@ namespace BlackGui QWidget *mainWindow = this->mainApplicationWindowWidget(); Q_ASSERT_X(mainWindow, Q_FUNC_INFO, "no main window found"); this->setFilterDialog(new CAircraftModelFilterDialog(mainWindow)); + + // default mode + CAircraftModelListModel::AircraftModelMode mode = derivedModel()->getModelMode(); + this->setAircraftModelMode(mode); } void CAircraftModelView::setAircraftModelMode(CAircraftModelListModel::AircraftModelMode mode) { - if (mode == CAircraftModelListModel::Database) - { - this->m_withMenuItemClear = false; - this->m_withMenuItemRefresh = false; - this->m_withMenuItemBackend = true; - } - else if (mode == CAircraftModelListModel::OwnSimulatorModel) - { - this->m_withMenuItemClear = false; - this->m_withMenuItemRefresh = false; - this->m_withMenuItemBackend = true; - } - else if (mode == CAircraftModelListModel::VPilotRuleModel) + this->m_withMenuDisplayAutomatically = false; + this->setCustomMenu(nullptr, false); // delete everything + switch (mode) { + case CAircraftModelListModel::StashModel: this->m_withMenuItemClear = true; this->m_withMenuItemRefresh = false; this->m_withMenuItemBackend = false; - } - else - { - this->m_withMenuItemClear = true; - this->m_withMenuItemRefresh = true; + this->setCustomMenu(new CHighlightDbModelsMenu(this, true)); + break; + case CAircraftModelListModel::Database: + this->m_withMenuItemClear = false; + this->m_withMenuItemRefresh = false; this->m_withMenuItemBackend = true; + break; + case CAircraftModelListModel::VPilotRuleModel: + this->m_withMenuItemClear = false; + this->m_withMenuItemRefresh = false; + this->m_withMenuItemBackend = false; + this->setCustomMenu(new CHighlightDbModelsMenu(this, true)); + this->setCustomMenu(new CHighlightStashedModelsMenu(this, true)); + break; + case CAircraftModelListModel::OwnSimulatorModel: + default: + this->m_withMenuDisplayAutomatically = true; + this->m_withMenuItemClear = false; + this->m_withMenuItemRefresh = false; + this->m_withMenuItemBackend = false; + this->setCustomMenu(new CHighlightDbModelsMenu(this, true)); + this->setCustomMenu(new CHighlightStashedModelsMenu(this, true)); + break; } - this->m_model->setAircraftModelMode(mode); - } - - bool CAircraftModelView::displayAutomatically() const - { - return m_displayAutomatically; - } - - void CAircraftModelView::customMenu(QMenu &menu) const - { - CAircraftModelListModel::AircraftModelMode mode = this->m_model->getModelMode(); - if (mode == CAircraftModelListModel::VPilotRuleModel || mode == CAircraftModelListModel::OwnSimulatorModel) - { - QAction *a = menu.addAction(CIcons::appMappings16(), "Automatically display", this, SLOT(ps_toggleAutoDisplay())); - a->setCheckable(true); - a->setChecked(m_displayAutomatically); - menu.addSeparator(); - a = menu.addAction(CIcons::database16(), "Highlight DB items", this, SLOT(ps_toggleHighlightDbModels())); - a->setCheckable(true); - a->setChecked(derivedModel()->highlightDbData()); - } - CViewBase::customMenu(menu); - } - - void CAircraftModelView::ps_toggleAutoDisplay() - { - QAction *a = qobject_cast(QObject::sender()); - if (!a) { return; } - Q_ASSERT_X(a->isCheckable(), Q_FUNC_INFO, "object not checkable"); - this->m_displayAutomatically = a->isChecked(); } void CAircraftModelView::ps_toggleHighlightDbModels() @@ -96,5 +78,31 @@ namespace BlackGui derivedModel()->setHighlightDbData(!h); } + void CAircraftModelView::ps_toggleHighlightStashedModels() + { + bool h = derivedModel()->highlightStashedModels(); + derivedModel()->setHighlightStashedModels(!h); + } + + void CAircraftModelView::CHighlightDbModelsMenu::customMenu(QMenu &menu) const + { + const CAircraftModelView *mv = qobject_cast(parent()); + Q_ASSERT_X(mv, Q_FUNC_INFO, "no view"); + QAction *a = menu.addAction(CIcons::database16(), "Highlight DB models", mv, SLOT(ps_toggleHighlightDbModels())); + a->setCheckable(true); + a->setChecked(mv->derivedModel()->highlightDbData()); + this->nestedCustomMenu(menu); + } + + void CAircraftModelView::CHighlightStashedModelsMenu::customMenu(QMenu &menu) const + { + const CAircraftModelView *mv = qobject_cast(parent()); + Q_ASSERT_X(mv, Q_FUNC_INFO, "no view"); + QAction *a = menu.addAction(CIcons::appDbStash16(), "Highlight stashed models", mv, SLOT(ps_toggleHighlightStashedModels())); + a->setCheckable(true); + a->setChecked(mv->derivedModel()->highlightStashedModels()); + this->nestedCustomMenu(menu); + } + } // namespace } // namespace diff --git a/src/blackgui/views/aircraftmodelview.h b/src/blackgui/views/aircraftmodelview.h index bf5a4ed94..11de20d97 100644 --- a/src/blackgui/views/aircraftmodelview.h +++ b/src/blackgui/views/aircraftmodelview.h @@ -34,29 +34,39 @@ namespace BlackGui //! Set display mode void setAircraftModelMode(Models::CAircraftModelListModel::AircraftModelMode mode); - //! Display automatically (when models are loaded) - bool displayAutomatically() const; - - //! Display automatically (when models are loaded) - void setDisplayAutomatically(bool automatically) { m_displayAutomatically = automatically; } - signals: //! Request to load VPilot data void requestVPilotRules(); - protected: - //! \copydoc CViewBase::customMenu - virtual void customMenu(QMenu &menu) const override; - private slots: - //! Toggle auto display - void ps_toggleAutoDisplay(); - //! Highlight DB models void ps_toggleHighlightDbModels(); + //! Highlight stashed models + void ps_toggleHighlightStashedModels(); + private: - bool m_displayAutomatically = false; //!< display automatically (when models are loaded) + //! Custom menu for the models which have been loaded + class CHighlightDbModelsMenu : public BlackGui::IMenuDelegate + { + public: + //! Constructor + CHighlightDbModelsMenu(CAircraftModelView *parent, bool separatorAtEnd) : IMenuDelegate(parent, separatorAtEnd) {} + + //! \copydoc IMenuDelegate::customMenu + virtual void customMenu(QMenu &menu) const override; + }; + + //! Custom menu for the models which have been loaded + class CHighlightStashedModelsMenu : public BlackGui::IMenuDelegate + { + public: + //! Constructor + CHighlightStashedModelsMenu(CAircraftModelView *parent, bool separatorAtEnd) : IMenuDelegate(parent, separatorAtEnd) {} + + //! \copydoc IMenuDelegate::customMenu + virtual void customMenu(QMenu &menu) const override; + }; }; } // ns } // ns diff --git a/src/blackgui/views/viewbase.cpp b/src/blackgui/views/viewbase.cpp index 6f464e955..a0fc11eb0 100644 --- a/src/blackgui/views/viewbase.cpp +++ b/src/blackgui/views/viewbase.cpp @@ -87,9 +87,24 @@ namespace BlackGui } } - void CViewBaseNonTemplate::setCustomMenu(IMenuDelegate *menu) + void CViewBaseNonTemplate::setCustomMenu(IMenuDelegate *menu, bool nestPreviousMenu) { - this->m_menu = menu; + if (menu && nestPreviousMenu) + { + // new menu with nesting + menu->setNestedDelegate(this->m_menu); + m_menu = menu; + } + else if (!menu && nestPreviousMenu) + { + // nested new menu + m_menu = m_menu->getNestedDelegate(); + } + else + { + // no nesting + m_menu = menu; + } } void CViewBaseNonTemplate::enableLoadIndicator(bool enable) @@ -123,9 +138,18 @@ namespace BlackGui if (this->m_menu) { this->m_menu->customMenu(menu); } // standard menus + bool withStandardMenu = this->m_withMenuItemRefresh || this->m_withMenuItemBackend || this->m_withMenuItemClear || this->m_withMenuDisplayAutomatically; if (this->m_withMenuItemRefresh) { menu.addAction(BlackMisc::CIcons::refresh16(), "Update", this, SIGNAL(requestUpdate())); } if (this->m_withMenuItemBackend) { menu.addAction(BlackMisc::CIcons::refresh16(), "Reload from backend", this, SIGNAL(requestNewBackendData())); } if (this->m_withMenuItemClear) { menu.addAction(BlackMisc::CIcons::delete16(), "Clear", this, SLOT(ps_clear())); } + if (this->m_withMenuDisplayAutomatically) + { + QAction *a = menu.addAction(CIcons::appMappings16(), "Automatically display (when loaded)", this, SLOT(ps_toggleAutoDisplay())); + a->setCheckable(true); + a->setChecked(this->displayAutomatically()); + } + if (withStandardMenu) { menu.addSeparator(); } + if (this->m_withMenuFilter) { menu.addAction(BlackMisc::CIcons::tableSheet16(), "Filter", this, SLOT(ps_displayFilterDialog())); @@ -205,6 +229,22 @@ namespace BlackGui return this->selectionModel()->selectedRows(); } + int CViewBaseNonTemplate::selectedRowsCount() const + { + if (!this->hasSelection()) { return 0;} + return this->selectedRows().count(); + } + + bool CViewBaseNonTemplate::hasSingleSelectedRow() const + { + return this->selectedRowsCount() == 1; + } + + bool CViewBaseNonTemplate::hasMultipleSelectedRows() const + { + return this->selectedRowsCount() > 1; + } + void CViewBaseNonTemplate::init() { int fh = qRound(1.5 * this->getHorizontalHeaderFontHeight()); @@ -347,6 +387,14 @@ namespace BlackGui } } + void CViewBaseNonTemplate::ps_toggleAutoDisplay() + { + QAction *a = qobject_cast(QObject::sender()); + if (!a) { return; } + Q_ASSERT_X(a->isCheckable(), Q_FUNC_INFO, "object not checkable"); + this->m_displayAutomatically = a->isChecked(); + } + void CViewBaseNonTemplate::ps_updatedIndicator() { this->update(); @@ -448,10 +496,10 @@ namespace BlackGui } template - const ContainerType &CViewBase::getContainer() const + const ContainerType &CViewBase::container() const { Q_ASSERT(this->m_model); - return this->m_model->getContainer(); + return this->m_model->container(); } template @@ -474,6 +522,31 @@ namespace BlackGui return c.frontOrDefault(); } + template + int CViewBase::removeSelectedRows() + { + if (!this->hasSelection()) { return 0; } + if (this->isEmpty()) { return 0; } + + int currentRows = this->rowCount(); + if (currentRows == selectedRowsCount()) + { + this->clear(); + return currentRows; + } + + ContainerType selected(selectedObjects()); + ContainerType newObjects(container()); + for (const ObjectType &obj : selected) + { + newObjects.remove(obj); + } + + int delta = currentRows - newObjects.size(); + this->updateContainerMaybeAsync(newObjects); + return delta; + } + template int CViewBase::rowCount() const { diff --git a/src/blackgui/views/viewbase.h b/src/blackgui/views/viewbase.h index 30ceadbcf..ed157a7f7 100644 --- a/src/blackgui/views/viewbase.h +++ b/src/blackgui/views/viewbase.h @@ -83,6 +83,12 @@ namespace BlackGui //! In \sa ResizingAuto mode, how often to update. "1" updates every time, "2" every 2nd time, .. void setAutoResizeFrequency(int updateEveryNthTime) { this->m_resizeAutoNthTime = updateEveryNthTime; } + //! Display automatically (when models are loaded) + bool displayAutomatically() const { return m_displayAutomatically; } + + //! Display automatically (when models are loaded) + void setDisplayAutomatically(bool automatically) { m_displayAutomatically = automatically; } + //! Header (horizontal) font const QFont &getHorizontalHeaderFont() const { Q_ASSERT(this->horizontalHeader()); return this->horizontalHeader()->font(); } @@ -95,6 +101,15 @@ namespace BlackGui //! Selected rows if any QModelIndexList selectedRows() const; + //! Number of selected rows + int selectedRowsCount() const; + + //! Single selected row + bool hasSingleSelectedRow() const; + + //! Multiple selected rows + bool hasMultipleSelectedRows() const; + //! Filter dialog void setFilterDialog(BlackGui::Filters::CFilterDialog *filterDialog); @@ -102,7 +117,7 @@ namespace BlackGui void setFilterWidget(BlackGui::Filters::CFilterWidget *filterDialog); //! Set custom menu if applicable - void setCustomMenu(BlackGui::IMenuDelegate *menu); + void setCustomMenu(BlackGui::IMenuDelegate *menu, bool nestPreviousMenu = true); //! Enable loading indicator void enableLoadIndicator(bool enable); @@ -126,12 +141,12 @@ namespace BlackGui //! Ask for new data from currently loaded data void requestUpdate(); - //! Load indicator's visibility has been changed - void loadIndicatorVisibilityChanged(bool visible); - //! Load data from backend (where it makes sense) void requestNewBackendData(); + //! Load indicator's visibility has been changed + void loadIndicatorVisibilityChanged(bool visible); + //! Asynchronous update finished void asyncUpdateFinished(); @@ -210,17 +225,20 @@ namespace BlackGui int m_skipResizeThreshold = 40; //!< when to skip resize (rows count) int m_resizeAutoNthTime = 1; //!< with ResizeAuto, resize every n-th time bool m_forceStretchLastColumnWhenResized = false; //!< a small table might (few columns) might to fail stretching, force again - bool m_withMenuItemClear = false; //!< allow clearing the view via menu - bool m_withMenuItemRefresh = false; //!< allow refreshing the view via menu - bool m_withMenuItemBackend = false; //!< allow to request data from backend - bool m_withMenuFilter = false; //!< filter can be opened - bool m_showingLoadIndicator = false; //!< showing loading indicator - bool m_enabledLoadIndicator = true; //!< loading indicator enabled/disabled - bool m_acceptClickSelection = false; //!< clicked - bool m_acceptRowSelected = false; //!< selection changed - bool m_acceptDoubleClickSelection = false; //!< double clicked + bool m_withMenuItemClear = false; //!< allow clearing the view via menu + bool m_withMenuItemRefresh = false; //!< allow refreshing the view via menu + bool m_withMenuItemBackend = false; //!< allow to request data from backend + bool m_withMenuDisplayAutomatically = false; //!< allow to switch display automatically + bool m_withMenuFilter = false; //!< filter can be opened + bool m_showingLoadIndicator = false; //!< showing loading indicator + bool m_enabledLoadIndicator = true; //!< loading indicator enabled/disabled + bool m_acceptClickSelection = false; //!< clicked + bool m_acceptRowSelected = false; //!< selection changed + bool m_acceptDoubleClickSelection = false; //!< double clicked + bool m_displayAutomatically = true; //!< display directly when loaded + QWidget *m_filterWidget = nullptr; //!< filter widget if any - BlackGui::IMenuDelegate *m_menu = nullptr; //!< custom menu if any + BlackGui::IMenuDelegate *m_menu = nullptr; //!< custom menu if any BlackGui::CLoadIndicator *m_loadIndicator = nullptr; //!< load indicator if neeeded protected slots: @@ -258,6 +276,9 @@ namespace BlackGui //! Indicator has been updated void ps_updatedIndicator(); + //! Toggle auto display flag + void ps_toggleAutoDisplay(); + //! Clear the model virtual void ps_clear() { this->clear(); } }; @@ -294,7 +315,7 @@ namespace BlackGui const ObjectType &at(const QModelIndex &index) const; //! Access to container - const ContainerType &getContainer() const; + const ContainerType &container() const; //! Selected objects ContainerType selectedObjects() const; @@ -302,6 +323,9 @@ namespace BlackGui //! Selected object (or default) ObjectType selectedObject() const; + //! Remove selected rows + int removeSelectedRows(); + //! Row count int rowCount() const;