aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--QMatrixClient.pc.in10
-rw-r--r--lib/avatar.cpp17
-rw-r--r--lib/connection.cpp42
-rw-r--r--lib/connection.h78
-rw-r--r--lib/converters.h5
-rw-r--r--lib/events/accountdataevents.h38
-rw-r--r--lib/jobs/basejob.cpp2
-rw-r--r--lib/jobs/syncjob.cpp2
-rw-r--r--lib/room.cpp95
-rw-r--r--lib/room.h56
-rw-r--r--lib/util.h18
12 files changed, 232 insertions, 136 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e9b847f4..d08b13f0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -152,6 +152,7 @@ target_link_libraries(QMatrixClient Qt5::Core Qt5::Network Qt5::Gui)
add_executable(qmc-example ${example_SRCS})
target_link_libraries(qmc-example Qt5::Core QMatrixClient)
+configure_file(QMatrixClient.pc.in ${CMAKE_CURRENT_BINARY_DIR}/QMatrixClient.pc @ONLY NEWLINE_STYLE UNIX)
# Installation
@@ -194,3 +195,7 @@ if (WIN32)
endif (WIN32)
install(TARGETS qmc-example RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+if (UNIX AND NOT APPLE)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/QMatrixClient.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+endif()
diff --git a/QMatrixClient.pc.in b/QMatrixClient.pc.in
new file mode 100644
index 00000000..d2938ab7
--- /dev/null
+++ b/QMatrixClient.pc.in
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+includedir=${prefix}/include
+libdir=${prefix}/lib
+
+Name: QMatrixClient
+Description: A Qt5 library to write cross-platfrom clients for Matrix
+Version: @API_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lQMatrixClient
diff --git a/lib/avatar.cpp b/lib/avatar.cpp
index 7e6dc50b..be9b6a78 100644
--- a/lib/avatar.cpp
+++ b/lib/avatar.cpp
@@ -126,6 +126,14 @@ QImage Avatar::Private::get(Connection* connection, QSize size,
if (callback)
callbacks.emplace_back(move(callback));
_thumbnailRequest = connection->getThumbnail(_url, size);
+ if (_originalImage.isNull() && !_defaultIcon.isNull())
+ {
+ _originalImage = QImage(_defaultIcon.actualSize(size),
+ QImage::Format_ARGB32_Premultiplied);
+ _originalImage.fill(Qt::transparent);
+ QPainter p { &_originalImage };
+ _defaultIcon.paint(&p, { QPoint(), _defaultIcon.actualSize(size) });
+ }
QObject::connect( _thumbnailRequest, &MediaThumbnailJob::success,
_thumbnailRequest, [this] {
_fetched = true;
@@ -138,15 +146,6 @@ QImage Avatar::Private::get(Connection* connection, QSize size,
});
}
- if( _originalImage.isNull() )
- {
- if (_defaultIcon.isNull())
- return _originalImage;
-
- QPainter p { &_originalImage };
- _defaultIcon.paint(&p, { QPoint(), _defaultIcon.actualSize(size) });
- }
-
for (const auto& p: _scaledImages)
if (p.first == size)
return p.second;
diff --git a/lib/connection.cpp b/lib/connection.cpp
index e8c9a2dc..3d635a7e 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -650,14 +650,14 @@ ForgetRoomJob* Connection::forgetRoom(const QString& id)
forgetJob->start(connectionData());
connect(forgetJob, &BaseJob::success, this, [this, id]
{
- // If the room is in the map (possibly in both forms), delete all forms.
+ // Delete whatever instances of the room are still in the map.
for (auto f: {false, true})
if (auto r = d->roomMap.take({ id, f }))
{
- emit aboutToDeleteRoom(r);
- qCDebug(MAIN) << "Room" << id
- << "in join state" << toCString(r->joinState())
+ qCDebug(MAIN) << "Room" << r->objectName()
+ << "in state" << toCString(r->joinState())
<< "will be deleted";
+ emit r->beforeDestruction(r);
r->deleteLater();
}
});
@@ -731,7 +731,7 @@ User* Connection::user(const QString& userId)
}
if( d->userMap.contains(userId) )
return d->userMap.value(userId);
- auto* user = userFactory(this, userId);
+ auto* user = userFactory()(this, userId);
d->userMap.insert(userId, user);
emit newUser(user);
return user;
@@ -988,7 +988,7 @@ Room* Connection::provideRoom(const QString& id, JoinState joinState)
}
else
{
- room = roomFactory(this, id, joinState);
+ room = roomFactory()(this, id, joinState);
if (!room)
{
qCCritical(MAIN) << "Failed to create a room" << id;
@@ -996,6 +996,8 @@ Room* Connection::provideRoom(const QString& id, JoinState joinState)
}
d->roomMap.insert(roomKey, room);
d->firstTimeRooms.push_back(room);
+ connect(room, &Room::beforeDestruction,
+ this, &Connection::aboutToDeleteRoom);
emit newRoom(room);
}
if (joinState == JoinState::Invite)
@@ -1016,7 +1018,7 @@ Room* Connection::provideRoom(const QString& id, JoinState joinState)
if (prevInvite)
{
qCDebug(MAIN) << "Deleting Invite state for room" << prevInvite->id();
- emit aboutToDeleteRoom(prevInvite);
+ emit prevInvite->beforeDestruction(prevInvite);
prevInvite->deleteLater();
}
}
@@ -1024,12 +1026,28 @@ Room* Connection::provideRoom(const QString& id, JoinState joinState)
return room;
}
-Connection::room_factory_t Connection::roomFactory =
- [](Connection* c, const QString& id, JoinState joinState)
- { return new Room(c, id, joinState); };
+void Connection::setRoomFactory(room_factory_t f)
+{
+ _roomFactory = std::move(f);
+}
+
+void Connection::setUserFactory(user_factory_t f)
+{
+ _userFactory = std::move(f);
+}
+
+room_factory_t Connection::roomFactory()
+{
+ return _roomFactory;
+}
+
+user_factory_t Connection::userFactory()
+{
+ return _userFactory;
+}
-Connection::user_factory_t Connection::userFactory =
- [](Connection* c, const QString& id) { return new User(id, c); };
+room_factory_t Connection::_roomFactory = defaultRoomFactory<>();
+user_factory_t Connection::_userFactory = defaultUserFactory<>();
QByteArray Connection::generateTxnId() const
{
diff --git a/lib/connection.h b/lib/connection.h
index 0823ff7e..cfad8774 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -69,6 +69,40 @@ namespace QMatrixClient
return connection;
}
+ class Connection;
+
+ using room_factory_t = std::function<Room*(Connection*, const QString&,
+ JoinState)>;
+ using user_factory_t = std::function<User*(Connection*, const QString&)>;
+
+ /** The default factory to create room objects
+ *
+ * Just a wrapper around operator new.
+ * \sa Connection::setRoomFactory, Connection::setRoomType
+ */
+ template <typename T = Room>
+ static inline room_factory_t defaultRoomFactory()
+ {
+ return [](Connection* c, const QString& id, JoinState js)
+ {
+ return new T(c, id, js);
+ };
+ }
+
+ /** The default factory to create user objects
+ *
+ * Just a wrapper around operator new.
+ * \sa Connection::setUserFactory, Connection::setUserType
+ */
+ template <typename T = User>
+ static inline user_factory_t defaultUserFactory()
+ {
+ return [](Connection* c, const QString& id)
+ {
+ return new T(id, c);
+ };
+ }
+
/** Enumeration with flags defining the network job running policy
* So far only background/foreground flags are available.
*
@@ -89,11 +123,6 @@ namespace QMatrixClient
Q_PROPERTY(QUrl homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)
Q_PROPERTY(bool cacheState READ cacheState WRITE setCacheState NOTIFY cacheStateChanged)
public:
- using room_factory_t =
- std::function<Room*(Connection*, const QString&, JoinState joinState)>;
- using user_factory_t =
- std::function<User*(Connection*, const QString&)>;
-
// Room ids, rather than room pointers, are used in the direct chat
// map types because the library keeps Invite rooms separate from
// rooms in Join and Leave state; and direct chats in account data
@@ -309,25 +338,30 @@ namespace QMatrixClient
std::forward<JobArgTs>(jobArgs)...);
}
- /** Generates a new transaction id. Transaction id's are unique within
+ /** Generate a new transaction id. Transaction id's are unique within
* a single Connection object
*/
Q_INVOKABLE QByteArray generateTxnId() const;
- template <typename T = Room>
- static void setRoomType()
- {
- roomFactory =
- [](Connection* c, const QString& id, JoinState joinState)
- { return new T(c, id, joinState); };
- }
+ /// Set a room factory function
+ static void setRoomFactory(room_factory_t f);
- template <typename T = User>
- static void setUserType()
- {
- userFactory =
- [](Connection* c, const QString& id) { return new T(id, c); };
- }
+ /// Set a user factory function
+ static void setUserFactory(user_factory_t f);
+
+ /// Get a room factory function
+ static room_factory_t roomFactory();
+
+ /// Get a user factory function
+ static user_factory_t userFactory();
+
+ /// Set the room factory to default with the overriden room type
+ template <typename T>
+ static void setRoomType() { setRoomFactory(defaultRoomFactory<T>()); }
+
+ /// Set the user factory to default with the overriden user type
+ template <typename T>
+ static void setUserType() { setUserFactory(defaultUserFactory<T>()); }
public slots:
/** Set the homeserver base URL */
@@ -632,7 +666,7 @@ namespace QMatrixClient
* the server; in particular, does not automatically create rooms
* on the server.
* @return a pointer to a Room object with the specified id; nullptr
- * if roomId is empty if roomFactory() failed to create a Room object.
+ * if roomId is empty or roomFactory() failed to create a Room object.
*/
Room* provideRoom(const QString& roomId, JoinState joinState);
@@ -662,8 +696,8 @@ namespace QMatrixClient
const QString& initialDeviceName,
const QString& deviceId = {});
- static room_factory_t roomFactory;
- static user_factory_t userFactory;
+ static room_factory_t _roomFactory;
+ static user_factory_t _userFactory;
};
} // namespace QMatrixClient
Q_DECLARE_METATYPE(QMatrixClient::Connection*)
diff --git a/lib/converters.h b/lib/converters.h
index 1e828393..7f78effe 100644
--- a/lib/converters.h
+++ b/lib/converters.h
@@ -163,6 +163,11 @@ namespace QMatrixClient
auto operator()(const QJsonValue& jv) const { return jv.toDouble(); }
};
+ template <> struct FromJson<float>
+ {
+ auto operator()(const QJsonValue& jv) const { return float(jv.toDouble()); }
+ };
+
template <> struct FromJson<qint64>
{
auto operator()(const QJsonValue& jv) const { return qint64(jv.toDouble()); }
diff --git a/lib/events/accountdataevents.h b/lib/events/accountdataevents.h
index 94fc510a..27f6c77c 100644
--- a/lib/events/accountdataevents.h
+++ b/lib/events/accountdataevents.h
@@ -31,22 +31,40 @@ namespace QMatrixClient
struct TagRecord
{
- TagRecord (QString order = {}) : order(std::move(order)) { }
- explicit TagRecord(const QJsonValue& jv)
- : order(jv.toObject().value("order"_ls).toString())
- { }
+ using order_type = Omittable<float>;
+
+ order_type order;
- QString order;
+ TagRecord (order_type order = none) : order(order) { }
+ explicit TagRecord(const QJsonValue& jv)
+ {
+ // Parse a float both from JSON double and JSON string because
+ // libqmatrixclient previously used to use strings to store order.
+ const auto orderJv = jv.toObject().value("order"_ls);
+ if (orderJv.isDouble())
+ order = fromJson<float>(orderJv);
+ else if (orderJv.isString())
+ {
+ bool ok;
+ order = orderJv.toString().toFloat(&ok);
+ if (!ok)
+ order = none;
+ }
+ }
- bool operator==(const TagRecord& other) const
- { return order == other.order; }
- bool operator!=(const TagRecord& other) const
- { return !operator==(other); }
+ bool operator<(const TagRecord& other) const
+ {
+ // Per The Spec, rooms with no order should be after those with order
+ return !order.omitted() &&
+ (other.order.omitted() || order.value() < other.order.value());
+ }
};
inline QJsonValue toJson(const TagRecord& rec)
{
- return QJsonObject {{ QStringLiteral("order"), rec.order }};
+ QJsonObject o;
+ addParam(o, QStringLiteral("order"), rec.order);
+ return o;
}
using TagsMap = QHash<QString, TagRecord>;
diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp
index f9628c19..979fa431 100644
--- a/lib/jobs/basejob.cpp
+++ b/lib/jobs/basejob.cpp
@@ -514,7 +514,7 @@ BaseJob::Status BaseJob::status() const
QByteArray BaseJob::rawData(int bytesAtMost) const
{
- return bytesAtMost > 0 ?
+ return bytesAtMost > 0 && d->rawResponse.size() > bytesAtMost ?
d->rawResponse.left(bytesAtMost) + "...(truncated)" : d->rawResponse;
}
diff --git a/lib/jobs/syncjob.cpp b/lib/jobs/syncjob.cpp
index 02690e6d..9cbac71b 100644
--- a/lib/jobs/syncjob.cpp
+++ b/lib/jobs/syncjob.cpp
@@ -130,10 +130,10 @@ SyncRoomData::SyncRoomData(const QString& roomId_, JoinState joinState_,
switch (joinState) {
case JoinState::Join:
ephemeral = load<Events>(room_, "ephemeral"_ls);
- accountData = load<Events>(room_, "account_data"_ls);
FALLTHROUGH;
case JoinState::Leave:
{
+ accountData = load<Events>(room_, "account_data"_ls);
timeline = load<RoomEvents>(room_, "timeline"_ls);
const auto timelineJson = room_.value("timeline"_ls).toObject();
timelineLimited = timelineJson.value("limited"_ls).toBool();
diff --git a/lib/room.cpp b/lib/room.cpp
index ea1386ad..2b81d47d 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -107,6 +107,7 @@ class Room::Private
int notificationCount = 0;
members_map_t membersMap;
QList<User*> usersTyping;
+ QMultiHash<QString, User*> eventIdReadUsers;
QList<User*> membersLeft;
int unreadMessages = 0;
bool displayed = false;
@@ -237,14 +238,13 @@ class Room::Private
*/
bool processRedaction(const RedactionEvent& redaction);
- std::pair<TagsMap, QStringList> setTags(TagsMap newTags);
- void broadcastTagUpdates(const TagsMap& additions,
- const QStringList& removals)
+ void setTags(TagsMap newTags);
+ void sendTagUpdates()
{
connection->callApi<SetAccountDataPerRoomJob>(
connection->userId(), id, TagEvent::matrixTypeId(),
TagEvent(tags).contentJson());
- emit q->tagsChanged(additions, removals);
+ emit q->tagsChanged();
}
QJsonObject toJson() const;
@@ -380,8 +380,11 @@ void Room::Private::setLastReadEvent(User* u, QString eventId)
auto& storedId = lastReadEventIds[u];
if (storedId == eventId)
return;
+ eventIdReadUsers.remove(storedId, u);
+ eventIdReadUsers.insert(eventId, u);
swap(storedId, eventId);
emit q->lastReadEventChanged(u);
+ emit q->readMarkerForUserMoved(u, eventId, storedId);
if (isLocalUser(u))
{
if (storedId != serverReadMarker)
@@ -640,6 +643,10 @@ QString Room::readMarkerEventId() const
return d->lastReadEventIds.value(localUser());
}
+QList<User*> Room::usersAtEventId(const QString& eventId) {
+ return d->eventIdReadUsers.values(eventId);
+}
+
int Room::notificationCount() const
{
return d->notificationCount;
@@ -699,7 +706,7 @@ std::pair<bool, QString> validatedTag(QString name)
return { false, name };
qWarning(MAIN) << "The tag" << name
- << "doesn't follow the CS API conventions, check your client code";
+ << "doesn't follow the CS API conventions";
name.prepend("u.");
qWarning(MAIN) << "Using " << name << "instead";
@@ -713,8 +720,10 @@ void Room::addTag(const QString& name, const TagRecord& record)
(checkRes.first && d->tags.contains(checkRes.second)))
return;
+ emit tagsAboutToChange();
d->tags.insert(checkRes.second, record);
- d->broadcastTagUpdates({{ checkRes.second, record }}, {});
+ emit tagsChanged();
+ d->sendTagUpdates();
}
void Room::addTag(const QString& name, const QString& order)
@@ -724,43 +733,32 @@ void Room::addTag(const QString& name, const QString& order)
void Room::removeTag(const QString& name)
{
- if (!d->tags.contains(name))
- return;
-
- d->tags.remove(name);
- d->broadcastTagUpdates({}, {{ name }});
+ if (d->tags.contains(name))
+ {
+ emit tagsAboutToChange();
+ d->tags.remove(name);
+ emit tagsChanged();
+ d->sendTagUpdates();
+ } else if (!name.startsWith("u."))
+ removeTag("u." + name);
+ else
+ qWarning(MAIN) << "Tag" << name << "on room" << objectName()
+ << "not found, nothing to remove";
}
void Room::setTags(TagsMap newTags)
{
- const auto& changes = d->setTags(move(newTags));
- d->broadcastTagUpdates(changes.first, changes.second);
+ d->setTags(move(newTags));
+ d->sendTagUpdates();
}
-std::pair<TagsMap, QStringList> Room::Private::setTags(TagsMap newTags)
+void Room::Private::setTags(TagsMap newTags)
{
- if (newTags == tags)
- return {};
-
- TagsMap additions;
- const auto& tagNames = newTags.keys();
- for (const auto& t: tagNames)
- {
- const auto& checkRes = validatedTag(t);
- const auto& value = checkRes.first ?
- newTags.insert(checkRes.second, newTags.take(t)).value() :
- newTags.value(checkRes.second);
- if (!tags.contains(checkRes.second))
- additions.insert(checkRes.second, value);
- }
-
- QStringList removals;
- for (const auto& tag: tags.keys())
- if (!newTags.contains(tag))
- removals.push_back(tag);
-
- tags = newTags;
- return { additions, removals };
+ emit q->tagsAboutToChange();
+ tags = move(newTags);
+ qCDebug(MAIN) << "Room" << q->objectName() << "is tagged with"
+ << q->tagNames().join(", ");
+ emit q->tagsChanged();
}
bool Room::isFavourite() const
@@ -1913,15 +1911,8 @@ void Room::processEphemeralEvent(EventPtr&& event)
void Room::processAccountDataEvent(EventPtr&& event)
{
if (auto* evt = eventCast<TagEvent>(event))
- {
- const auto& changes = d->setTags(evt->tags());
- if (!(changes.first.empty() && changes.second.empty()))
- {
- qCDebug(MAIN) << "Room" << id() << "is tagged with:"
- << tagNames().join(", ");
- emit tagsChanged(changes.first, changes.second);
- }
- }
+ d->setTags(evt->tags());
+
if (auto* evt = eventCast<ReadMarkerEvent>(event))
{
auto readEventId = evt->event_id();
@@ -1939,6 +1930,7 @@ void Room::processAccountDataEvent(EventPtr&& event)
// efficient; maaybe do it another day
if (!currentData || currentData->contentJson() != event->contentJson())
{
+ emit accountDataAboutToChange(event->matrixType());
currentData = move(event);
qCDebug(MAIN) << "Updated account data of type"
<< currentData->matrixType();
@@ -2026,10 +2018,15 @@ QString Room::Private::calculateDisplayname() const
void Room::Private::updateDisplayname()
{
- const QString oldName = displayname;
- displayname = calculateDisplayname();
- if (oldName != displayname)
- emit q->displaynameChanged(q, oldName);
+ auto swappedName = calculateDisplayname();
+ if (swappedName != displayname)
+ {
+ emit q->displaynameAboutToChange(q);
+ swap(displayname, swappedName);
+ qDebug(MAIN) << q->objectName() << "has changed display name from"
+ << swappedName << "to" << displayname;
+ emit q->displaynameChanged(q, swappedName);
+ }
}
void appendStateEvent(QJsonArray& events, const QString& type,
diff --git a/lib/room.h b/lib/room.h
index fa5762e2..403207dd 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -24,7 +24,7 @@
#include "eventitem.h"
#include "joinstate.h"
-#include <QtGui/QPixmap>
+#include <QtGui/QImage>
#include <memory>
#include <deque>
@@ -129,20 +129,20 @@ namespace QMatrixClient
/**
* 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
+ * \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
+ * \return a pixmap with the avatar or a placeholder if there's none
* available yet
*/
Q_INVOKABLE QImage avatar(int width, int height);
/**
- * @brief Get a user object for a given user id
+ * \brief Get a user object for a given user id
* This is the recommended way to get a user object in a room
* context. The actual object type may be changed in further
* versions to provide room-specific user information (display name,
@@ -164,12 +164,12 @@ namespace QMatrixClient
Q_INVOKABLE JoinState memberJoinState(User* user) const;
/**
- * @brief Produces a disambiguated name for a given user in
+ * Get a disambiguated name for a given user in
* the context of the room
*/
Q_INVOKABLE QString roomMembername(const User* u) const;
/**
- * @brief Produces a disambiguated name for a user with this id in
+ * Get a disambiguated name for a user with this id in
* the context of the room
*/
Q_INVOKABLE QString roomMembername(const QString& userId) const;
@@ -177,8 +177,8 @@ namespace QMatrixClient
const Timeline& messageEvents() const;
const PendingEvents& pendingEvents() const;
/**
- * A convenience method returning the read marker to the before-oldest
- * message
+ * A convenience method returning the read marker to
+ * the before-oldest message
*/
rev_iter_t timelineEdge() const;
Q_INVOKABLE TimelineItem::index_t minTimelineIndex() const;
@@ -202,8 +202,9 @@ namespace QMatrixClient
rev_iter_t readMarker(const User* user) const;
rev_iter_t readMarker() const;
QString readMarkerEventId() const;
+ QList<User*> usersAtEventId(const QString& eventId);
/**
- * @brief Mark the event with uptoEventId as read
+ * \brief Mark the event with uptoEventId as read
*
* Finds in the timeline and marks as read the event with
* the specified id; also posts a read receipt to the server either
@@ -212,7 +213,7 @@ namespace QMatrixClient
*/
void markMessagesAsRead(QString uptoEventId);
- /** Check whether there are unread messages in the room */
+ /// Check whether there are unread messages in the room
bool hasUnreadMessages() const;
/** Get the number of unread messages in the room
@@ -263,7 +264,7 @@ namespace QMatrixClient
void addTag(const QString& name, const TagRecord& record = {});
Q_INVOKABLE void addTag(const QString& name, const QString& order);
- /** Remove a tag from the room */
+ /// Remove a tag from the room
Q_INVOKABLE void removeTag(const QString& name);
/** Overwrite the room's tags
@@ -276,15 +277,15 @@ namespace QMatrixClient
*/
void setTags(TagsMap newTags);
- /** Check whether the list of tags has m.favourite */
+ /// Check whether the list of tags has m.favourite
bool isFavourite() const;
- /** Check whether the list of tags has m.lowpriority */
+ /// Check whether the list of tags has m.lowpriority
bool isLowPriority() const;
- /** Check whether this room is a direct chat */
+ /// Check whether this room is a direct chat
Q_INVOKABLE bool isDirectChat() const;
- /** Get the list of users this room is a direct chat with */
+ /// Get the list of users this room is a direct chat with
QList<User*> directChatUsers() const;
Q_INVOKABLE QUrl urlToThumbnail(const QString& eventId);
@@ -301,9 +302,6 @@ namespace QMatrixClient
MemberSorter memberSorter() const;
- QJsonObject toJson() const;
- void updateData(SyncRoomData&& data );
- void setJoinState( JoinState state );
bool processCall(Room* room, const RoomEvent* event);
Q_INVOKABLE void inviteCall(const QString& callId,
@@ -356,7 +354,7 @@ namespace QMatrixClient
const QUrl& localFilename = {});
void cancelFileTransfer(const QString& id);
- /** Mark all messages in the room as read */
+ /// Mark all messages in the room as read
void markAllMessagesAsRead();
signals:
@@ -373,12 +371,12 @@ namespace QMatrixClient
void pendingEventChanged(int pendingEventIndex);
/**
- * @brief The room name, the canonical alias or other aliases changed
+ * \brief The room name, the canonical alias or other aliases changed
*
* Not triggered when displayname changes.
*/
void namesChanged(Room* room);
- /** @brief The room displayname changed */
+ void displaynameAboutToChange(Room* room);
void displaynameChanged(Room* room, QString oldName);
void topicChanged();
void avatarChanged();
@@ -400,11 +398,13 @@ namespace QMatrixClient
void lastDisplayedEventChanged();
void lastReadEventChanged(User* user);
void readMarkerMoved(QString fromEventId, QString toEventId);
+ void readMarkerForUserMoved(User* user, QString fromEventId, QString toEventId);
void unreadMessagesChanged(Room* room);
+ void accountDataAboutToChange(QString type);
void accountDataChanged(QString type);
- void tagsChanged(const TagsMap& additions,
- const QStringList& removals);
+ void tagsAboutToChange();
+ void tagsChanged();
void replacedEvent(const RoomEvent* newEvent,
const RoomEvent* oldEvent);
@@ -416,6 +416,16 @@ namespace QMatrixClient
void fileTransferCancelled(QString id);
void callEvent(Room* room, const RoomEvent* event);
+ /// The room is about to be deleted
+ void beforeDestruction(Room*);
+
+ public: // Used by Connection - not a part of the client API
+ QJsonObject toJson() const;
+ void updateData(SyncRoomData&& data );
+
+ // Clients should use Connection::joinRoom() and Room::leaveRoom()
+ // to change the room state
+ void setJoinState( JoinState state );
protected:
/// Returns true if any of room names/aliases has changed
diff --git a/lib/util.h b/lib/util.h
index ce166e35..13eec143 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -40,6 +40,15 @@
_ClassName(_ClassName&&) Q_DECL_EQ_DELETE; \
_ClassName& operator=(_ClassName&&) Q_DECL_EQ_DELETE;
+#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
+// Copy-pasted from Qt 5.10
+template <typename T>
+Q_DECL_CONSTEXPR typename std::add_const<T>::type &qAsConst(T &t) Q_DECL_NOTHROW { return t; }
+// prevent rvalue arguments:
+template <typename T>
+static void qAsConst(const T &&) Q_DECL_EQ_DELETE;
+#endif
+
namespace QMatrixClient
{
// The below enables pretty-printing of enums in logs
@@ -146,15 +155,6 @@ namespace QMatrixClient
template <typename FnT>
using fn_arg_t = typename function_traits<FnT>::arg_type;
-#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
- // Copy-pasted from Qt 5.10
- template <typename T>
- Q_DECL_CONSTEXPR typename std::add_const<T>::type &qAsConst(T &t) Q_DECL_NOTHROW { return t; }
- // prevent rvalue arguments:
- template <typename T>
- static void qAsConst(const T &&) Q_DECL_EQ_DELETE;
-#endif
-
inline auto operator"" _ls(const char* s, std::size_t size)
{
return QLatin1String(s, int(size));