Skip to content
Snippets Groups Projects
Commit c37495fa authored by Nicolas Werner's avatar Nicolas Werner
Browse files

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.
parent cff46d97
No related branches found
No related tags found
No related merge requests found
...@@ -193,6 +193,7 @@ set(SRC_FILES ...@@ -193,6 +193,7 @@ set(SRC_FILES
# Timeline # Timeline
src/timeline2/TimelineViewManager.cpp src/timeline2/TimelineViewManager.cpp
src/timeline2/TimelineModel.cpp src/timeline2/TimelineModel.cpp
src/timeline2/DelegateChooser.cpp
#src/timeline/TimelineViewManager.cpp #src/timeline/TimelineViewManager.cpp
#src/timeline/TimelineItem.cpp #src/timeline/TimelineItem.cpp
#src/timeline/TimelineView.cpp #src/timeline/TimelineView.cpp
...@@ -338,6 +339,7 @@ qt5_wrap_cpp(MOC_HEADERS ...@@ -338,6 +339,7 @@ qt5_wrap_cpp(MOC_HEADERS
# Timeline # Timeline
src/timeline2/TimelineViewManager.h src/timeline2/TimelineViewManager.h
src/timeline2/TimelineModel.h src/timeline2/TimelineModel.h
src/timeline2/DelegateChooser.h
#src/timeline/TimelineItem.h #src/timeline/TimelineItem.h
#src/timeline/TimelineView.h #src/timeline/TimelineView.h
#src/timeline/TimelineViewManager.h #src/timeline/TimelineViewManager.h
...@@ -410,6 +412,7 @@ set(COMMON_LIBS ...@@ -410,6 +412,7 @@ set(COMMON_LIBS
Qt5::Concurrent Qt5::Concurrent
Qt5::Multimedia Qt5::Multimedia
Qt5::Qml Qt5::Qml
Qt5::QmlPrivate
Qt5::QuickControls2 Qt5::QuickControls2
nlohmann_json::nlohmann_json) nlohmann_json::nlohmann_json)
......
import QtQuick 2.6
import Qt.labs.qmlmodels 1.0
import com.github.nheko 1.0
import "./delegates"
DelegateChooser {
role: "type"
width: chat.width
roleValue: model.type
DelegateChoice {
roleValue: MtxEvent.TextMessage
TimelineRow { view: chat; TextMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.NoticeMessage
TimelineRow { view: chat; NoticeMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.EmoteMessage
TimelineRow { view: chat; TextMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.ImageMessage
TimelineRow { view: chat; ImageMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.Sticker
TimelineRow { view: chat; ImageMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.FileMessage
TimelineRow { view: chat; FileMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.VideoMessage
TimelineRow { view: chat; PlayableMediaMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.AudioMessage
TimelineRow { view: chat; PlayableMediaMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.Redacted
TimelineRow { view: chat; Redacted { id: kid } }
}
DelegateChoice {
//roleValue: MtxEvent.Redacted
TimelineRow { view: chat; Placeholder { id: kid } }
}
}
...@@ -3,7 +3,6 @@ import QtQuick.Controls 2.1 ...@@ -3,7 +3,6 @@ import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2 import QtQuick.Layouts 1.2
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtQuick.Window 2.2 import QtQuick.Window 2.2
import Qt.labs.qmlmodels 1.0
import com.github.nheko 1.0 import com.github.nheko 1.0
...@@ -91,50 +90,7 @@ Rectangle { ...@@ -91,50 +90,7 @@ Rectangle {
onMovementEnded: updatePosition() onMovementEnded: updatePosition()
spacing: 4 spacing: 4
delegate: DelegateChooser { delegate: RowDelegateChooser {}
role: "type"
DelegateChoice {
roleValue: MtxEvent.TextMessage
TimelineRow { view: chat; TextMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.NoticeMessage
TimelineRow { view: chat; NoticeMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.EmoteMessage
TimelineRow { view: chat; TextMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.ImageMessage
TimelineRow { view: chat; ImageMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.Sticker
TimelineRow { view: chat; ImageMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.FileMessage
TimelineRow { view: chat; FileMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.VideoMessage
TimelineRow { view: chat; PlayableMediaMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.AudioMessage
TimelineRow { view: chat; PlayableMediaMessage { id: kid } }
}
DelegateChoice {
roleValue: MtxEvent.Redacted
TimelineRow { view: chat; Redacted { id: kid } }
}
DelegateChoice {
//roleValue: MtxEvent.Redacted
TimelineRow { view: chat; Placeholder { id: kid } }
}
}
section { section {
property: "section" property: "section"
......
...@@ -116,6 +116,7 @@ ...@@ -116,6 +116,7 @@
</qresource> </qresource>
<qresource prefix="/"> <qresource prefix="/">
<file>qml/TimelineView.qml</file> <file>qml/TimelineView.qml</file>
<file>qml/RowDelegateChooser.qml</file>
<file>qml/Avatar.qml</file> <file>qml/Avatar.qml</file>
<file>qml/StatusIndicator.qml</file> <file>qml/StatusIndicator.qml</file>
<file>qml/EncryptionIndicator.qml</file> <file>qml/EncryptionIndicator.qml</file>
......
#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();
}
// 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> *);
};
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <QStandardPaths> #include <QStandardPaths>
#include "ChatPage.h" #include "ChatPage.h"
#include "DelegateChooser.h"
#include "Logging.h" #include "Logging.h"
#include "MxcImageProvider.h" #include "MxcImageProvider.h"
#include "UserSettingsPage.h" #include "UserSettingsPage.h"
...@@ -57,6 +58,9 @@ TimelineViewManager::TimelineViewManager(QWidget *parent) ...@@ -57,6 +58,9 @@ TimelineViewManager::TimelineViewManager(QWidget *parent)
0, 0,
"MtxEvent", "MtxEvent",
"Can't instantiate enum!"); "Can't instantiate enum!");
qmlRegisterType<DelegateChoice>("com.github.nheko", 1, 0, "DelegateChoice");
qmlRegisterType<DelegateChooser>("com.github.nheko", 1, 0, "DelegateChooser");
view = new QQuickView(); view = new QQuickView();
container = QWidget::createWindowContainer(view, parent); container = QWidget::createWindowContainer(view, parent);
container->setMinimumSize(200, 200); container->setMinimumSize(200, 200);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment