diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2019-07-01 16:26:56 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2019-07-01 16:26:56 +0900 |
commit | 00ff511ab11fae58eb9dc43879f2483a9f303263 (patch) | |
tree | 804a23d1aa6ad6dd0669882c3107a5ed0edad7b3 /lib | |
parent | 12478cf7330727083103d22f76de92c4aa476f5b (diff) | |
parent | d3ddd394e855cfe217bf0f0d368822c9b99316bb (diff) | |
download | libquotient-00ff511ab11fae58eb9dc43879f2483a9f303263.tar.gz libquotient-00ff511ab11fae58eb9dc43879f2483a9f303263.zip |
Merge branch 'master' into forget-rooms-really
Diffstat (limited to 'lib')
-rw-r--r-- | lib/csapi/capabilities.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/content-repo.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/create_room.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/filter.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/joining.cpp | 4 | ||||
-rw-r--r-- | lib/csapi/keys.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/list_joined_rooms.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/notifications.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/openid.cpp | 8 | ||||
-rw-r--r-- | lib/csapi/presence.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/pushrules.cpp | 6 | ||||
-rw-r--r-- | lib/csapi/registration.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/room_upgrades.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/search.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/users.cpp | 4 | ||||
-rw-r--r-- | lib/csapi/versions.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/whoami.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/{{base}}.cpp.mustache | 2 | ||||
-rw-r--r-- | lib/jobs/basejob.cpp | 2 | ||||
-rw-r--r-- | lib/jobs/basejob.h | 34 | ||||
-rw-r--r-- | lib/room.cpp | 13 | ||||
-rw-r--r-- | lib/room.h | 8 | ||||
-rw-r--r-- | lib/user.cpp | 20 | ||||
-rw-r--r-- | lib/util.cpp | 19 | ||||
-rw-r--r-- | lib/util.h | 8 |
25 files changed, 85 insertions, 69 deletions
diff --git a/lib/csapi/capabilities.cpp b/lib/csapi/capabilities.cpp index 210423f5..fb506784 100644 --- a/lib/csapi/capabilities.cpp +++ b/lib/csapi/capabilities.cpp @@ -76,7 +76,7 @@ BaseJob::Status GetCapabilitiesJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("capabilities"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'capabilities' not found in the response" }; fromJson(json.value("capabilities"_ls), d->capabilities); return Success; diff --git a/lib/csapi/content-repo.cpp b/lib/csapi/content-repo.cpp index 22223985..7e490604 100644 --- a/lib/csapi/content-repo.cpp +++ b/lib/csapi/content-repo.cpp @@ -50,7 +50,7 @@ BaseJob::Status UploadContentJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("content_uri"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'content_uri' not found in the response" }; fromJson(json.value("content_uri"_ls), d->contentUri); return Success; diff --git a/lib/csapi/create_room.cpp b/lib/csapi/create_room.cpp index 448547ae..3101152a 100644 --- a/lib/csapi/create_room.cpp +++ b/lib/csapi/create_room.cpp @@ -77,7 +77,7 @@ BaseJob::Status CreateRoomJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("room_id"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'room_id' not found in the response" }; fromJson(json.value("room_id"_ls), d->roomId); return Success; diff --git a/lib/csapi/filter.cpp b/lib/csapi/filter.cpp index 982e60b5..9f412d53 100644 --- a/lib/csapi/filter.cpp +++ b/lib/csapi/filter.cpp @@ -39,7 +39,7 @@ BaseJob::Status DefineFilterJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("filter_id"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'filter_id' not found in the response" }; fromJson(json.value("filter_id"_ls), d->filterId); return Success; diff --git a/lib/csapi/joining.cpp b/lib/csapi/joining.cpp index 00d930fa..544f442f 100644 --- a/lib/csapi/joining.cpp +++ b/lib/csapi/joining.cpp @@ -57,7 +57,7 @@ BaseJob::Status JoinRoomByIdJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("room_id"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'room_id' not found in the response" }; fromJson(json.value("room_id"_ls), d->roomId); return Success; @@ -124,7 +124,7 @@ BaseJob::Status JoinRoomJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("room_id"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'room_id' not found in the response" }; fromJson(json.value("room_id"_ls), d->roomId); return Success; diff --git a/lib/csapi/keys.cpp b/lib/csapi/keys.cpp index 6c16a8a3..5bbc1aab 100644 --- a/lib/csapi/keys.cpp +++ b/lib/csapi/keys.cpp @@ -42,7 +42,7 @@ BaseJob::Status UploadKeysJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("one_time_key_counts"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'one_time_key_counts' not found in the response" }; fromJson(json.value("one_time_key_counts"_ls), d->oneTimeKeyCounts); return Success; diff --git a/lib/csapi/list_joined_rooms.cpp b/lib/csapi/list_joined_rooms.cpp index 85a9cae4..297a5ae0 100644 --- a/lib/csapi/list_joined_rooms.cpp +++ b/lib/csapi/list_joined_rooms.cpp @@ -44,7 +44,7 @@ BaseJob::Status GetJoinedRoomsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("joined_rooms"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'joined_rooms' not found in the response" }; fromJson(json.value("joined_rooms"_ls), d->joinedRooms); return Success; diff --git a/lib/csapi/notifications.cpp b/lib/csapi/notifications.cpp index c00b7cb0..5d3bdb47 100644 --- a/lib/csapi/notifications.cpp +++ b/lib/csapi/notifications.cpp @@ -80,7 +80,7 @@ BaseJob::Status GetNotificationsJob::parseJson(const QJsonDocument& data) auto json = data.object(); fromJson(json.value("next_token"_ls), d->nextToken); if (!json.contains("notifications"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'notifications' not found in the response" }; fromJson(json.value("notifications"_ls), d->notifications); return Success; diff --git a/lib/csapi/openid.cpp b/lib/csapi/openid.cpp index b27fe0b8..03d24790 100644 --- a/lib/csapi/openid.cpp +++ b/lib/csapi/openid.cpp @@ -57,19 +57,19 @@ BaseJob::Status RequestOpenIdTokenJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("access_token"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'access_token' not found in the response" }; fromJson(json.value("access_token"_ls), d->accessToken); if (!json.contains("token_type"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'token_type' not found in the response" }; fromJson(json.value("token_type"_ls), d->tokenType); if (!json.contains("matrix_server_name"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'matrix_server_name' not found in the response" }; fromJson(json.value("matrix_server_name"_ls), d->matrixServerName); if (!json.contains("expires_in"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'expires_in' not found in the response" }; fromJson(json.value("expires_in"_ls), d->expiresIn); return Success; diff --git a/lib/csapi/presence.cpp b/lib/csapi/presence.cpp index 024d7a34..210ee0ae 100644 --- a/lib/csapi/presence.cpp +++ b/lib/csapi/presence.cpp @@ -74,7 +74,7 @@ BaseJob::Status GetPresenceJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("presence"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'presence' not found in the response" }; fromJson(json.value("presence"_ls), d->presence); fromJson(json.value("last_active_ago"_ls), d->lastActiveAgo); diff --git a/lib/csapi/pushrules.cpp b/lib/csapi/pushrules.cpp index b91d18f7..9b5b7cd1 100644 --- a/lib/csapi/pushrules.cpp +++ b/lib/csapi/pushrules.cpp @@ -44,7 +44,7 @@ BaseJob::Status GetPushRulesJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("global"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'global' not found in the response" }; fromJson(json.value("global"_ls), d->global); return Success; @@ -152,7 +152,7 @@ BaseJob::Status IsPushRuleEnabledJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("enabled"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'enabled' not found in the response" }; fromJson(json.value("enabled"_ls), d->enabled); return Success; @@ -201,7 +201,7 @@ BaseJob::Status GetPushRuleActionsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("actions"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'actions' not found in the response" }; fromJson(json.value("actions"_ls), d->actions); return Success; diff --git a/lib/csapi/registration.cpp b/lib/csapi/registration.cpp index 5dc9c1e5..76741a50 100644 --- a/lib/csapi/registration.cpp +++ b/lib/csapi/registration.cpp @@ -74,7 +74,7 @@ BaseJob::Status RegisterJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("user_id"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'user_id' not found in the response" }; fromJson(json.value("user_id"_ls), d->userId); fromJson(json.value("access_token"_ls), d->accessToken); diff --git a/lib/csapi/room_upgrades.cpp b/lib/csapi/room_upgrades.cpp index f58fd675..f80c3aba 100644 --- a/lib/csapi/room_upgrades.cpp +++ b/lib/csapi/room_upgrades.cpp @@ -41,7 +41,7 @@ BaseJob::Status UpgradeRoomJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("replacement_room"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'replacement_room' not found in the response" }; fromJson(json.value("replacement_room"_ls), d->replacementRoom); return Success; diff --git a/lib/csapi/search.cpp b/lib/csapi/search.cpp index a5f83c79..ad2c34a3 100644 --- a/lib/csapi/search.cpp +++ b/lib/csapi/search.cpp @@ -164,7 +164,7 @@ BaseJob::Status SearchJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("search_categories"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'search_categories' not found in the response" }; fromJson(json.value("search_categories"_ls), d->searchCategories); return Success; diff --git a/lib/csapi/users.cpp b/lib/csapi/users.cpp index 97d8962d..0d867145 100644 --- a/lib/csapi/users.cpp +++ b/lib/csapi/users.cpp @@ -63,11 +63,11 @@ BaseJob::Status SearchUserDirectoryJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("results"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'results' not found in the response" }; fromJson(json.value("results"_ls), d->results); if (!json.contains("limited"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'limited' not found in the response" }; fromJson(json.value("limited"_ls), d->limited); return Success; diff --git a/lib/csapi/versions.cpp b/lib/csapi/versions.cpp index 6ee6725d..4b7c4ced 100644 --- a/lib/csapi/versions.cpp +++ b/lib/csapi/versions.cpp @@ -50,7 +50,7 @@ BaseJob::Status GetVersionsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("versions"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'versions' not found in the response" }; fromJson(json.value("versions"_ls), d->versions); fromJson(json.value("unstable_features"_ls), d->unstableFeatures); diff --git a/lib/csapi/whoami.cpp b/lib/csapi/whoami.cpp index aebdf5d3..ce024c33 100644 --- a/lib/csapi/whoami.cpp +++ b/lib/csapi/whoami.cpp @@ -44,7 +44,7 @@ BaseJob::Status GetTokenOwnerJob::parseJson(const QJsonDocument& data) { auto json = data.object(); if (!json.contains("user_id"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key 'user_id' not found in the response" }; fromJson(json.value("user_id"_ls), d->userId); return Success; diff --git a/lib/csapi/{{base}}.cpp.mustache b/lib/csapi/{{base}}.cpp.mustache index ff888d76..010f9116 100644 --- a/lib/csapi/{{base}}.cpp.mustache +++ b/lib/csapi/{{base}}.cpp.mustache @@ -115,7 +115,7 @@ BaseJob::Status {{camelCaseOperationId}}Job::parseJson(const QJsonDocument& data {{#inlineResponse}} fromJson(data, d->{{paramName}}); {{/inlineResponse}}{{^inlineResponse}} auto json = data.object(); {{#properties}}{{#required?}} if (!json.contains("{{baseName}}"_ls)) - return { JsonParseError, + return { IncorrectResponse, "The key '{{baseName}}' not found in the response" }; {{/required?}} fromJson(json.value("{{baseName}}"_ls), d->{{paramName}}); {{/properties}}{{/inlineResponse}} return Success; diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp index dbf197ec..6ad8d971 100644 --- a/lib/jobs/basejob.cpp +++ b/lib/jobs/basejob.cpp @@ -560,8 +560,6 @@ QString BaseJob::statusCaption() const return tr("Request was abandoned"); case NetworkError: return tr("Network problems"); - case JsonParseError: - return tr("Response could not be parsed"); case TimeoutError: return tr("Request timed out"); case ContentAccessError: diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h index 30ecceb3..d435749a 100644 --- a/lib/jobs/basejob.h +++ b/lib/jobs/basejob.h @@ -46,28 +46,36 @@ namespace QMatrixClient Q_PROPERTY(QUrl requestUrl READ requestUrl CONSTANT) Q_PROPERTY(int maxRetries READ maxRetries WRITE setMaxRetries) public: - /* Just in case, the values are compatible with KJob - * (which BaseJob used to inherit from). */ enum StatusCode { NoError = 0 // To be compatible with Qt conventions , Success = 0 , Pending = 1 , WarningLevel = 20 - , UnexpectedResponseTypeWarning = 21 + , UnexpectedResponseType = 21 + , UnexpectedResponseTypeWarning = UnexpectedResponseType , Abandoned = 50 //< A very brief period between abandoning and object deletion , ErrorLevel = 100 //< Errors have codes starting from this , NetworkError = 100 - , JsonParseError // TODO: Merge into IncorrectResponseError - , TimeoutError + , Timeout + , TimeoutError = Timeout , ContentAccessError , NotFoundError - , IncorrectRequestError - , IncorrectResponseError - , TooManyRequestsError - , RequestNotImplementedError - , UnsupportedRoomVersionError - , NetworkAuthRequiredError - , UserConsentRequiredError - , UserDefinedError = 200 + , IncorrectRequest + , IncorrectRequestError = IncorrectRequest + , IncorrectResponse + , IncorrectResponseError = IncorrectResponse + , JsonParseError //< deprecated; Use IncorrectResponse instead + = IncorrectResponse + , TooManyRequests + , TooManyRequestsError = TooManyRequests + , RequestNotImplemented + , RequestNotImplementedError = RequestNotImplemented + , UnsupportedRoomVersion + , UnsupportedRoomVersionError = UnsupportedRoomVersion + , NetworkAuthRequired + , NetworkAuthRequiredError = NetworkAuthRequired + , UserConsentRequired + , UserConsentRequiredError = UserConsentRequired + , UserDefinedError = 256 }; /** diff --git a/lib/room.cpp b/lib/room.cpp index 2ce37acc..9042130a 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -75,7 +75,8 @@ enum EventsPlacement : int { Older = -1, Newer = 1 }; class Room::Private { public: - /** Map of user names to users. User names potentially duplicate, hence a multi-hashmap. */ + /// Map of user names to users + /** User names potentially duplicate, hence QMultiHash. */ using members_map_t = QMultiHash<QString, User*>; Private(Connection* c, QString id_, JoinState initialJoinState) @@ -515,7 +516,7 @@ void Room::Private::updateUnreadCount(rev_iter_t from, rev_iter_t to) if(newUnreadMessages > 0) { - // See https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count + // See https://github.com/quotient-im/libQuotient/wiki/unread_count if (unreadMessages < 0) unreadMessages = 0; @@ -556,7 +557,7 @@ Room::Changes Room::Private::promoteReadMarker(User* u, rev_iter_t newMarker, if (et.nsecsElapsed() > profilerMinNsecs() / 10) qCDebug(PROFILER) << "Recounting unread messages took" << et; - // See https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count + // See https://github.com/quotient-im/libQuotient/wiki/unread_count if (unreadMessages == 0) unreadMessages = -1; @@ -612,7 +613,7 @@ void Room::markAllMessagesAsRead() bool Room::canSwitchVersions() const { if (!successorId().isEmpty()) - return false; // Noone can upgrade a room that's already upgraded + return false; // No one can upgrade a room that's already upgraded // TODO, #276: m.room.power_levels const auto* plEvt = @@ -1235,7 +1236,7 @@ void Room::Private::removeMemberFromMap(const QString& username, User* u) } membersMap.remove(username, u); // If there was one namesake besides the removed user, signal member renaming - // for it because it doesn't need to be disambiguated anymore. + // for it because it doesn't need to be disambiguated any more. if (namesake) emit q->memberRenamed(namesake); } @@ -1354,7 +1355,7 @@ void Room::updateData(SyncRoomData&& data, bool fromCache) for( auto&& ephemeralEvent: data.ephemeral ) roomChanges |= processEphemeralEvent(move(ephemeralEvent)); - // See https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count + // See https://github.com/quotient-im/libQuotient/wiki/unread_count if (data.unreadCount != -2 && data.unreadCount != d->unreadMessages) { qCDebug(MAIN) << "Setting unread_count to" << data.unreadCount; @@ -322,7 +322,7 @@ namespace QMatrixClient bool hasAccountData(const QString& type) const; /** Get a generic account data event of the given type - * This returns a generic hashmap for any room account data event + * This returns a generic hash map for any room account data event * stored on the server. Tags and read markers cannot be retrieved * using this method _yet_. */ @@ -516,7 +516,7 @@ namespace QMatrixClient /** A common signal for various kinds of changes in the room * Aside from all changes in the room state - * @param changes a set of flags describing what changes occured + * @param changes a set of flags describing what changes occurred * upon the last sync * \sa StateChange */ @@ -524,7 +524,7 @@ namespace QMatrixClient /** * \brief The room name, the canonical alias or other aliases changed * - * Not triggered when displayname changes. + * Not triggered when display name changes. */ void namesChanged(Room* room); void displaynameAboutToChange(Room* room); @@ -581,7 +581,7 @@ namespace QMatrixClient /// The room's version stability may have changed void stabilityUpdated(QString recommendedDefault, QStringList stableVersions); - /// This room has been upgraded and won't receive updates anymore + /// This room has been upgraded and won't receive updates any more void upgraded(QString serverMessage, Room* successor); /// An attempted room upgrade has failed void upgradeFailed(QString errorMessage); diff --git a/lib/user.cpp b/lib/user.cpp index 7f3f11f6..7b695618 100644 --- a/lib/user.cpp +++ b/lib/user.cpp @@ -33,9 +33,6 @@ #include <QtCore/QStringBuilder> #include <QtCore/QElapsedTimer> -#include <QtCore/QCryptographicHash> -#include <QtCore/QtEndian> - #include <functional> using namespace QMatrixClient; @@ -50,23 +47,8 @@ class User::Private return Avatar(move(url)); } - qreal makeHueF() - { - Q_ASSERT(!userId.isEmpty()); - QByteArray hash = QCryptographicHash::hash(userId.toUtf8(), - QCryptographicHash::Sha1); - QDataStream dataStream(qToLittleEndian(hash).left(2)); - dataStream.setByteOrder(QDataStream::LittleEndian); - quint16 hashValue; - dataStream >> hashValue; - const auto hueF = - qreal(hashValue)/std::numeric_limits<quint16>::max(); - Q_ASSERT((0 <= hueF) && (hueF <= 1)); - return hueF; - } - Private(QString userId, Connection* connection) - : userId(move(userId)), connection(connection), hueF(makeHueF()) + : userId(move(userId)), connection(connection), hueF(stringToHueF(this->userId)) { } QString userId; diff --git a/lib/util.cpp b/lib/util.cpp index 4e17d2f9..01d4e77b 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -23,6 +23,10 @@ #include <QtCore/QDir> #include <QtCore/QStringBuilder> +#include <QtCore/QCryptographicHash> +#include <QtCore/QtEndian> +#include <QtCore/QDataStream> + static const auto RegExpOptions = QRegularExpression::CaseInsensitiveOption | QRegularExpression::OptimizeOnFirstUsageOption @@ -93,6 +97,21 @@ QString QMatrixClient::cacheLocation(const QString& dirName) return cachePath; } +qreal QMatrixClient::stringToHueF(const QString &string) +{ + Q_ASSERT(!string.isEmpty()); + QByteArray hash = QCryptographicHash::hash(string.toUtf8(), + QCryptographicHash::Sha1); + QDataStream dataStream(qToLittleEndian(hash).left(2)); + dataStream.setByteOrder(QDataStream::LittleEndian); + quint16 hashValue; + dataStream >> hashValue; + const auto hueF = + qreal(hashValue)/std::numeric_limits<quint16>::max(); + Q_ASSERT((0 <= hueF) && (hueF <= 1)); + return hueF; +} + // Tests for function_traits<> #ifdef Q_CC_CLANG @@ -314,5 +314,13 @@ namespace QMatrixClient * \param dir path to cache directory relative to the standard cache path */ QString cacheLocation(const QString& dirName); + + /** Hue color component of based of the hash of the string. + * The implementation is based on XEP-0392: + * https://xmpp.org/extensions/xep-0392.html + * Naming and range are the same as QColor's hueF method: + * https://doc.qt.io/qt-5/qcolor.html#integer-vs-floating-point-precision + */ + qreal stringToHueF(const QString& string); } // namespace QMatrixClient |