diff options
author | Nicolas Werner <nicolas.werner@hotmail.de> | 2019-10-20 12:39:47 +0200 |
---|---|---|
committer | Nicolas Werner <nicolas.werner@hotmail.de> | 2019-11-23 20:06:15 +0100 |
commit | c37495fae29cd93b1b03e4e3689c604cc5312a18 (patch) | |
tree | 44a9fd5b0eb2c2d459ba122bd8cff739e358e4b7 /src | |
parent | Add native themeing to QML (where possible) (diff) | |
download | nheko-c37495fae29cd93b1b03e4e3689c604cc5312a18.tar.xz |
Use a basic implementation of a DelegateChooser for compat with older Qt
The interface is taken from Qt/KDE, but the implementation is different, because the Qt implementation depends on some Qt internals.
Diffstat (limited to 'src')
-rw-r--r-- | src/timeline2/DelegateChooser.cpp | 160 | ||||
-rw-r--r-- | src/timeline2/DelegateChooser.h | 78 | ||||
-rw-r--r-- | src/timeline2/TimelineViewManager.cpp | 4 |
3 files changed, 242 insertions, 0 deletions
diff --git a/src/timeline2/DelegateChooser.cpp b/src/timeline2/DelegateChooser.cpp new file mode 100644 index 00000000..ddde93e1 --- /dev/null +++ b/src/timeline2/DelegateChooser.cpp @@ -0,0 +1,160 @@ +#include "DelegateChooser.h" + +#include "Logging.h" + +// uses private API, which moved between versions +#include <QQmlEngine> +#include <QtGlobal> +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) +#include <QtQmlModels/private/qqmladaptormodel_p.h> +#else +#include <QtQml/private/qqmladaptormodel_p.h> +#endif + +QQmlComponent * +DelegateChoice::delegate() const +{ + return delegate_; +} + +void +DelegateChoice::setDelegate(QQmlComponent *delegate) +{ + if (delegate != delegate_) { + delegate_ = delegate; + emit delegateChanged(); + emit changed(); + } +} + +QVariant +DelegateChoice::roleValue() const +{ + return roleValue_; +} + +void +DelegateChoice::setRoleValue(const QVariant &value) +{ + if (value != roleValue_) { + roleValue_ = value; + emit roleValueChanged(); + emit changed(); + } +} + +QVariant +DelegateChooser::roleValue() const +{ + return roleValue_; +} + +void +DelegateChooser::setRoleValue(const QVariant &value) +{ + if (value != roleValue_) { + roleValue_ = value; + recalcChild(); + emit roleValueChanged(); + } +} + +QQmlListProperty<DelegateChoice> +DelegateChooser::choices() +{ + return QQmlListProperty<DelegateChoice>(this, + this, + &DelegateChooser::appendChoice, + &DelegateChooser::choiceCount, + &DelegateChooser::choice, + &DelegateChooser::clearChoices); +} + +QString +DelegateChooser::role() const +{ + return role_; +} + +void +DelegateChooser::setRole(const QString &role) +{ + if (role != role_) { + role_ = role; + emit roleChanged(); + } +} + +QQmlComponent * +DelegateChooser::delegate(QQmlAdaptorModel *adaptorModel, int row, int column) const +{ + auto value = adaptorModel->value(adaptorModel->indexAt(row, column), role_); + + for (const auto choice : choices_) { + auto choiceValue = choice->roleValue(); + if (!value.isValid() || choiceValue == value) { + nhlog::ui()->debug("Returned delegate for {}", role_.toStdString()); + return choice->delegate(); + } + } + + nhlog::ui()->debug("Returned null delegate"); + return nullptr; +} + +void +DelegateChooser::appendChoice(QQmlListProperty<DelegateChoice> *p, DelegateChoice *c) +{ + DelegateChooser *dc = static_cast<DelegateChooser *>(p->object); + dc->choices_.append(c); + // dc->recalcChild(); +} + +int +DelegateChooser::choiceCount(QQmlListProperty<DelegateChoice> *p) +{ + return static_cast<DelegateChooser *>(p->object)->choices_.count(); +} +DelegateChoice * +DelegateChooser::choice(QQmlListProperty<DelegateChoice> *p, int index) +{ + return static_cast<DelegateChooser *>(p->object)->choices_.at(index); +} +void +DelegateChooser::clearChoices(QQmlListProperty<DelegateChoice> *p) +{ + static_cast<DelegateChooser *>(p->object)->choices_.clear(); +} + +void +DelegateChooser::recalcChild() +{ + for (const auto choice : choices_) { + auto choiceValue = choice->roleValue(); + if (!roleValue_.isValid() || !choiceValue.isValid() || choiceValue == roleValue_) { + nhlog::ui()->debug("Returned delegate for {}", role_.toStdString()); + + if (child) { + // delete child; + child = nullptr; + } + + child = dynamic_cast<QQuickItem *>( + choice->delegate()->create(QQmlEngine::contextForObject(this))); + child->setParentItem(this); + connect(this->child, &QQuickItem::heightChanged, this, [this]() { + this->setHeight(this->child->height()); + }); + this->setHeight(this->child->height()); + return; + } + } +} + +void +DelegateChooser::componentComplete() +{ + QQuickItem::componentComplete(); + recalcChild(); +} + diff --git a/src/timeline2/DelegateChooser.h b/src/timeline2/DelegateChooser.h new file mode 100644 index 00000000..d2a1cf59 --- /dev/null +++ b/src/timeline2/DelegateChooser.h @@ -0,0 +1,78 @@ +// A DelegateChooser like the one, that was added to Qt5.12 (in labs), but compatible with older Qt versions +// see KDE/kquickitemviews +// see qtdeclarative/qqmldelagatecomponent + +#pragma once + +#include <QQmlComponent> +#include <QQmlListProperty> +#include <QQuickItem> +#include <QtCore/QObject> +#include <QtCore/QVariant> + +class QQmlAdaptorModel; + +class DelegateChoice : public QObject +{ + Q_OBJECT + Q_CLASSINFO("DefaultProperty", "delegate") + +public: + Q_PROPERTY(QVariant roleValue READ roleValue WRITE setRoleValue NOTIFY roleValueChanged) + Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) + + QQmlComponent *delegate() const; + void setDelegate(QQmlComponent *delegate); + + QVariant roleValue() const; + void setRoleValue(const QVariant &value); + +signals: + void delegateChanged(); + void roleValueChanged(); + void changed(); + +private: + QVariant roleValue_; + QQmlComponent *delegate_ = nullptr; +}; + +class DelegateChooser : public QQuickItem +{ + Q_OBJECT + Q_CLASSINFO("DefaultProperty", "choices") + +public: + Q_PROPERTY(QQmlListProperty<DelegateChoice> choices READ choices CONSTANT) + Q_PROPERTY(QString role READ role WRITE setRole NOTIFY roleChanged) + Q_PROPERTY(QVariant roleValue READ roleValue WRITE setRoleValue NOTIFY roleValueChanged) + + QQmlListProperty<DelegateChoice> choices(); + + QString role() const; + void setRole(const QString &role); + + QVariant roleValue() const; + void setRoleValue(const QVariant &value); + + QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = 0) const; + + void recalcChild(); + void componentComplete() override; + +signals: + void roleChanged(); + void roleValueChanged(); + +private: + QString role_; + QVariant roleValue_; + QList<DelegateChoice *> choices_; + QQuickItem *child; + + static void appendChoice(QQmlListProperty<DelegateChoice> *, DelegateChoice *); + static int choiceCount(QQmlListProperty<DelegateChoice> *); + static DelegateChoice *choice(QQmlListProperty<DelegateChoice> *, int index); + static void clearChoices(QQmlListProperty<DelegateChoice> *); +}; + diff --git a/src/timeline2/TimelineViewManager.cpp b/src/timeline2/TimelineViewManager.cpp index 057f03de..a054bc78 100644 --- a/src/timeline2/TimelineViewManager.cpp +++ b/src/timeline2/TimelineViewManager.cpp @@ -8,6 +8,7 @@ #include <QStandardPaths> #include "ChatPage.h" +#include "DelegateChooser.h" #include "Logging.h" #include "MxcImageProvider.h" #include "UserSettingsPage.h" @@ -57,6 +58,9 @@ TimelineViewManager::TimelineViewManager(QWidget *parent) 0, "MtxEvent", "Can't instantiate enum!"); + qmlRegisterType<DelegateChoice>("com.github.nheko", 1, 0, "DelegateChoice"); + qmlRegisterType<DelegateChooser>("com.github.nheko", 1, 0, "DelegateChooser"); + view = new QQuickView(); container = QWidget::createWindowContainer(view, parent); container->setMinimumSize(200, 200); |