mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 04:28:49 +03:00
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:
parent
cff46d97a8
commit
c37495fae2
7 changed files with 299 additions and 45 deletions
|
@ -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
|
||||||
# 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
|
||||||
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)
|
||||||
|
|
||||||
|
|
52
resources/qml/RowDelegateChooser.qml
Normal file
52
resources/qml/RowDelegateChooser.qml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
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
|
||||||
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 {
|
||||||
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 @@
|
||||||
</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>
|
||||||
|
|
160
src/timeline2/DelegateChooser.cpp
Normal file
160
src/timeline2/DelegateChooser.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
78
src/timeline2/DelegateChooser.h
Normal file
78
src/timeline2/DelegateChooser.h
Normal 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> *);
|
||||||
|
};
|
||||||
|
|
|
@ -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)
|
||||||
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);
|
||||||
|
|
Loading…
Reference in a new issue