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.
This commit is contained in:
Nicolas Werner 2019-10-20 12:39:47 +02:00
parent cff46d97a8
commit c37495fae2
7 changed files with 299 additions and 45 deletions

View file

@ -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();
}

View file

@ -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> *);
};

View file

@ -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);