aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2017-12-31 08:53:32 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2017-12-31 08:53:32 +0900
commit0b5f0deb773f850d1b905fafc656f67f5b63de24 (patch)
treeb5e0ad5a4558a86d9c95a5d14cc3595e0fa2b5d8
parentcbfe29b3435fbe47fee268facbe6a82000fce0ad (diff)
parent2c440249052b0d518fccd953a7dc657f9eed7ab7 (diff)
downloadlibquotient-0b5f0deb773f850d1b905fafc656f67f5b63de24.tar.gz
libquotient-0b5f0deb773f850d1b905fafc656f67f5b63de24.zip
Merge branch 'master' into kitsune-gtad
-rw-r--r--.travis.yml17
-rw-r--r--CMakeLists.txt16
-rw-r--r--avatar.cpp43
-rw-r--r--avatar.h3
-rw-r--r--connection.cpp35
-rw-r--r--connection.h8
-rw-r--r--connectiondata.cpp32
-rw-r--r--connectiondata.h4
-rw-r--r--events/event.cpp10
-rw-r--r--events/event.h27
-rw-r--r--jobs/basejob.cpp27
-rw-r--r--jobs/basejob.h10
-rw-r--r--jobs/mediathumbnailjob.cpp11
-rw-r--r--jobs/mediathumbnailjob.h6
-rw-r--r--libqmatrixclient.pri11
-rw-r--r--networkaccessmanager.cpp74
-rw-r--r--networkaccessmanager.h49
-rw-r--r--networksettings.cpp31
-rw-r--r--networksettings.h44
-rw-r--r--room.cpp25
-rw-r--r--room.h30
-rw-r--r--settings.cpp32
-rw-r--r--settings.h260
-rw-r--r--user.cpp7
-rw-r--r--user.h3
25 files changed, 519 insertions, 296 deletions
diff --git a/.travis.yml b/.travis.yml
index 6c08b428..9c7d8a7d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,5 @@
language: cpp
-os: [ linux, osx ]
-
-compiler: [ gcc, clang ]
-
addons:
apt:
sources:
@@ -14,10 +10,17 @@ addons:
- qt56base
matrix:
- exclude: [ { os: osx, compiler: gcc } ]
+ include:
+ - os: linux
+ compiler: gcc
+ env: [ ENV_EVAL="CC=gcc-5 && CXX=g++-5" ]
+ - os: linux
+ compiler: clang
+ - os: osx
+ env: [ ENV_EVAL="brew update && brew install qt5 && PATH=/usr/local/opt/qt/bin" ]
before_install:
-- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew install qt5; export PATH="$PATH:/usr/local/opt/qt/bin"; fi
+- eval "${ENV_EVAL}"
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then . /opt/qt56/bin/qt56-env.sh; fi
install:
@@ -36,7 +39,7 @@ before_script:
script:
- cmake --build . --target all
- cd ..
-- qmake qmc-example.pro && make all
+- qmake qmc-example.pro "QMAKE_CC = $CC" "QMAKE_CXX = $CXX" && make all
notifications:
webhooks:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0ead9ec8..1aa06198 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,6 @@
-cmake_minimum_required(VERSION 2.8.11) # Maybe works with even older versions
+cmake_minimum_required(VERSION 3.1)
-project(qmatrixclient)
-enable_language(CXX)
+project(qmatrixclient CXX)
include(CheckCXXCompilerFlag)
@@ -19,16 +18,15 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
"MinSizeRel" "RelWithDebInfo")
endif()
-# Setup command line parameters for the compiler and linker
-foreach (FLAG all pedantic error=return-type)
+set(CMAKE_CXX_STANDARD 14)
+
+foreach (FLAG all "" pedantic extra error=return-type no-unused-parameter no-gnu-zero-variadic-macro-arguments)
CHECK_CXX_COMPILER_FLAG("-W${FLAG}" WARN_${FLAG}_SUPPORTED)
if ( WARN_${FLAG}_SUPPORTED AND NOT CMAKE_CXX_FLAGS MATCHES "(^| )-W?${FLAG}($| )")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W${FLAG}")
- endif ( )
+ endif ()
endforeach ()
-set(CMAKE_CXX_STANDARD 14)
-
find_package(Qt5 5.6 REQUIRED Network Gui)
get_filename_component(Qt5_Prefix "${Qt5_DIR}/../../../.." ABSOLUTE)
@@ -51,6 +49,7 @@ message( STATUS )
# Set up source files
set(libqmatrixclient_SRCS
+ networkaccessmanager.cpp
connectiondata.cpp
connection.cpp
logging.cpp
@@ -58,6 +57,7 @@ set(libqmatrixclient_SRCS
user.cpp
avatar.cpp
settings.cpp
+ networksettings.cpp
events/event.cpp
events/eventcontent.cpp
events/roommessageevent.cpp
diff --git a/avatar.cpp b/avatar.cpp
index b2f50a67..9490347d 100644
--- a/avatar.cpp
+++ b/avatar.cpp
@@ -22,20 +22,22 @@
#include "events/eventcontent.h"
#include "connection.h"
+#include <QtGui/QPainter>
+
using namespace QMatrixClient;
class Avatar::Private
{
public:
Private(Connection* c, QIcon di) : _connection(c), _defaultIcon(di) { }
- QPixmap get(int width, int height, Avatar::notifier_t notifier);
+ QImage get(QSize size, Avatar::notifier_t notifier);
Connection* _connection;
const QIcon _defaultIcon;
QUrl _url;
- QPixmap _originalPixmap;
+ QImage _originalImage;
- std::vector<QPair<QSize, QPixmap>> _scaledPixmaps;
+ std::vector<QPair<QSize, QImage>> _scaledImages;
QSize _requestedSize;
bool _valid = false;
@@ -49,22 +51,25 @@ Avatar::Avatar(Connection* connection, QIcon defaultIcon)
Avatar::~Avatar() = default;
-QPixmap Avatar::get(int width, int height, Avatar::notifier_t notifier)
+QImage Avatar::get(int dimension, Avatar::notifier_t notifier)
{
- return d->get(width, height, notifier);
+ return d->get({dimension, dimension}, notifier);
}
-QPixmap Avatar::Private::get(int width, int height, Avatar::notifier_t notifier)
+QImage Avatar::get(int width, int height, Avatar::notifier_t notifier)
{
- QSize size(width, height);
+ return d->get({width, height}, notifier);
+}
+QImage Avatar::Private::get(QSize size, Avatar::notifier_t notifier)
+{
// FIXME: Alternating between longer-width and longer-height requests
// is a sure way to trick the below code into constantly getting another
// image from the server because the existing one is alleged unsatisfactory.
// This is plain abuse by the client, though; so not critical for now.
if( ( !(_valid || _ongoingRequest)
- || width > _requestedSize.width()
- || height > _requestedSize.height() ) && _url.isValid() )
+ || size.width() > _requestedSize.width()
+ || size.height() > _requestedSize.height() ) && _url.isValid() )
{
qCDebug(MAIN) << "Getting avatar from" << _url.toString();
_requestedSize = size;
@@ -77,8 +82,9 @@ QPixmap Avatar::Private::get(int width, int height, Avatar::notifier_t notifier)
if (_ongoingRequest->status().good())
{
_valid = true;
- _originalPixmap = _ongoingRequest->scaledThumbnail(_requestedSize);
- _scaledPixmaps.clear();
+ _originalImage =
+ _ongoingRequest->scaledThumbnail(_requestedSize);
+ _scaledImages.clear();
for (auto n: notifiers)
n();
}
@@ -86,21 +92,22 @@ QPixmap Avatar::Private::get(int width, int height, Avatar::notifier_t notifier)
});
}
- if( _originalPixmap.isNull() )
+ if( _originalImage.isNull() )
{
if (_defaultIcon.isNull())
- return _originalPixmap;
+ return _originalImage;
- _originalPixmap = _defaultIcon.pixmap(size);
+ QPainter p { &_originalImage };
+ _defaultIcon.paint(&p, { QPoint(), _defaultIcon.actualSize(size) });
}
- for (auto p: _scaledPixmaps)
+ for (auto p: _scaledImages)
if (p.first == size)
return p.second;
- auto pixmap = _originalPixmap.scaled(size,
+ auto result = _originalImage.scaled(size,
Qt::KeepAspectRatio, Qt::SmoothTransformation);
- _scaledPixmaps.emplace_back(size, pixmap);
- return pixmap;
+ _scaledImages.emplace_back(size, result);
+ return result;
}
QUrl Avatar::url() const { return d->_url; }
diff --git a/avatar.h b/avatar.h
index e71fecd7..d8b4b206 100644
--- a/avatar.h
+++ b/avatar.h
@@ -36,7 +36,8 @@ namespace QMatrixClient
using notifier_t = std::function<void()>;
- QPixmap get(int w, int h, notifier_t notifier);
+ QImage get(int dimension, notifier_t notifier);
+ QImage get(int w, int h, notifier_t notifier);
QUrl url() const;
bool updateUrl(const QUrl& newUrl);
diff --git a/connection.cpp b/connection.cpp
index 1f554974..36da838f 100644
--- a/connection.cpp
+++ b/connection.cpp
@@ -44,15 +44,14 @@ using namespace QMatrixClient;
class Connection::Private
{
public:
- explicit Private(const QUrl& serverUrl)
- : q(nullptr)
- , data(new ConnectionData(serverUrl))
+ explicit Private(std::unique_ptr<ConnectionData>&& connection)
+ : data(move(connection))
{ }
Q_DISABLE_COPY(Private)
Private(Private&&) = delete;
Private operator=(Private&&) = delete;
- Connection* q;
+ Connection* q = nullptr;
std::unique_ptr<ConnectionData> data;
// A complex key below is a pair of room name and whether its
// state is Invited. The spec mandates to keep Invited room state
@@ -72,7 +71,7 @@ class Connection::Private
Connection::Connection(const QUrl& server, QObject* parent)
: QObject(parent)
- , d(new Private(server))
+ , d(std::make_unique<Private>(std::make_unique<ConnectionData>(server)))
{
d->q = this; // All d initialization should occur before this line
}
@@ -85,7 +84,6 @@ Connection::~Connection()
{
qCDebug(MAIN) << "deconstructing connection object for" << d->userId;
stopSync();
- delete d;
}
void Connection::resolveServer(const QString& mxidOrDomain)
@@ -125,7 +123,7 @@ void Connection::resolveServer(const QString& mxidOrDomain)
dns->setType(QDnsLookup::SRV);
dns->setName("_matrix._tcp." + domain);
- connect(dns, &QDnsLookup::finished, [this,dns,maybeBaseUrl]() {
+ connect(dns, &QDnsLookup::finished, [this,dns,&maybeBaseUrl]() {
QUrl baseUrl { maybeBaseUrl };
if (dns->error() == QDnsLookup::NoError &&
dns->serviceRecords().isEmpty())
@@ -151,7 +149,7 @@ void Connection::connectToServer(const QString& user, const QString& password,
const QString& deviceId)
{
checkAndConnect(user,
- [=] {
+ [&] {
doConnectToServer(user, password, initialDeviceName, deviceId);
});
}
@@ -163,12 +161,12 @@ void Connection::doConnectToServer(const QString& user, const QString& password,
user, /*medium*/ "", /*address*/ "", password, /*token*/ "",
deviceId, initialDeviceName);
connect(loginJob, &BaseJob::success, this,
- [=] {
+ [this, loginJob] {
d->connectWithToken(loginJob->userId(), loginJob->accessToken(),
loginJob->deviceId());
});
connect(loginJob, &BaseJob::failure, this,
- [=] {
+ [this, loginJob] {
emit loginError(loginJob->errorString());
});
}
@@ -178,7 +176,7 @@ void Connection::connectWithToken(const QString& userId,
const QString& deviceId)
{
checkAndConnect(userId,
- [=] { d->connectWithToken(userId, accessToken, deviceId); });
+ [&] { d->connectWithToken(userId, accessToken, deviceId); });
}
void Connection::Private::connectWithToken(const QString& user,
@@ -222,7 +220,7 @@ void Connection::checkAndConnect(const QString& userId,
void Connection::logout()
{
auto job = callApi<LogoutJob>();
- connect( job, &LogoutJob::success, this, [=] {
+ connect( job, &LogoutJob::success, this, [this] {
stopSync();
emit loggedOut();
});
@@ -237,13 +235,13 @@ void Connection::sync(int timeout)
const QString filter { R"({"room": { "timeline": { "limit": 100 } } })" };
auto job = d->syncJob =
callApi<SyncJob>(d->data->lastEvent(), filter, timeout);
- connect( job, &SyncJob::success, [=] () {
+ connect( job, &SyncJob::success, [this, job] {
onSyncSuccess(job->takeData());
d->syncJob = nullptr;
emit syncDone();
});
connect( job, &SyncJob::retryScheduled, this, &Connection::networkError);
- connect( job, &SyncJob::failure, [=] () {
+ connect( job, &SyncJob::failure, [this, job] {
d->syncJob = nullptr;
if (job->error() == BaseJob::ContentAccessError)
emit loginError(job->errorString());
@@ -285,7 +283,7 @@ JoinRoomJob* Connection::joinRoom(const QString& roomAlias)
{
auto job = callApi<JoinRoomJob>(roomAlias);
connect(job, &JoinRoomJob::success,
- this, [=] { provideRoom(job->roomId(), JoinState::Join); });
+ this, [this, job] { provideRoom(job->roomId(), JoinState::Join); });
return job;
}
@@ -325,13 +323,12 @@ ForgetRoomJob* Connection::forgetRoom(const QString& id)
{
auto leaveJob = joinedRoom->leaveRoom();
connect(leaveJob, &BaseJob::success,
- this, [=] { forgetJob->start(connectionData()); });
- connect(leaveJob, &BaseJob::failure,
- this, [=] { forgetJob->abandon(); });
+ this, [this, forgetJob] { forgetJob->start(connectionData()); });
+ connect(leaveJob, &BaseJob::failure, forgetJob, &BaseJob::abandon);
}
else
forgetJob->start(connectionData());
- connect(forgetJob, &BaseJob::success, this, [=]
+ connect(forgetJob, &BaseJob::success, this, [this, &id]
{
// If the room happens to be in the map (possible in both forms),
// delete the found object(s).
diff --git a/connection.h b/connection.h
index eccde170..8dda2bbf 100644
--- a/connection.h
+++ b/connection.h
@@ -26,15 +26,13 @@
#include <QtCore/QSize>
#include <functional>
-
-class QDnsLookup;
+#include <memory>
namespace QMatrixClient
{
class Room;
class User;
class RoomEvent;
- class ConnectionPrivate;
class ConnectionData;
class SyncJob;
@@ -217,7 +215,7 @@ namespace QMatrixClient
void reconnected(); //< Unused; use connected() instead
void loggedOut();
void loginError(QString error);
- void networkError(size_t nextAttempt, int inMilliseconds);
+ void networkError(int retriesTaken, int inMilliseconds);
void syncDone();
void syncError(QString error);
@@ -307,7 +305,7 @@ namespace QMatrixClient
private:
class Private;
- Private* d;
+ std::unique_ptr<Private> d;
/**
* A single entry for functions that need to check whether the
diff --git a/connectiondata.cpp b/connectiondata.cpp
index 70791952..4e9bc77e 100644
--- a/connectiondata.cpp
+++ b/connectiondata.cpp
@@ -18,26 +18,15 @@
#include "connectiondata.h"
+#include "networkaccessmanager.h"
#include "logging.h"
-#include <QtNetwork/QNetworkAccessManager>
-
using namespace QMatrixClient;
-QNetworkAccessManager* createNam()
-{
- auto nam = new QNetworkAccessManager();
- // See #109. Once Qt bearer management gets better, this workaround
- // should become unnecessary.
- nam->connect(nam, &QNetworkAccessManager::networkAccessibleChanged,
- nam, [=] {
- nam->setNetworkAccessible(QNetworkAccessManager::Accessible);
- });
- return nam;
-}
-
struct ConnectionData::Private
{
+ explicit Private(const QUrl& url) : baseUrl(url) { }
+
QUrl baseUrl;
QByteArray accessToken;
QString lastEvent;
@@ -48,16 +37,10 @@ struct ConnectionData::Private
};
ConnectionData::ConnectionData(QUrl baseUrl)
- : d(new Private)
-{
- nam(); // Just to ensure NAM is created
- d->baseUrl = baseUrl;
-}
+ : d(std::make_unique<Private>(baseUrl))
+{ }
-ConnectionData::~ConnectionData()
-{
- delete d;
-}
+ConnectionData::~ConnectionData() = default;
QByteArray ConnectionData::accessToken() const
{
@@ -71,8 +54,7 @@ QUrl ConnectionData::baseUrl() const
QNetworkAccessManager* ConnectionData::nam() const
{
- static auto nam = createNam();
- return nam;
+ return NetworkAccessManager::instance();
}
void ConnectionData::setBaseUrl(QUrl baseUrl)
diff --git a/connectiondata.h b/connectiondata.h
index 530a52ee..7a2f2e90 100644
--- a/connectiondata.h
+++ b/connectiondata.h
@@ -20,6 +20,8 @@
#include <QtCore/QUrl>
+#include <memory>
+
class QNetworkAccessManager;
namespace QMatrixClient
@@ -48,6 +50,6 @@ namespace QMatrixClient
private:
struct Private;
- Private* d;
+ std::unique_ptr<Private> d;
};
} // namespace QMatrixClient
diff --git a/events/event.cpp b/events/event.cpp
index e74bc114..c7345a13 100644
--- a/events/event.cpp
+++ b/events/event.cpp
@@ -144,3 +144,13 @@ RoomEventPtr _impl::doMakeEvent(const QJsonObject& obj)
RoomAvatarEvent, EncryptionEvent, RedactionEvent>
(obj, obj["type"].toString()) };
}
+
+StateEventBase::~StateEventBase() = default;
+
+bool StateEventBase::repeatsState() const
+{
+ auto contentJson = originalJsonObject().value("content");
+ auto prevContentJson = originalJsonObject().value("unsigned")
+ .toObject().value("prev_content");
+ return contentJson == prevContentJson;
+}
diff --git a/events/event.h b/events/event.h
index d4923f1f..319c3443 100644
--- a/events/event.h
+++ b/events/event.h
@@ -240,8 +240,23 @@ namespace QMatrixClient
RoomEvents::iterator end() { return to; }
};
+ class StateEventBase: public RoomEvent
+ {
+ public:
+ explicit StateEventBase(Type type, const QJsonObject& obj)
+ : RoomEvent(obj.contains("state_key") ? type : Type::Unknown,
+ obj)
+ { }
+ explicit StateEventBase(Type type)
+ : RoomEvent(type)
+ { }
+ ~StateEventBase() override = 0;
+
+ virtual bool repeatsState() const;
+ };
+
template <typename ContentT>
- class StateEvent: public RoomEvent
+ class StateEvent: public StateEventBase
{
public:
using content_type = ContentT;
@@ -249,19 +264,19 @@ namespace QMatrixClient
template <typename... ContentParamTs>
explicit StateEvent(Type type, const QJsonObject& obj,
ContentParamTs&&... contentParams)
- : RoomEvent(obj.contains("state_key") ? type : Type::Unknown,
- obj)
+ : StateEventBase(type, obj)
, _content(contentJson(),
std::forward<ContentParamTs>(contentParams)...)
{
- if (obj.contains("prev_content"))
+ auto unsignedData = obj.value("unsigned").toObject();
+ if (unsignedData.contains("prev_content"))
_prev.reset(new ContentT(
- obj["prev_content"].toObject(),
+ unsignedData.value("prev_content").toObject(),
std::forward<ContentParamTs>(contentParams)...));
}
template <typename... ContentParamTs>
explicit StateEvent(Type type, ContentParamTs&&... contentParams)
- : RoomEvent(type)
+ : StateEventBase(type)
, _content(std::forward<ContentParamTs>(contentParams)...)
{ }
diff --git a/jobs/basejob.cpp b/jobs/basejob.cpp
index 2f5c381a..405cb9e0 100644
--- a/jobs/basejob.cpp
+++ b/jobs/basejob.cpp
@@ -52,6 +52,7 @@ class BaseJob::Private
{ }
void sendRequest();
+ const JobTimeoutConfig& getCurrentTimeoutConfig() const;
const ConnectionData* connection = nullptr;
@@ -68,8 +69,10 @@ class BaseJob::Private
QTimer timer;
QTimer retryTimer;
- size_t maxRetries = 3;
- size_t retriesTaken = 0;
+ QVector<JobTimeoutConfig> errorStrategy =
+ { { 90, 5 }, { 90, 10 }, { 120, 30 } };
+ int maxRetries = errorStrategy.size();
+ int retriesTaken = 0;
LoggingCategory logCat = JOBS;
};
@@ -187,7 +190,6 @@ void BaseJob::sendRequest()
if (!d->requestQuery.isEmpty())
qCDebug(d->logCat) << " query:" << d->requestQuery.toString();
d->sendRequest();
- connect( d->reply.data(), &QNetworkReply::sslErrors, this, &BaseJob::sslErrors );
connect( d->reply.data(), &QNetworkReply::finished, this, &BaseJob::gotReply );
if (d->reply->isRunning())
{
@@ -296,16 +298,19 @@ void BaseJob::finishJob()
deleteLater();
}
+const JobTimeoutConfig& BaseJob::Private::getCurrentTimeoutConfig() const
+{
+ return errorStrategy[std::min(retriesTaken, errorStrategy.size() - 1)];
+}
+
BaseJob::duration_t BaseJob::getCurrentTimeout() const
{
- static const std::array<int, 4> timeouts = { 90, 90, 120, 120 };
- return timeouts[std::min(d->retriesTaken, timeouts.size() - 1)] * 1000;
+ return d->getCurrentTimeoutConfig().jobTimeout * 1000;
}
BaseJob::duration_t BaseJob::getNextRetryInterval() const
{
- static const std::array<int, 3> intervals = { 5, 10, 30 };
- return intervals[std::min(d->retriesTaken, intervals.size() - 1)] * 1000;
+ return d->getCurrentTimeoutConfig().nextRetryInterval * 1000;
}
BaseJob::duration_t BaseJob::millisToRetry() const
@@ -364,14 +369,6 @@ void BaseJob::timeout()
finishJob();
}
-void BaseJob::sslErrors(const QList<QSslError>& errors)
-{
- foreach (const QSslError &error, errors) {
- qCWarning(d->logCat) << "SSL ERROR" << error.errorString();
- }
- d->reply->ignoreSslErrors(); // TODO: insecure! should prompt user first
-}
-
void BaseJob::setLoggingCategory(LoggingCategory lcf)
{
d->logCat = lcf;
diff --git a/jobs/basejob.h b/jobs/basejob.h
index 66812774..e3a379fa 100644
--- a/jobs/basejob.h
+++ b/jobs/basejob.h
@@ -36,6 +36,12 @@ namespace QMatrixClient
enum class HttpVerb { Get, Put, Post, Delete };
+ struct JobTimeoutConfig
+ {
+ int jobTimeout;
+ int nextRetryInterval;
+ };
+
class BaseJob: public QObject
{
Q_OBJECT
@@ -162,7 +168,7 @@ namespace QMatrixClient
* @param nextAttempt the 1-based number of attempt (will always be more than 1)
* @param inMilliseconds the interval after which the next attempt will be taken
*/
- void retryScheduled(size_t nextAttempt, int inMilliseconds);
+ void retryScheduled(int nextAttempt, int inMilliseconds);
/**
* Emitted when the job is finished, in any case. It is used to notify
@@ -179,7 +185,6 @@ namespace QMatrixClient
* to avoid dangling pointers in your list.
*
* @param job the job that emitted this signal
- * @internal
*
* @see success, failure
*/
@@ -262,7 +267,6 @@ namespace QMatrixClient
virtual ~BaseJob();
protected slots:
void timeout();
- void sslErrors(const QList<QSslError>& errors);
private slots:
void sendRequest();
diff --git a/jobs/mediathumbnailjob.cpp b/jobs/mediathumbnailjob.cpp
index 5945493a..c0d67a63 100644
--- a/jobs/mediathumbnailjob.cpp
+++ b/jobs/mediathumbnailjob.cpp
@@ -36,19 +36,20 @@ MediaThumbnailJob::MediaThumbnailJob(QUrl url, QSize requestedSize,
}))
{ }
-QPixmap MediaThumbnailJob::thumbnail() const
+QImage MediaThumbnailJob::thumbnail() const
{
- return pixmap;
+ return _thumbnail;
}
-QPixmap MediaThumbnailJob::scaledThumbnail(QSize toSize) const
+QImage MediaThumbnailJob::scaledThumbnail(QSize toSize) const
{
- return pixmap.scaled(toSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ return _thumbnail.scaled(toSize,
+ Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
BaseJob::Status MediaThumbnailJob::parseReply(QByteArray data)
{
- if( !pixmap.loadFromData(data) )
+ if( !_thumbnail.loadFromData(data) )
{
qCDebug(JOBS) << "MediaThumbnailJob: could not read image data";
}
diff --git a/jobs/mediathumbnailjob.h b/jobs/mediathumbnailjob.h
index 292e7f14..f8f36fe9 100644
--- a/jobs/mediathumbnailjob.h
+++ b/jobs/mediathumbnailjob.h
@@ -32,13 +32,13 @@ namespace QMatrixClient
MediaThumbnailJob(QUrl url, QSize requestedSize,
ThumbnailType thumbnailType = ThumbnailType::Scale);
- QPixmap thumbnail() const;
- QPixmap scaledThumbnail(QSize toSize) const;
+ QImage thumbnail() const;
+ QImage scaledThumbnail(QSize toSize) const;
protected:
Status parseReply(QByteArray data) override;
private:
- QPixmap pixmap;
+ QImage _thumbnail;
};
} // namespace QMatrixClient
diff --git a/libqmatrixclient.pri b/libqmatrixclient.pri
index 49442197..8ee3634c 100644
--- a/libqmatrixclient.pri
+++ b/libqmatrixclient.pri
@@ -1,5 +1,6 @@
QT += network
-CONFIG += c++11 warn_on rtti_off
+CONFIG += c++14 warn_on rtti_off
+QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
INCLUDEPATH += $$PWD
@@ -31,7 +32,9 @@ HEADERS += \
$$PWD/jobs/setroomstatejob.h \
$$files($$PWD/jobs/generated/*.h, false) \
$$PWD/logging.h \
- $$PWD/settings.h
+ $$PWD/settings.h \
+ $$PWD/networksettings.h \
+ $$PWD/networkaccessmanager.h
SOURCES += \
$$PWD/connectiondata.cpp \
@@ -58,4 +61,6 @@ SOURCES += \
$$PWD/jobs/setroomstatejob.cpp \
$$files($$PWD/jobs/generated/*.cpp, false) \
$$PWD/logging.cpp \
- $$PWD/settings.cpp
+ $$PWD/settings.cpp \
+ $$PWD/networksettings.cpp \
+ $$PWD/networkaccessmanager.cpp
diff --git a/networkaccessmanager.cpp b/networkaccessmanager.cpp
new file mode 100644
index 00000000..7fb2f602
--- /dev/null
+++ b/networkaccessmanager.cpp
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "networkaccessmanager.h"
+
+#include <QtNetwork/QNetworkReply>
+
+using namespace QMatrixClient;
+
+class NetworkAccessManager::Private
+{
+ public:
+ QList<QSslError> ignoredSslErrors;
+};
+
+NetworkAccessManager::NetworkAccessManager() : d(std::make_unique<Private>())
+{ }
+
+QList<QSslError> NetworkAccessManager::ignoredSslErrors() const
+{
+ return d->ignoredSslErrors;
+}
+
+void NetworkAccessManager::addIgnoredSslError(const QSslError& error)
+{
+ d->ignoredSslErrors << error;
+}
+
+void NetworkAccessManager::clearIgnoredSslErrors()
+{
+ d->ignoredSslErrors.clear();
+}
+
+static NetworkAccessManager* createNam()
+{
+ auto nam = new NetworkAccessManager;
+ // See #109. Once Qt bearer management gets better, this workaround
+ // should become unnecessary.
+ nam->connect(nam, &QNetworkAccessManager::networkAccessibleChanged,
+ [nam] { nam->setNetworkAccessible(QNetworkAccessManager::Accessible); });
+ return nam;
+}
+
+NetworkAccessManager*NetworkAccessManager::instance()
+{
+ static auto* nam = createNam();
+ return nam;
+}
+
+NetworkAccessManager::~NetworkAccessManager() = default;
+
+QNetworkReply* NetworkAccessManager::createRequest(Operation op,
+ const QNetworkRequest& request, QIODevice* outgoingData)
+{
+ auto reply =
+ QNetworkAccessManager::createRequest(op, request, outgoingData);
+ reply->ignoreSslErrors(d->ignoredSslErrors);
+ return reply;
+}
diff --git a/networkaccessmanager.h b/networkaccessmanager.h
new file mode 100644
index 00000000..ea08c591
--- /dev/null
+++ b/networkaccessmanager.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include <QtNetwork/QNetworkAccessManager>
+
+#include <memory>
+
+namespace QMatrixClient
+{
+ class NetworkAccessManager : public QNetworkAccessManager
+ {
+ Q_OBJECT
+ public:
+ NetworkAccessManager();
+ ~NetworkAccessManager() override;
+
+ QList<QSslError> ignoredSslErrors() const;
+ void addIgnoredSslError(const QSslError& error);
+ void clearIgnoredSslErrors();
+
+ /** Get a pointer to the singleton */
+ static NetworkAccessManager* instance();
+
+ private:
+ QNetworkReply * createRequest(Operation op,
+ const QNetworkRequest &request,
+ QIODevice *outgoingData = Q_NULLPTR) override;
+
+ class Private;
+ std::unique_ptr<Private> d;
+ };
+} // namespace QMatrixClient
diff --git a/networksettings.cpp b/networksettings.cpp
new file mode 100644
index 00000000..48bd09f3
--- /dev/null
+++ b/networksettings.cpp
@@ -0,0 +1,31 @@
+/******************************************************************************
+ * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "networksettings.h"
+
+using namespace QMatrixClient;
+
+void NetworkSettings::setupApplicationProxy() const
+{
+ QNetworkProxy::setApplicationProxy(
+ { proxyType(), proxyHostName(), proxyPort() });
+}
+
+QMC_DEFINE_SETTING(NetworkSettings, QNetworkProxy::ProxyType, proxyType, "proxy_type", QNetworkProxy::DefaultProxy, setProxyType)
+QMC_DEFINE_SETTING(NetworkSettings, QString, proxyHostName, "proxy_hostname", "", setProxyHostName)
+QMC_DEFINE_SETTING(NetworkSettings, quint16, proxyPort, "proxy_port", -1, setProxyPort)
diff --git a/networksettings.h b/networksettings.h
new file mode 100644
index 00000000..83613060
--- /dev/null
+++ b/networksettings.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include "settings.h"
+
+#include <QtNetwork/QNetworkProxy>
+
+Q_DECLARE_METATYPE(QNetworkProxy::ProxyType)
+
+namespace QMatrixClient {
+ class NetworkSettings: public SettingsGroup
+ {
+ Q_OBJECT
+ QMC_DECLARE_SETTING(QNetworkProxy::ProxyType, proxyType, setProxyType)
+ QMC_DECLARE_SETTING(QString, proxyHostName, setProxyHostName)
+ QMC_DECLARE_SETTING(quint16, proxyPort, setProxyPort)
+ Q_PROPERTY(QString proxyHost READ proxyHostName WRITE setProxyHostName)
+ public:
+ template <typename... ArgTs>
+ explicit NetworkSettings(ArgTs... qsettingsArgs)
+ : SettingsGroup(QStringLiteral("Network"), qsettingsArgs...)
+ { }
+ ~NetworkSettings() override = default;
+
+ Q_INVOKABLE void setupApplicationProxy() const;
+ };
+}
diff --git a/room.cpp b/room.cpp
index d39e6d32..1e159fd5 100644
--- a/room.cpp
+++ b/room.cpp
@@ -160,6 +160,11 @@ class Room::Private
}
};
+RoomEventPtr TimelineItem::replaceEvent(RoomEventPtr&& other)
+{
+ return std::exchange(evt, std::move(other));
+}
+
Room::Room(Connection* connection, QString id, JoinState initialJoinState)
: QObject(connection), d(new Private(connection, id, initialJoinState))
{
@@ -209,7 +214,12 @@ QString Room::topic() const
return d->topic;
}
-QPixmap Room::avatar(int width, int height)
+QImage Room::avatar(int dimension)
+{
+ return avatar(dimension, dimension);
+}
+
+QImage Room::avatar(int width, int height)
{
if (!d->avatar.url().isEmpty())
return d->avatar.get(width, height, [=] { emit avatarChanged(); });
@@ -457,7 +467,7 @@ void Room::Private::removeMemberFromMap(const QString& username, User* u)
emit q->memberRenamed(formerNamesakes[0]);
}
-inline QByteArray makeErrorStr(const Event& e, QByteArray msg)
+inline auto makeErrorStr(const Event& e, QByteArray msg)
{
return msg.append("; event dump follows:\n").append(e.originalJson());
}
@@ -499,7 +509,7 @@ void Room::Private::addMember(User *u)
{
insertMemberIntoMap(u);
connect(u, &User::nameChanged, q,
- [=] (User* u, const QString& newName) { renameMember(u, newName); });
+ bind(&Private::renameMember, this, _1, _2));
emit q->userAdded(u);
}
}
@@ -660,7 +670,7 @@ void Room::Private::getPreviousContent(int limit)
{
roomMessagesJob =
connection->callApi<RoomMessagesJob>(id, prevBatch, limit);
- connect( roomMessagesJob, &RoomMessagesJob::result, [=]() {
+ connect( roomMessagesJob, &RoomMessagesJob::result, [=] {
if( !roomMessagesJob->error() )
{
addHistoricalMessageEvents(roomMessagesJob->releaseEvents());
@@ -780,8 +790,7 @@ void Room::Private::processRedaction(RoomEventPtr redactionEvent)
}
auto keepContentKeys =
find_if(keepContentKeysMap.begin(), keepContentKeysMap.end(),
- [&](const std::pair<EventType,QStringList>& t)
- { return ti->type() == t.first; } );
+ [&ti](const auto& t) { return ti->type() == t.first; } );
if (keepContentKeys == keepContentKeysMap.end())
{
originalJson.remove("content");
@@ -1226,9 +1235,9 @@ bool MemberSorter::operator()(User *u1, User *u2) const
{
auto n1 = room->roomMembername(u1);
auto n2 = room->roomMembername(u2);
- if (n1[0] == '@')
+ if (n1.startsWith('@'))
n1.remove(0, 1);
- if (n2[0] == '@')
+ if (n2.startsWith('@'))
n2.remove(0, 1);
return n1.localeAwareCompare(n2) < 0;
}
diff --git a/room.h b/room.h
index 08327917..f863d41b 100644
--- a/room.h
+++ b/room.h
@@ -18,8 +18,9 @@
#pragma once
-#include <memory>
-#include <deque>
+#include "jobs/syncjob.h"
+#include "events/roommessageevent.h"
+#include "joinstate.h"
#include <QtCore/QList>
#include <QtCore/QStringList>
@@ -27,9 +28,9 @@
#include <QtCore/QJsonObject>
#include <QtGui/QPixmap>
-#include "jobs/syncjob.h"
-#include "events/roommessageevent.h"
-#include "joinstate.h"
+#include <memory>
+#include <deque>
+#include <utility>
namespace QMatrixClient
{
@@ -56,11 +57,7 @@ namespace QMatrixClient
index_t index() const { return idx; }
// Used for event redaction
- RoomEventPtr replaceEvent(RoomEventPtr&& other)
- {
- evt.swap(other);
- return move(other);
- }
+ RoomEventPtr replaceEvent(RoomEventPtr&& other);
private:
RoomEventPtr evt;
@@ -111,11 +108,20 @@ namespace QMatrixClient
Q_INVOKABLE int timelineSize() const;
/**
- * Returns a room avatar and requests it from the network if needed
+ * Returns a square room avatar with the given size and requests it
+ * from the network if needed
+ * @return a pixmap with the avatar or a placeholder if there's none
+ * available yet
+ */
+ Q_INVOKABLE QImage avatar(int dimension);
+ /**
+ * Returns a room avatar with the given dimensions and requests it
+ * from the network if needed
* @return a pixmap with the avatar or a placeholder if there's none
* available yet
*/
- Q_INVOKABLE QPixmap avatar(int width, int height);
+ Q_INVOKABLE QImage avatar(int width, int height);
+
/**
* @brief Produces a disambiguated name for a given user in
* the context of the room
diff --git a/settings.cpp b/settings.cpp
index ac9c091c..bf369c58 100644
--- a/settings.cpp
+++ b/settings.cpp
@@ -84,15 +84,9 @@ void SettingsGroup::remove(const QString& key)
Settings::remove(fullKey);
}
-bool AccountSettings::keepLoggedIn() const
-{
- return value("keep_logged_in", false).toBool();
-}
-
-void AccountSettings::setKeepLoggedIn(bool newSetting)
-{
- setValue("keep_logged_in", newSetting);
-}
+QMC_DEFINE_SETTING(AccountSettings, QString, deviceId, "device_id", "", setDeviceId)
+QMC_DEFINE_SETTING(AccountSettings, QString, deviceName, "device_name", "", setDeviceName)
+QMC_DEFINE_SETTING(AccountSettings, bool, keepLoggedIn, "keep_logged_in", false, setKeepLoggedIn)
QUrl AccountSettings::homeserver() const
{
@@ -109,26 +103,6 @@ QString AccountSettings::userId() const
return group().section('/', -1);
}
-QString AccountSettings::deviceId() const
-{
- return value("device_id").toString();
-}
-
-void AccountSettings::setDeviceId(const QString& deviceId)
-{
- setValue("device_id", deviceId);
-}
-
-QString AccountSettings::deviceName() const
-{
- return value("device_name").toString();
-}
-
-void AccountSettings::setDeviceName(const QString& deviceName)
-{
- setValue("device_name", deviceName);
-}
-
QString AccountSettings::accessToken() const
{
return value("access_token").toString();
diff --git a/settings.h b/settings.h
index 36e29cf1..27ec9ba5 100644
--- a/settings.h
+++ b/settings.h
@@ -1,126 +1,134 @@
-/******************************************************************************
- * Copyright (C) 2016 Kitsune Ral <kitsune-ral@users.sf.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#pragma once
-
-#include <QtCore/QSettings>
-#include <QtCore/QVector>
-#include <QtCore/QUrl>
-
-class QVariant;
-
-namespace QMatrixClient
-{
- class Settings: public QSettings
- {
- Q_OBJECT
- public:
- /**
- * Use this function before creating any Settings objects in order
- * to setup a read-only location where configuration has previously
- * been stored. This will provide an additional fallback in case of
- * renaming the organisation/application.
- */
- static void setLegacyNames(const QString& organizationName,
- const QString& applicationName = {});
-
-#if defined(_MSC_VER) && _MSC_VER < 1900
- // VS 2013 (and probably older) aren't friends with 'using' statements
- // that involve private constructors
- explicit Settings(QObject* parent = 0) : QSettings(parent) { }
-#else
- using QSettings::QSettings;
-#endif
-
- Q_INVOKABLE void setValue(const QString &key,
- const QVariant &value);
- Q_INVOKABLE QVariant value(const QString &key,
- const QVariant &defaultValue = {}) const;
- Q_INVOKABLE bool contains(const QString& key) const;
- Q_INVOKABLE QStringList childGroups() const;
-
- private:
- static QString legacyOrganizationName;
- static QString legacyApplicationName;
-
- protected:
- QSettings legacySettings { legacyOrganizationName,
- legacyApplicationName };
- };
-
- class SettingsGroup: public Settings
- {
- public:
- template <typename... ArgTs>
- explicit SettingsGroup(const QString& path, ArgTs... qsettingsArgs)
- : Settings(qsettingsArgs...)
- , groupPath(path)
- { }
-
- Q_INVOKABLE bool contains(const QString& key) const;
- Q_INVOKABLE QVariant value(const QString &key,
- const QVariant &defaultValue = {}) const;
- Q_INVOKABLE QString group() const;
- Q_INVOKABLE QStringList childGroups() const;
- Q_INVOKABLE void setValue(const QString &key,
- const QVariant &value);
-
- Q_INVOKABLE void remove(const QString& key);
-
- private:
- QString groupPath;
- };
-
- class AccountSettings: public SettingsGroup
- {
- Q_OBJECT
- Q_PROPERTY(QString userId READ userId CONSTANT)
- Q_PROPERTY(QString deviceId READ deviceId WRITE setDeviceId)
- Q_PROPERTY(QString deviceName READ deviceName WRITE setDeviceName)
- Q_PROPERTY(QUrl homeserver READ homeserver WRITE setHomeserver)
- Q_PROPERTY(bool keepLoggedIn READ keepLoggedIn WRITE setKeepLoggedIn)
- /** \deprecated \sa setToken */
- Q_PROPERTY(QString accessToken READ accessToken WRITE setAccessToken)
- public:
- template <typename... ArgTs>
- explicit AccountSettings(const QString& accountId, ArgTs... qsettingsArgs)
- : SettingsGroup("Accounts/" + accountId, qsettingsArgs...)
- { }
-
- QString userId() const;
-
- QString deviceId() const;
- void setDeviceId(const QString& deviceId);
-
- QString deviceName() const;
- void setDeviceName(const QString& deviceName);
-
- QUrl homeserver() const;
- void setHomeserver(const QUrl& url);
-
- bool keepLoggedIn() const;
- void setKeepLoggedIn(bool newSetting);
-
- /** \deprecated \sa setToken */
- QString accessToken() const;
- /** \deprecated Storing accessToken in QSettings is unsafe,
- * see QMatrixClient/Quaternion#181 */
- void setAccessToken(const QString& accessToken);
- Q_INVOKABLE void clearAccessToken();
- };
-} // namespace QMatrixClient
+/******************************************************************************
+ * Copyright (C) 2016 Kitsune Ral <kitsune-ral@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include <QtCore/QSettings>
+#include <QtCore/QVector>
+#include <QtCore/QUrl>
+
+class QVariant;
+
+namespace QMatrixClient
+{
+ class Settings: public QSettings
+ {
+ Q_OBJECT
+ public:
+ /**
+ * Use this function before creating any Settings objects in order
+ * to setup a read-only location where configuration has previously
+ * been stored. This will provide an additional fallback in case of
+ * renaming the organisation/application.
+ */
+ static void setLegacyNames(const QString& organizationName,
+ const QString& applicationName = {});
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+ // VS 2013 (and probably older) aren't friends with 'using' statements
+ // that involve private constructors
+ explicit Settings(QObject* parent = 0) : QSettings(parent) { }
+#else
+ using QSettings::QSettings;
+#endif
+
+ Q_INVOKABLE void setValue(const QString &key,
+ const QVariant &value);
+ Q_INVOKABLE QVariant value(const QString &key,
+ const QVariant &defaultValue = {}) const;
+ Q_INVOKABLE bool contains(const QString& key) const;
+ Q_INVOKABLE QStringList childGroups() const;
+
+ private:
+ static QString legacyOrganizationName;
+ static QString legacyApplicationName;
+
+ protected:
+ QSettings legacySettings { legacyOrganizationName,
+ legacyApplicationName };
+ };
+
+ class SettingsGroup: public Settings
+ {
+ public:
+ template <typename... ArgTs>
+ explicit SettingsGroup(const QString& path, ArgTs... qsettingsArgs)
+ : Settings(qsettingsArgs...)
+ , groupPath(path)
+ { }
+
+ Q_INVOKABLE bool contains(const QString& key) const;
+ Q_INVOKABLE QVariant value(const QString &key,
+ const QVariant &defaultValue = {}) const;
+ Q_INVOKABLE QString group() const;
+ Q_INVOKABLE QStringList childGroups() const;
+ Q_INVOKABLE void setValue(const QString &key,
+ const QVariant &value);
+
+ Q_INVOKABLE void remove(const QString& key);
+
+ private:
+ QString groupPath;
+ };
+
+#define QMC_DECLARE_SETTING(type, propname, setter) \
+ Q_PROPERTY(type propname READ propname WRITE setter) \
+ public: \
+ type propname() const; \
+ void setter(type newValue); \
+ private:
+
+#define QMC_DEFINE_SETTING(classname, type, propname, qsettingname, defaultValue, setter) \
+type classname::propname() const \
+{ \
+ return value(QStringLiteral(qsettingname), defaultValue).value<type>(); \
+} \
+\
+void classname::setter(type newValue) \
+{ \
+ setValue(QStringLiteral(qsettingname), newValue); \
+} \
+
+ class AccountSettings: public SettingsGroup
+ {
+ Q_OBJECT
+ Q_PROPERTY(QString userId READ userId CONSTANT)
+ QMC_DECLARE_SETTING(QString, deviceId, setDeviceId)
+ QMC_DECLARE_SETTING(QString, deviceName, setDeviceName)
+ QMC_DECLARE_SETTING(bool, keepLoggedIn, setKeepLoggedIn)
+ /** \deprecated \sa setAccessToken */
+ Q_PROPERTY(QString accessToken READ accessToken WRITE setAccessToken)
+ public:
+ template <typename... ArgTs>
+ explicit AccountSettings(const QString& accountId, ArgTs... qsettingsArgs)
+ : SettingsGroup("Accounts/" + accountId, qsettingsArgs...)
+ { }
+
+ QString userId() const;
+
+ QUrl homeserver() const;
+ void setHomeserver(const QUrl& url);
+
+ /** \deprecated \sa setToken */
+ QString accessToken() const;
+ /** \deprecated Storing accessToken in QSettings is unsafe,
+ * see QMatrixClient/Quaternion#181 */
+ void setAccessToken(const QString& accessToken);
+ Q_INVOKABLE void clearAccessToken();
+ };
+} // namespace QMatrixClient
diff --git a/user.cpp b/user.cpp
index faad6231..6d2a2030 100644
--- a/user.cpp
+++ b/user.cpp
@@ -95,7 +95,12 @@ Avatar& User::avatarObject()
return d->avatar;
}
-QPixmap User::avatar(int width, int height)
+QImage User::avatar(int dimension)
+{
+ return avatar(dimension, dimension);
+}
+
+QImage User::avatar(int width, int height)
{
return d->avatar.get(width, height, [=] { emit avatarChanged(this); });
}
diff --git a/user.h b/user.h
index 148ed64d..b7d67fb2 100644
--- a/user.h
+++ b/user.h
@@ -54,7 +54,8 @@ namespace QMatrixClient
Q_INVOKABLE QString bridged() const;
Avatar& avatarObject();
- QPixmap avatar(int requestedWidth, int requestedHeight);
+ QImage avatar(int dimension);
+ QImage avatar(int requestedWidth, int requestedHeight);
QUrl avatarUrl() const;