Support Qt 5.11 and fix image provider.

This commit is contained in:
Black Hat
2018-07-07 17:38:20 +08:00
parent a850224c98
commit 17fa7cc7da
24 changed files with 666 additions and 808 deletions

View File

@@ -3,51 +3,52 @@
#include "libqmatrixclient/connection.h"
Controller::Controller(QObject *parent) : QObject(parent) {
connect(m_connection, &QMatrixClient::Connection::connected, this, &Controller::connected);
connect(m_connection, &QMatrixClient::Connection::resolveError, this, &Controller::reconnect);
connect(m_connection, &QMatrixClient::Connection::syncError, this, &Controller::reconnect);
connect(m_connection, &QMatrixClient::Connection::syncDone, this, &Controller::resync);
}
Controller::~Controller() {
}
void Controller::login(QString home, QString user, QString pass) {
if(!isLogin) {
if(home.isEmpty()) home = "matrix.org";
void Controller::login() {
if (!isLogin) {
qDebug() << "UserID:" << userID;
qDebug() << "Token:" << token;
qDebug() << "Home:" << home;
m_connection->setHomeserver(QUrl(homeserver));
m_connection->connectWithToken(userID, token, "");
}
}
void Controller::loginWithCredentials(QString serverAddr, QString user, QString pass) {
if(!isLogin) {
qDebug() << "Server:" << serverAddr;
qDebug() << "User:" << user;
qDebug() << "Pass:" << pass;
if(!userID.isEmpty() && !token.isEmpty()) {
qDebug() << "Using token.";
m_connection->connectWithToken(userID, token, "");
} else if(!user.isEmpty() && !pass.isEmpty()) {
if(!user.isEmpty() && !pass.isEmpty()) {
qDebug() << "Using given credential.";
m_connection->connectToServer("@"+user+":"+home, pass, "");
m_connection->setHomeserver(QUrl(serverAddr));
m_connection->connectToServer(user, pass, "");
}
} else {
qDebug() << "You are already logged in.";
}
}
void Controller::setConnection(QMatrixClient::Connection* conn) {
m_connection = conn;
connect(m_connection, &QMatrixClient::Connection::connected, this, &Controller::connected);
connect(m_connection, &QMatrixClient::Connection::resolveError, this, &Controller::reconnect);
connect(m_connection, &QMatrixClient::Connection::syncError, this, &Controller::reconnect);
connect(m_connection, &QMatrixClient::Connection::syncDone, this, &Controller::resync);
emit connectionChanged();
}
void Controller::logout() {
userID = "";
token = "";
qDebug() << "Logging out.";
setUserID("");
setToken("");
setIsLogin(false);
}
void Controller::connected() {
qDebug() << "Logged in.";
setHomeserver(m_connection->homeserver().toString());
setUserID(m_connection->userId());
setToken(m_connection->accessToken());
m_connection->loadState();

View File

@@ -2,9 +2,7 @@
#define CONTROLLER_H
#include <QObject>
#include "libqmatrixclient/connection.h"
#include "roomlistmodel.h"
namespace QMatrixClient {
@@ -15,25 +13,27 @@ class Controller : public QObject
{
Q_OBJECT
Q_PROPERTY(QMatrixClient::Connection *connection READ getConnection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection NOTIFY connectionChanged)
Q_PROPERTY(bool isLogin READ getIsLogin WRITE setIsLogin NOTIFY isLoginChanged)
Q_PROPERTY(QString homeserver READ getHomeserver WRITE setHomeserver NOTIFY homeserverChanged)
Q_PROPERTY(QString userID READ getUserID WRITE setUserID NOTIFY userIDChanged)
Q_PROPERTY(QByteArray token READ getToken WRITE setToken NOTIFY tokenChanged)
Q_PROPERTY(bool busy READ getBusy WRITE setBusy NOTIFY busyChanged)
public:
explicit Controller(QObject *parent = nullptr);
~Controller();
// All the Q_INVOKABLEs.
Q_INVOKABLE void login(QString, QString, QString);
Q_INVOKABLE void login();
Q_INVOKABLE void loginWithCredentials(QString, QString, QString);
Q_INVOKABLE void logout();
// All the non-Q_INVOKABLE functions.
// All the Q_PROPERTYs.
QMatrixClient::Connection* m_connection;
QMatrixClient::Connection* m_connection = new QMatrixClient::Connection();
QMatrixClient::Connection* getConnection() { return m_connection; }
void setConnection(QMatrixClient::Connection* conn);
bool isLogin = false;
bool getIsLogin() { return isLogin; }
@@ -62,6 +62,24 @@ class Controller : public QObject
}
}
QString homeserver;
QString getHomeserver() { return homeserver; }
void setHomeserver(QString n) {
if (n != homeserver) {
homeserver = n;
emit homeserverChanged();
}
}
bool busy = false;
bool getBusy() { return busy; }
void setBusy(bool b) {
if (b != busy) {
busy = b;
emit busyChanged();
}
}
private:
void connected();
void resync();
@@ -72,7 +90,9 @@ class Controller : public QObject
void isLoginChanged();
void userIDChanged();
void tokenChanged();
void homeServerChanged();
void homeserverChanged();
void busyChanged();
void errorOccured();
public slots:
};

View File

@@ -10,13 +10,22 @@
using QMatrixClient::MediaThumbnailJob;
ImageProvider::ImageProvider(QObject *parent)
ImageProviderConnection::ImageProviderConnection(QObject* parent) : QObject(parent) {
}
ImageProviderConnection::~ImageProviderConnection() {
}
ImageProvider::ImageProvider(QObject* parent)
: QQuickImageProvider(QQmlImageProviderBase::Image,
QQmlImageProviderBase::ForceAsynchronousImageLoading)
{
#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
qRegisterMetaType<MediaThumbnailJob*>();
#endif
m_connection = new ImageProviderConnection();
}
QImage ImageProvider::requestImage(const QString& id,
@@ -34,9 +43,10 @@ QImage ImageProvider::requestImage(const QString& id,
MediaThumbnailJob* job = nullptr;
QReadLocker locker(&m_lock);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
QMetaObject::invokeMethod(m_connection,
[=] { return m_connection->getThumbnail(mxcUri, requestedSize); },
[=] { return m_connection->getConnection()->getThumbnail(mxcUri, requestedSize); },
Qt::BlockingQueuedConnection, &job);
#else
QMetaObject::invokeMethod(m_connection, "getThumbnail",
@@ -64,9 +74,3 @@ QImage ImageProvider::requestImage(const QString& id,
return result;
}
void ImageProvider::setConnection(QMatrixClient::Connection* connection)
{
QWriteLocker locker(&m_lock);
m_connection = connection;
}

View File

@@ -3,26 +3,47 @@
#include <QtQuick/QQuickImageProvider>
#include <QtCore/QReadWriteLock>
#include <QObject>
namespace QMatrixClient {
class Connection;
}
#include "libqmatrixclient/connection.h"
class ImageProviderConnection: public QObject
{
Q_OBJECT
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection WRITE setConnection NOTIFY connectionChanged)
public:
explicit ImageProviderConnection(QObject* parent = nullptr);
~ImageProviderConnection();
QMatrixClient::Connection* getConnection() { return m_connection; }
Q_INVOKABLE void setConnection(QMatrixClient::Connection* connection) {
qDebug() << "Connection changed.";
emit connectionChanged();
m_connection = connection;
}
private:
QMatrixClient::Connection* m_connection;
signals:
void connectionChanged();
};
class ImageProvider: public QQuickImageProvider
{
public:
explicit ImageProvider(QObject *parent = nullptr);
explicit ImageProvider(QObject* parent = nullptr);
QImage requestImage(const QString& id, QSize* pSize,
const QSize& requestedSize) override;
void setConnection(QMatrixClient::Connection* connection);
void initializeEngine(QQmlEngine *engine, const char *uri);
ImageProviderConnection* getConnection() { return m_connection; }
private:
QMatrixClient::Connection* m_connection;
QReadWriteLock m_lock;
ImageProviderConnection* m_connection;
};
#endif // IMAGEPROVIDER_H

View File

@@ -23,7 +23,6 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
roles[AuthorRole] = "author";
roles[ContentRole] = "content";
roles[ContentTypeRole] = "contentType";
roles[HighlightRole] = "highlight";
roles[ReadMarkerRole] = "readMarker";
roles[SpecialMarksRole] = "marks";
roles[LongOperationRole] = "progressInfo";
@@ -38,7 +37,7 @@ MessageEventModel::MessageEventModel(QObject* parent)
qRegisterMetaType<QMatrixClient::FileTransferInfo>();
}
void MessageEventModel::changeRoom(MatriqueRoom* room)
void MessageEventModel::changeRoom(QMatrixClient::Room* room)
{
if (room == m_currentRoom)
return;
@@ -114,7 +113,7 @@ inline bool hasValidTimestamp(const QMatrixClient::TimelineItem& ti)
return ti->timestamp().isValid();
}
QDateTime MessageEventModel::makeMessageTimestamp(MatriqueRoom::rev_iter_t baseIt) const
QDateTime MessageEventModel::makeMessageTimestamp(QMatrixClient::Room::rev_iter_t baseIt) const
{
const auto& timeline = m_currentRoom->messageEvents();
auto ts = baseIt->event()->timestamp();
@@ -137,7 +136,7 @@ QDateTime MessageEventModel::makeMessageTimestamp(MatriqueRoom::rev_iter_t baseI
return {};
}
QString MessageEventModel::makeDateString(MatriqueRoom::rev_iter_t baseIt) const
QString MessageEventModel::makeDateString(QMatrixClient::Room::rev_iter_t baseIt) const
{
auto date = makeMessageTimestamp(baseIt).toLocalTime().date();
if (QMatrixClient::SettingsGroup("UI")
@@ -402,9 +401,6 @@ QVariant MessageEventModel::data(const QModelIndex& index, int role) const
}
}
if(role == HighlightRole)
return m_currentRoom->isEventHighlighted(event);
if(role == ReadMarkerRole)
return event->id() == lastReadEventId;

View File

@@ -2,8 +2,7 @@
#define MESSAGEEVENTMODEL_H
#include <QtCore/QAbstractListModel>
#include "matriqueroom.h"
#include "room.h"
class MessageEventModel: public QAbstractListModel
{
@@ -13,7 +12,7 @@ class MessageEventModel: public QAbstractListModel
// has to be re-calculated anyway).
// XXX: A better way would be to make [Room::]Timeline a list model
// itself, leaving only representation of the model to a client.
Q_PROPERTY(MatriqueRoom* room MEMBER m_currentRoom CONSTANT)
Q_PROPERTY(QMatrixClient::Room* room MEMBER m_currentRoom CONSTANT)
public:
enum EventRoles {
@@ -25,7 +24,6 @@ class MessageEventModel: public QAbstractListModel
AuthorRole,
ContentRole,
ContentTypeRole,
HighlightRole,
ReadMarkerRole,
SpecialMarksRole,
LongOperationRole,
@@ -33,7 +31,7 @@ class MessageEventModel: public QAbstractListModel
explicit MessageEventModel(QObject* parent = nullptr);
void changeRoom(MatriqueRoom* room);
void changeRoom(QMatrixClient::Room* room);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
@@ -43,11 +41,11 @@ class MessageEventModel: public QAbstractListModel
void refreshEvent(const QString& eventId);
private:
MatriqueRoom* m_currentRoom;
QMatrixClient::Room* m_currentRoom;
QString lastReadEventId;
QDateTime makeMessageTimestamp(MatriqueRoom::rev_iter_t baseIt) const;
QString makeDateString(MatriqueRoom::rev_iter_t baseIt) const;
QDateTime makeMessageTimestamp(QMatrixClient::Room::rev_iter_t baseIt) const;
QString makeDateString(QMatrixClient::Room::rev_iter_t baseIt) const;
void refreshEventRoles(const QString& eventId, const QVector<int> roles);
};

View File

@@ -1,131 +1,43 @@
#include "roomlistmodel.h"
#include <QtGui/QIcon>
#include "matriqueroom.h"
#include "connection.h"
#include "user.h"
#include <QtGui/QBrush>
#include <QtGui/QColor>
#include <QtCore/QDebug>
RoomListModel::RoomListModel(QObject* parent)
: QAbstractListModel(parent)
{ }
{
m_connection = 0;
}
RoomListModel::~RoomListModel()
{
}
void RoomListModel::setConnection(QMatrixClient::Connection* connection)
{
Q_ASSERT(connection);
using QMatrixClient::Room;
beginResetModel();
m_connection = connection;
connect( connection, &QMatrixClient::Connection::loggedOut,
this, [=]{ deleteConnection(connection); } );
connect( connection, &QMatrixClient::Connection::invitedRoom,
this, &RoomListModel::updateRoom);
connect( connection, &QMatrixClient::Connection::joinedRoom,
this, &RoomListModel::updateRoom);
connect( connection, &QMatrixClient::Connection::leftRoom,
this, &RoomListModel::updateRoom);
connect( connection, &QMatrixClient::Connection::aboutToDeleteRoom,
this, &RoomListModel::deleteRoom);
for( auto r: connection->roomMap() )
doAddRoom(r);
m_rooms.clear();
connect( connection, &QMatrixClient::Connection::newRoom, this, &RoomListModel::addRoom );
for( QMatrixClient::Room* room: connection->roomMap().values() ) {
connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged );
m_rooms.append(room);
}
endResetModel();
}
void RoomListModel::deleteConnection(QMatrixClient::Connection* connection) {
QMatrixClient::Room* RoomListModel::roomAt(int row)
{
return m_rooms.at(row);
}
MatriqueRoom* RoomListModel::roomAt(QModelIndex index) const
void RoomListModel::addRoom(QMatrixClient::Room* room)
{
return m_rooms.at(index.row());
}
QModelIndex RoomListModel::indexOf(MatriqueRoom* room) const
{
return index(m_rooms.indexOf(room), 0);
}
void RoomListModel::updateRoom(QMatrixClient::Room* room,
QMatrixClient::Room* prev)
{
// There are two cases when this method is called:
// 1. (prev == nullptr) adding a new room to the room list
// 2. (prev != nullptr) accepting/rejecting an invitation or inviting to
// the previously left room (in both cases prev has the previous state).
if (prev == room)
{
qCritical() << "RoomListModel::updateRoom: room tried to replace itself";
refresh(static_cast<MatriqueRoom*>(room));
return;
}
if (prev && room->id() != prev->id())
{
qCritical() << "RoomListModel::updateRoom: attempt to update room"
<< room->id() << "to" << prev->id();
// That doesn't look right but technically we still can do it.
}
// Ok, we're through with pre-checks, now for the real thing.
auto* newRoom = static_cast<MatriqueRoom*>(room);
const auto it = std::find_if(m_rooms.begin(), m_rooms.end(),
[=](const MatriqueRoom* r) { return r == prev || r == newRoom; });
if (it != m_rooms.end())
{
const int row = it - m_rooms.begin();
// There's no guarantee that prev != newRoom
if (*it == prev && *it != newRoom)
{
prev->disconnect(this);
m_rooms.replace(row, newRoom);
connectRoomSignals(newRoom);
}
emit dataChanged(index(row), index(row));
}
else
{
beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count());
doAddRoom(newRoom);
endInsertRows();
}
}
void RoomListModel::deleteRoom(QMatrixClient::Room* room)
{
auto i = m_rooms.indexOf(static_cast<MatriqueRoom*>(room));
if (i == -1)
return; // Already deleted, nothing to do
beginRemoveRows(QModelIndex(), i, i);
m_rooms.removeAt(i);
endRemoveRows();
}
void RoomListModel::doAddRoom(QMatrixClient::Room* r)
{
if (auto* room = static_cast<MatriqueRoom*>(r))
{
m_rooms.append(room);
connectRoomSignals(room);
} else
{
qCritical() << "Attempt to add nullptr to the room list";
Q_ASSERT(false);
}
}
void RoomListModel::connectRoomSignals(MatriqueRoom* room)
{
connect(room, &MatriqueRoom::displaynameChanged,
this, [=]{ displaynameChanged(room); } );
connect( room, &MatriqueRoom::unreadMessagesChanged,
this, [=]{ unreadMessagesChanged(room); } );
connect( room, &MatriqueRoom::notificationCountChanged,
this, [=]{ unreadMessagesChanged(room); } );
connect( room, &MatriqueRoom::joinStateChanged,
this, [=]{ refresh(room); });
connect( room, &MatriqueRoom::avatarChanged,
this, [=]{ refresh(room, { Qt::DecorationRole }); });
beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count());
connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged );
m_rooms.append(room);
endInsertRows();
}
int RoomListModel::rowCount(const QModelIndex& parent) const
@@ -145,83 +57,47 @@ QVariant RoomListModel::data(const QModelIndex& index, int role) const
qDebug() << "UserListModel: something wrong here...";
return QVariant();
}
auto room = m_rooms.at(index.row());
using QMatrixClient::JoinState;
switch (role)
QMatrixClient::Room* room = m_rooms.at(index.row());
if( role == Qt::DisplayRole )
{
case Qt::DisplayRole:
return room->displayName();
case Qt::DecorationRole:
{
if(room->avatarUrl().toString() != "") {
qInfo() << "Room avatar:" << room->avatarUrl();
return room->avatarUrl();
} else if(room->users().length() == 2) {
QMatrixClient::User* user = room->users().at(0);
qInfo() << "User avatar:" << user->avatarUrl();
return user->avatarUrl();
}
}
case Qt::StatusTipRole:
{
return room->topic();
}
case Qt::ToolTipRole:
{
int hlCount = room->highlightCount();
auto result = QStringLiteral("<b>%1</b><br>").arg(room->displayName());
result += tr("Main alias: %1<br>").arg(room->canonicalAlias());
result += tr("Members: %1<br>").arg(room->memberCount());
if (hlCount > 0)
result += tr("Unread mentions: %1<br>").arg(hlCount);
result += tr("ID: %1<br>").arg(room->id());
switch (room->joinState())
{
case JoinState::Join:
result += tr("You joined this room");
break;
case JoinState::Leave:
result += tr("You left this room");
break;
default:
result += tr("You were invited into this room");
}
return result;
}
case HasUnreadRole:
return room->hasUnreadMessages();
case HighlightCountRole:
return room->highlightCount();
case JoinStateRole:
return toCString(room->joinState()); // FIXME: better make the enum QVariant-convertible
default:
return QVariant();
return room->displayName();
}
if( role == Qt::ForegroundRole )
{
if( room->highlightCount() > 0 )
return QBrush(QColor("orange"));
return QVariant();
}
if( role == Qt::DecorationRole )
{
if(room->avatarUrl().toString() != "") {
return room->avatarUrl();
}
return QVariant();
}
if (role == Qt::StatusTipRole )
{
return room->topic();
}
return QVariant();
}
void RoomListModel::namesChanged(QMatrixClient::Room* room)
{
int row = m_rooms.indexOf(room);
emit dataChanged(index(row), index(row));
}
void RoomListModel::unreadMessagesChanged(QMatrixClient::Room* room)
{
int row = m_rooms.indexOf(room);
emit dataChanged(index(row), index(row));
}
QHash<int, QByteArray> RoomListModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "name";
roles[Qt::DecorationRole] = "avatar";
roles[Qt::StatusTipRole] = "value";
roles[Qt::StatusTipRole] = "topic";
return roles;
}
void RoomListModel::displaynameChanged(MatriqueRoom* room)
{
refresh(room);
}
void RoomListModel::unreadMessagesChanged(MatriqueRoom* room)
{
refresh(room);
}
void RoomListModel::refresh(MatriqueRoom* room, const QVector<int>& roles)
{
int row = m_rooms.indexOf(room);
if (row == -1)
qCritical() << "Room" << room->id() << "not found in the room list";
else
emit dataChanged(index(row), index(row), roles);
}

View File

@@ -2,55 +2,39 @@
#define ROOMLISTMODEL_H
#include <QtCore/QAbstractListModel>
#include "matriqueroom.h"
namespace QMatrixClient
{
class Connection;
class Room;
}
#include "room.h"
#include "connection.h"
class RoomListModel: public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QMatrixClient::Connection *connection READ getConnection WRITE setConnection)
public:
enum Roles {
HasUnreadRole = Qt::UserRole + 1,
HighlightCountRole, JoinStateRole
};
RoomListModel(QObject* parent=0);
virtual ~RoomListModel();
explicit RoomListModel(QObject* parent = nullptr);
QMatrixClient::Connection* getConnection() { return m_connection; }
QMatrixClient::Connection* getConnection() {return m_connection;}
void setConnection(QMatrixClient::Connection* connection);
void deleteConnection(QMatrixClient::Connection* connection);
MatriqueRoom* roomAt(QModelIndex index) const;
QModelIndex indexOf(MatriqueRoom* room) const;
Q_INVOKABLE QMatrixClient::Room* roomAt(int row);
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
Q_INVOKABLE int rowCount(const QModelIndex& parent=QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role) const override;
QHash<int, QByteArray> roleNames() const;
int rowCount(const QModelIndex& parent) const override;
private slots:
void displaynameChanged(MatriqueRoom* room);
void unreadMessagesChanged(MatriqueRoom* room);
void refresh(MatriqueRoom* room, const QVector<int>& roles = {});
void updateRoom(QMatrixClient::Room* room,
QMatrixClient::Room* prev);
void deleteRoom(QMatrixClient::Room* room);
void namesChanged(QMatrixClient::Room* room);
void unreadMessagesChanged(QMatrixClient::Room* room);
void addRoom(QMatrixClient::Room* room);
private:
QMatrixClient::Connection* m_connection;
QList<MatriqueRoom*> m_rooms;
QList<QMatrixClient::Room*> m_rooms;
void doAddRoom(QMatrixClient::Room* r);
void connectRoomSignals(MatriqueRoom* room);
signals:
void connectionChanged();
};
#endif // ROOMLISTMODEL_H