[vlc-devel] [RFC 32/82] qt: provide helper class to build menus
Pierre Lamot
pierre at videolabs.io
Fri Feb 1 14:01:36 CET 2019
---
modules/gui/qt/components/custom_menus.cpp | 119 +++++++++++++++++++++
modules/gui/qt/components/custom_menus.hpp | 54 ++++++++++
2 files changed, 173 insertions(+)
diff --git a/modules/gui/qt/components/custom_menus.cpp b/modules/gui/qt/components/custom_menus.cpp
index 232a7aea7a..ff9c596bb0 100644
--- a/modules/gui/qt/components/custom_menus.cpp
+++ b/modules/gui/qt/components/custom_menus.cpp
@@ -35,6 +35,9 @@
#include <QVBoxLayout>
#include <QLabel>
#include <QProgressBar>
+#include <QMetaObject>
+#include <QMetaProperty>
+#include <QMetaMethod>
RendererAction::RendererAction( vlc_renderer_item_t *p_item_ )
: QAction()
@@ -196,3 +199,119 @@ void RendererMenu::RendererSelected(QAction *action)
else
RendererManager::getInstance( p_intf )->SelectRenderer( NULL );
}
+
+/* CheckableListMenu */
+
+CheckableListMenu::CheckableListMenu(QString title, QAbstractListModel* model , QWidget *parent)
+ : QMenu(parent)
+ , m_model(model)
+{
+ this->setTitle(title);
+ m_actionGroup = new QActionGroup( this );
+
+ connect(m_model, &QAbstractListModel::rowsAboutToBeRemoved, this, &CheckableListMenu::onRowsAboutToBeRemoved);
+ connect(m_model, &QAbstractListModel::rowsInserted, this, &CheckableListMenu::onRowInserted);
+ connect(m_model, &QAbstractListModel::dataChanged, this, &CheckableListMenu::onDataChanged);
+ connect(m_model, &QAbstractListModel::modelAboutToBeReset, this, &CheckableListMenu::onModelAboutToBeReset);
+ connect(m_model, &QAbstractListModel::modelReset, this, &CheckableListMenu::onModelReset);
+ onModelReset();
+}
+
+void CheckableListMenu::onRowsAboutToBeRemoved(const QModelIndex &, int first, int last)
+{
+ for (int i = last; i >= first; i--)
+ {
+ QAction* action = actions()[i];
+ delete action;
+ }
+ if (actions().count() == 0)
+ setEnabled(false);
+}
+
+void CheckableListMenu::onRowInserted(const QModelIndex &, int first, int last)
+{
+ for (int i = first; i <= last; i++)
+ {
+ QModelIndex index = m_model->index(i);
+ QString title = m_model->data(index, Qt::DisplayRole).toString();
+ bool checked = m_model->data(index, Qt::CheckStateRole).toBool();
+
+ QAction *choiceAction = new QAction(title, this);
+ m_actionGroup->addAction(choiceAction);
+ addAction(choiceAction);
+ connect(choiceAction, &QAction::triggered, [this, i](bool checked){
+ QModelIndex dataIndex = m_model->index(i);
+ m_model->setData(dataIndex, QVariant::fromValue<bool>(checked), Qt::CheckStateRole);
+ });
+ choiceAction->setCheckable(true);
+ choiceAction->setChecked(checked);
+ setEnabled(true);
+ }
+}
+
+void CheckableListMenu::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> & )
+{
+ for (int i = topLeft.row(); i <= bottomRight.row(); i++)
+ {
+ if (i >= actions().size())
+ break;
+ QAction *choiceAction = actions()[i];
+
+ QModelIndex index = m_model->index(i);
+ QString title = m_model->data(index, Qt::DisplayRole).toString();
+ bool checked = m_model->data(index, Qt::CheckStateRole).toBool();
+
+ choiceAction->setText(title);
+ choiceAction->setChecked(checked);
+ }
+}
+
+void CheckableListMenu::onModelAboutToBeReset()
+{
+ for (QAction* action :actions())
+ delete action;
+ setEnabled(false);
+}
+
+void CheckableListMenu::onModelReset()
+{
+ int nb_rows = m_model->rowCount();
+ if (nb_rows == 0)
+ setEnabled(false);
+ else
+ onRowInserted({}, 0, nb_rows - 1);
+}
+
+/* BooleanPropertyAction */
+
+BooleanPropertyAction::BooleanPropertyAction(QString title, QObject *model, QString propertyName, QWidget *parent)
+ : QAction(parent)
+ , m_model(model)
+ , m_propertyName(propertyName)
+{
+ setText(title);
+ assert(model);
+ const QMetaObject* meta = model->metaObject();
+ int propertyId = meta->indexOfProperty(qtu(propertyName));
+ assert(propertyId != -1);
+ QMetaProperty property = meta->property(propertyId);
+ assert(property.type() == QVariant::Bool);
+ const QMetaObject* selfMeta = this->metaObject();
+ if (property.hasNotifySignal())
+ {
+ QMetaMethod checkedSlot = selfMeta->method(selfMeta->indexOfSlot( "setChecked(bool)" ));
+ connect( model, property.notifySignal(), this, checkedSlot );
+ connect( this, &BooleanPropertyAction::toggled, this, &BooleanPropertyAction::setModelChecked );
+ setCheckable(true);
+ }
+ else
+ {
+ connect( this, &BooleanPropertyAction::triggered, this, &BooleanPropertyAction::setModelChecked );
+ setCheckable(true);
+ }
+}
+
+void BooleanPropertyAction::setModelChecked(bool checked)
+{
+ m_model->setProperty(qtu(m_propertyName), QVariant::fromValue<bool>(checked) );
+}
diff --git a/modules/gui/qt/components/custom_menus.hpp b/modules/gui/qt/components/custom_menus.hpp
index 45c8c9039c..80316fdc6a 100644
--- a/modules/gui/qt/components/custom_menus.hpp
+++ b/modules/gui/qt/components/custom_menus.hpp
@@ -24,6 +24,7 @@
#include "qt.hpp"
#include <QMenu>
+#include <QAbstractListModel>
class RendererAction : public QAction
{
@@ -64,4 +65,57 @@ private:
};
+/*
+ * Construct a menu from a QAbstractListModel with Qt::DisplayRole and Qt::CheckStateRole
+ */
+class CheckableListMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ /**
+ * @brief CheckableListMenu
+ * @param title the title of the menu
+ * @param model the model to observe, the model should provide at least Qt::DisplayRole and Qt::CheckStateRole
+ * @param parent QObject parent
+ */
+ CheckableListMenu(QString title, QAbstractListModel* model , QWidget *parent = nullptr);
+
+private slots:
+ void onRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
+ void onRowInserted(const QModelIndex &parent, int first, int last);
+ void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
+ void onModelAboutToBeReset();
+ void onModelReset();
+
+private:
+ QAbstractListModel* m_model;
+ QMenu * m_submenu;
+
+ QActionGroup* m_actionGroup;
+};
+
+
+/**
+ * @brief The BooleanPropertyAction class allows to bind a boolean Q_PROPRERTY to a QAction
+ */
+class BooleanPropertyAction: public QAction
+{
+ Q_OBJECT
+public:
+ /**
+ * @brief BooleanPropertyAction
+ * @param title the title of the menu
+ * @param model the object to observe
+ * @param propertyName the name of the property on the @a model
+ * @param parent QObject parent
+ */
+ BooleanPropertyAction(QString title, QObject* model , QString propertyName, QWidget *parent = nullptr);
+
+private slots:
+ void setModelChecked(bool checked);
+private:
+ QObject* m_model;
+ QString m_propertyName;
+};
+
#endif // CUSTOM_MENUS_HPP
--
2.19.1
More information about the vlc-devel
mailing list