Implement UI and serialization logic for sender modes
authorJanne Koschinski <janne@kuschku.de>
Wed, 20 Dec 2017 02:22:31 +0000 (03:22 +0100)
committerManuel Nickschas <sputnick@quassel-irc.org>
Thu, 21 Dec 2017 11:54:06 +0000 (12:54 +0100)
18 files changed:
src/client/clientauthhandler.cpp
src/common/message.cpp
src/common/peer.cpp
src/common/peer.h
src/common/protocol.h
src/common/protocols/datastream/datastreampeer.cpp
src/common/protocols/legacy/legacypeer.cpp
src/common/quassel.h
src/common/remotepeer.cpp
src/common/signalproxy.cpp
src/common/signalproxy.h
src/core/coreauthhandler.cpp
src/qtui/chatviewsettings.h
src/qtui/qtuistyle.cpp
src/qtui/qtuistyle.h
src/qtui/settingspages/chatviewsettingspage.ui
src/uisupport/uistyle.cpp
src/uisupport/uistyle.h

index 4a99890..ce7c58d 100644 (file)
@@ -288,7 +288,7 @@ void ClientAuthHandler::startRegistration()
     useSsl = _account.useSsl();
 #endif
 
-    _peer->dispatch(RegisterClient(Quassel::buildInfo().fancyVersionString, Quassel::buildInfo().commitDate, useSsl));
+    _peer->dispatch(RegisterClient(Quassel::buildInfo().fancyVersionString, Quassel::buildInfo().commitDate, useSsl, Quassel::features()));
 }
 
 
@@ -305,7 +305,8 @@ void ClientAuthHandler::handle(const ClientRegistered &msg)
     _backendInfo = msg.backendInfo;
     _authenticatorInfo = msg.authenticatorInfo;
 
-    Client::setCoreFeatures(static_cast<Quassel::Features>(msg.coreFeatures));
+    Client::setCoreFeatures(Quassel::Features(msg.coreFeatures));
+    SignalProxy::current()->sourcePeer()->setFeatures(Quassel::Features(msg.coreFeatures));
 
     // The legacy protocol enables SSL at this point
     if(_legacy && _account.useSsl())
index 25ea45c..a0e480a 100644 (file)
@@ -21,6 +21,8 @@
 #include "message.h"
 
 #include "util.h"
+#include "signalproxy.h"
+#include "peer.h"
 
 #include <QDataStream>
 
@@ -51,28 +53,52 @@ Message::Message(const QDateTime &ts, const BufferInfo &bufferInfo, Type type, c
 QDataStream &operator<<(QDataStream &out, const Message &msg)
 {
     // We do not serialize the sender prefixes until we have a new protocol or client-features implemented
-    out << msg.msgId() << (quint32)msg.timestamp().toTime_t() << (quint32)msg.type() << (quint8)msg.flags()
-    << msg.bufferInfo() << msg.sender().toUtf8() << msg.contents().toUtf8();
+    out << msg.msgId()
+        << (quint32) msg.timestamp().toTime_t()
+        << (quint32) msg.type()
+        << (quint8) msg.flags()
+        << msg.bufferInfo()
+        << msg.sender().toUtf8();
+
+    if (SignalProxy::current()->targetPeer()->features().testFlag(Quassel::Feature::SenderPrefixes))
+        out << msg.senderPrefixes().toUtf8();
+
+    out << msg.contents().toUtf8();
     return out;
 }
 
 
 QDataStream &operator>>(QDataStream &in, Message &msg)
 {
-    quint8 f;
-    quint32 t;
-    quint32 ts;
-    QByteArray s, m;
-    BufferInfo buf;
-    in >> msg._msgId >> ts >> t >> f >> buf >> s >> m;
-    msg._type = (Message::Type)t;
-    msg._flags = (Message::Flags)f;
-    msg._bufferInfo = buf;
-    msg._timestamp = QDateTime::fromTime_t(ts);
-    msg._sender = QString::fromUtf8(s);
-    // We do not serialize the sender prefixes until we have a new protocol or client-features implemented
-    msg._senderPrefixes = QString("");
-    msg._contents = QString::fromUtf8(m);
+    in >> msg._msgId;
+
+    quint32 timeStamp;
+    in >> timeStamp;
+    msg._timestamp = QDateTime::fromTime_t(timeStamp);
+
+    quint32 type;
+    in >> type;
+    msg._type = Message::Type(type);
+
+    quint8 flags;
+    in >> flags;
+    msg._flags = Message::Flags(flags);
+
+    in >> msg._bufferInfo;
+
+    QByteArray sender;
+    in >> sender;
+    msg._sender = QString::fromUtf8(sender);
+
+    QByteArray senderPrefixes;
+    if (SignalProxy::current()->sourcePeer()->features().testFlag(Quassel::Feature::SenderPrefixes))
+        in >> senderPrefixes;
+    msg._senderPrefixes = QString::fromUtf8(senderPrefixes);
+
+    QByteArray contents;
+    in >> contents;
+    msg._contents = QString::fromUtf8(contents);
+
     return in;
 }
 
index b0eee44..9a9e3f5 100644 (file)
@@ -57,6 +57,14 @@ void Peer::setClientVersion(const QString &clientVersion) {
     _clientVersion = clientVersion;
 }
 
+Quassel::Features Peer::features() const {
+    return _features;
+}
+
+void Peer::setFeatures(Quassel::Features features) {
+    _features = features;
+}
+
 int Peer::id() const {
     return _id;
 }
index 6f17ed6..34a5661 100644 (file)
@@ -28,6 +28,7 @@
 #include "authhandler.h"
 #include "protocol.h"
 #include "signalproxy.h"
+#include "quassel.h"
 
 class Peer : public QObject
 {
@@ -51,6 +52,9 @@ public:
     QString clientVersion() const;
     void setClientVersion(const QString &clientVersion);
 
+    Quassel::Features features() const;
+    void setFeatures(Quassel::Features features);
+
     int id() const;
     void setId(int id);
 
@@ -102,6 +106,7 @@ private:
 
     QString _buildDate;
     QString _clientVersion;
+    Quassel::Features _features;
 
     int _id = -1;
 };
index bf6c401..4576080 100644 (file)
@@ -57,16 +57,18 @@ struct HandshakeMessage {
 
 struct RegisterClient : public HandshakeMessage
 {
-    inline RegisterClient(const QString &clientVersion, const QString &buildDate, bool sslSupported = false)
+    inline RegisterClient(const QString &clientVersion, const QString &buildDate, bool sslSupported = false, int32_t features = 0)
     : clientVersion(clientVersion)
     , buildDate(buildDate)
-    , sslSupported(sslSupported) {}
+    , sslSupported(sslSupported)
+    , clientFeatures(features) {}
 
     QString clientVersion;
     QString buildDate;
 
     // this is only used by the LegacyProtocol in compat mode
     bool sslSupported;
+    int32_t clientFeatures;
 };
 
 
index 6a21a16..e91c977 100644 (file)
@@ -116,7 +116,7 @@ void DataStreamPeer::handleHandshakeMessage(const QVariantList &mapData)
     }
 
     if (msgType == "ClientInit") {
-        handle(RegisterClient(m["ClientVersion"].toString(), m["ClientDate"].toString(), false)); // UseSsl obsolete
+        handle(RegisterClient(m["ClientVersion"].toString(), m["ClientDate"].toString(), false, m["Features"].toInt())); // UseSsl obsolete
     }
 
     else if (msgType == "ClientInitReject") {
@@ -168,6 +168,7 @@ void DataStreamPeer::dispatch(const RegisterClient &msg) {
     m["MsgType"] = "ClientInit";
     m["ClientVersion"] = msg.clientVersion;
     m["ClientDate"] = msg.buildDate;
+    m["Features"] = msg.clientFeatures;
 
     writeMessage(m);
 }
index f59dffa..ebbd164 100644 (file)
@@ -151,7 +151,7 @@ void LegacyPeer::handleHandshakeMessage(const QVariant &msg)
             socket()->setProperty("UseCompression", true);
         }
 #endif
-        handle(RegisterClient(m["ClientVersion"].toString(), m["ClientDate"].toString(), m["UseSsl"].toBool()));
+        handle(RegisterClient(m["ClientVersion"].toString(), m["ClientDate"].toString(), m["UseSsl"].toBool(), m["Features"].toInt()));
     }
 
     else if (msgType == "ClientInitReject") {
@@ -214,6 +214,7 @@ void LegacyPeer::dispatch(const RegisterClient &msg) {
     m["MsgType"] = "ClientInit";
     m["ClientVersion"] = msg.clientVersion;
     m["ClientDate"] = msg.buildDate;
+    m["Features"] = msg.clientFeatures;
 
     // FIXME only in compat mode
     m["ProtocolVersion"] = protocolVersion;
index d20fdc2..b30872d 100644 (file)
@@ -79,8 +79,9 @@ public:
         Authenticators = 0x0400,           /// Whether or not the core supports auth backends.
         BufferActivitySync = 0x0800,       /// Sync buffer activity status
         CoreSideHighlights = 0x1000,       /// Core-Side highlight configuration and matching
+        SenderPrefixes = 0x2000,           /// Show prefixes for senders in backlog
 
-        NumFeatures = 0x1000
+        NumFeatures = 0x2000
     };
     Q_DECLARE_FLAGS(Features, Feature)
 
index 60c8b63..e25cbb3 100644 (file)
@@ -208,8 +208,16 @@ void RemotePeer::close(const QString &reason)
 void RemotePeer::onReadyRead()
 {
     QByteArray msg;
-    while (readMessage(msg))
+    while (readMessage(msg)) {
+        if (SignalProxy::current())
+            SignalProxy::current()->setSourcePeer(this);
+
         processMessage(msg);
+
+
+        if (SignalProxy::current())
+            SignalProxy::current()->setSourcePeer(nullptr);
+    }
 }
 
 
index db4a675..bcc639f 100644 (file)
@@ -221,6 +221,8 @@ void SignalProxy::setProxyMode(ProxyMode mode)
         initClient();
 }
 
+thread_local SignalProxy *SignalProxy::_current;
+
 
 void SignalProxy::init()
 {
@@ -230,6 +232,7 @@ void SignalProxy::init()
     setHeartBeatInterval(30);
     setMaxHeartBeatCount(2);
     _secure = false;
+    _current = this;
     updateSecureState();
 }
 
@@ -514,21 +517,28 @@ template<class T>
 void SignalProxy::dispatch(const T &protoMessage)
 {
     for (auto peer : _peerMap.values()) {
+        _targetPeer = peer;
+
         if (peer->isOpen())
             peer->dispatch(protoMessage);
         else
             QCoreApplication::postEvent(this, new ::RemovePeerEvent(peer));
     }
+    _targetPeer = nullptr;
 }
 
 
 template<class T>
 void SignalProxy::dispatch(Peer *peer, const T &protoMessage)
 {
+    _targetPeer = peer;
+
     if (peer && peer->isOpen())
         peer->dispatch(protoMessage);
     else
         QCoreApplication::postEvent(this, new ::RemovePeerEvent(peer));
+
+    _targetPeer = nullptr;
 }
 
 
@@ -571,7 +581,9 @@ void SignalProxy::handle(Peer *peer, const SyncMessage &syncMessage)
         if (eMeta->argTypes(receiverId).count() > 1)
             returnParams << syncMessage.params;
         returnParams << returnValue;
+        _targetPeer = peer;
         peer->dispatch(SyncMessage(syncMessage.className, syncMessage.objectName, eMeta->methodName(receiverId), returnParams));
+        _targetPeer = nullptr;
     }
 
     // send emit update signal
@@ -594,7 +606,9 @@ void SignalProxy::handle(Peer *peer, const InitRequest &initRequest)
     }
 
     SyncableObject *obj = _syncSlave[initRequest.className][initRequest.objectName];
+    _targetPeer = peer;
     peer->dispatch(InitData(initRequest.className, initRequest.objectName, initData(obj)));
+    _targetPeer = nullptr;
 }
 
 
@@ -851,6 +865,22 @@ void SignalProxy::restrictTargetPeers(QSet<Peer*> peers, std::function<void()> c
     _restrictedTargets = previousRestrictedTargets;
 }
 
+Peer *SignalProxy::sourcePeer() {
+    return _sourcePeer;
+}
+
+void SignalProxy::setSourcePeer(Peer *sourcePeer) {
+    _sourcePeer = sourcePeer;
+}
+
+Peer *SignalProxy::targetPeer() {
+    return _targetPeer;
+}
+
+void SignalProxy::setTargetPeer(Peer *targetPeer) {
+    _targetPeer = targetPeer;
+}
+
 // ==================================================
 //  ExtendedMetaObject
 // ==================================================
index 63d3438..77ef3a4 100644 (file)
 
 #include <QEvent>
 #include <QSet>
+#include <QThreadStorage>
 
 #include <functional>
+#include <memory>
 
 #include "protocol.h"
 
@@ -80,6 +82,10 @@ public:
     void dumpProxyStats();
     void dumpSyncMap(SyncableObject *object);
 
+    static SignalProxy *current() {
+        return _current;
+    }
+
     /**@{*/
     /**
      * This method allows to send a signal only to a limited set of peers
@@ -111,7 +117,14 @@ public:
     /**
      * @return If handling a signal, the Peer from which the current signal originates
      */
-    Peer *sourcePeer() { return _sourcePeer; }
+    Peer *sourcePeer();
+    void setSourcePeer(Peer *sourcePeer);
+
+    /**
+     * @return If sending a signal, the Peer to which the current signal is directed
+     */
+    Peer *targetPeer();
+    void setTargetPeer(Peer *targetPeer);
 
 public slots:
     void detachObject(QObject *obj);
@@ -206,6 +219,9 @@ private:
     bool _restrictMessageTarget = false;
 
     Peer *_sourcePeer = nullptr;
+    Peer *_targetPeer = nullptr;
+
+    thread_local static SignalProxy *_current;
 
     friend class SignalRelay;
     friend class SyncableObject;
index a2367c3..c01115f 100644 (file)
@@ -185,6 +185,7 @@ void CoreAuthHandler::handle(const RegisterClient &msg)
 
     _peer->setBuildDate(msg.buildDate);
     _peer->setClientVersion(msg.clientVersion);
+    _peer->setFeatures(Quassel::Features(msg.clientFeatures));
 
     if (_legacy && useSsl)
         startSsl();
index b727ab8..a0f70f9 100644 (file)
@@ -73,6 +73,13 @@ public:
      */
     inline void setTimestampFormatString(const QString &format) { setLocalValue("TimestampFormat", format); }
 
+    /**
+     * Gets if prefixmodes are shown before sender names
+     *
+     * @returns True if sender prefixmodes enabled, otherwise false
+     */
+    inline bool showSenderPrefixes() { return localValue("ShowSenderPrefixes", false).toBool(); }
+
     /**
      * Gets if brackets are shown around sender names
      *
index d167b2e..60d858a 100644 (file)
@@ -32,6 +32,8 @@ QtUiStyle::QtUiStyle(QObject *parent) : UiStyle(parent)
     updateUseCustomTimestampFormat();
     s.notify("TimestampFormat", this, SLOT(updateTimestampFormatString()));
     updateTimestampFormatString();
+    s.notify("ShowSenderPrefixes", this, SLOT(updateShowSenderPrefixes()));
+    updateShowSenderPrefixes();
     s.notify("ShowSenderBrackets", this, SLOT(updateShowSenderBrackets()));
     updateShowSenderBrackets();
 
@@ -54,6 +56,12 @@ void QtUiStyle::updateTimestampFormatString()
     setTimestampFormatString(s.timestampFormatString());
 }
 
+void QtUiStyle::updateShowSenderPrefixes()
+{
+    ChatViewSettings s;
+    enableSenderPrefixes(s.showSenderPrefixes());
+}
+
 void QtUiStyle::updateShowSenderBrackets()
 {
     ChatViewSettings s;
index 733e73e..8b9b17c 100644 (file)
@@ -59,6 +59,11 @@ private slots:
      * Updates knowledge of the current timestamp format
      */
     void updateTimestampFormatString();
+    
+    /**
+     * Updates knowledge of whether or not to show sender prefixmodes
+     */
+    void updateShowSenderPrefixes();
 
     /**
      * Updates knowledge of whether or not to show sender brackets
index 80c6cff..55fbc08 100644 (file)
      </property>
     </widget>
    </item>
+   <item>
+    <widget class="QCheckBox" name="showSenderPrefixes">
+     <property name="toolTip">
+      <string>Shows the modes of senders before their name (e.g. @, +)</string>
+     </property>
+     <property name="text">
+      <string>Show sendermodes in front of nicknames:</string>
+     </property>
+     <property name="checked">
+      <bool>true</bool>
+     </property>
+     <property name="defaultValue" stdset="0">
+      <bool>true</bool>
+     </property>
+     <property name="settingsKey" stdset="0">
+      <string notr="true">ShowSenderPrefixes</string>
+     </property>
+    </widget>
+   </item>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout_3">
      <item>
index f35543d..3b9e079 100644 (file)
@@ -32,6 +32,7 @@ QHash<QString, UiStyle::FormatType> UiStyle::_formatCodes;
 bool UiStyle::_useCustomTimestampFormat;       /// If true, use the custom timestamp format
 QString UiStyle::_timestampFormatString;       /// Timestamp format
 QString UiStyle::_systemTimestampFormatString; /// Cached copy of system locale timestamp format
+bool UiStyle::_showSenderPrefixes;             /// If true, show prefixmodes before sender names
 bool UiStyle::_showSenderBrackets;             /// If true, show brackets around sender names
 
 UiStyle::UiStyle(QObject *parent)
@@ -74,6 +75,7 @@ UiStyle::UiStyle(QObject *parent)
     // in there.
     setUseCustomTimestampFormat(false);
     setTimestampFormatString(" hh:mm:ss");
+    enableSenderPrefixes(false);
     enableSenderBrackets(true);
 
     // BufferView / NickView settings
@@ -224,6 +226,13 @@ void UiStyle::setTimestampFormatString(const QString &format)
     }
 }
 
+void UiStyle::enableSenderPrefixes(bool enabled)
+{
+    if (_showSenderPrefixes != enabled) {
+        _showSenderPrefixes = enabled;
+    }
+}
+
 void UiStyle::enableSenderBrackets(bool enabled)
 {
     if (_showSenderBrackets != enabled) {
@@ -908,15 +917,20 @@ QString UiStyle::StyledMessage::plainSender() const
 
 QString UiStyle::StyledMessage::decoratedSender() const
 {
+    QString _senderPrefixes;
+    if (_showSenderPrefixes) {
+        _senderPrefixes = senderPrefixes();
+    }
+
     switch (type()) {
     case Message::Plain:
         if (_showSenderBrackets)
-            return QString("<%1>").arg(plainSender());
+            return QString("<%1%2>").arg(_senderPrefixes, plainSender());
         else
-            return QString("%1").arg(plainSender());
+            return QString("%1%2").arg(_senderPrefixes, plainSender());
         break;
     case Message::Notice:
-        return QString("[%1]").arg(plainSender()); break;
+        return QString("[%1%2]").arg(_senderPrefixes, plainSender()); break;
     case Message::Action:
         return "-*-"; break;
     case Message::Nick:
@@ -950,7 +964,7 @@ QString UiStyle::StyledMessage::decoratedSender() const
     case Message::Invite:
         return "->"; break;
     default:
-        return QString("%1").arg(plainSender());
+        return QString("%1%2").arg(_senderPrefixes, plainSender());
     }
 }
 
index 030c1ac..d565e5b 100644 (file)
@@ -284,6 +284,12 @@ protected:
      * @param[in] format   Timestamp format string
      */
     static void setTimestampFormatString(const QString &format);
+    /**
+     * Updates the local setting cache of whether or not to show sender prefixmodes
+     *
+     * @param[in] enabled  If true, sender prefixmodes are enabled, otherwise false.
+     */
+    static void enableSenderPrefixes(bool enabled);
 
     /**
      * Updates the local setting cache of whether or not to show sender brackets
@@ -309,6 +315,7 @@ private:
     static bool _useCustomTimestampFormat;        /// If true, use the custom timestamp format
     static QString _systemTimestampFormatString;  /// Cached copy of system locale timestamp format
     static QString _timestampFormatString;        /// Timestamp format string
+    static bool _showSenderPrefixes;              /// If true, show prefixmodes before sender names
     static bool _showSenderBrackets;              /// If true, show brackets around sender names
 
     QIcon _channelJoinedIcon;