add lobby chat features to room chat
authorsheepluva
Wed, 20 Mar 2013 23:18:46 +0100
changeset 8759 1a4b9b9fe2b0
parent 8757 266df6d5ed73
child 8762 388d2bf73ff9
add lobby chat features to room chat TODO: fix player info
QTfrontend/hwform.cpp
QTfrontend/net/newnetclient.cpp
QTfrontend/net/newnetclient.h
QTfrontend/net/proto.cpp
QTfrontend/net/proto.h
QTfrontend/res/css/chat.css
QTfrontend/ui/widget/chatwidget.cpp
QTfrontend/ui/widget/chatwidget.h
--- a/QTfrontend/hwform.cpp	Wed Mar 20 09:13:05 2013 +0400
+++ b/QTfrontend/hwform.cpp	Wed Mar 20 23:18:46 2013 +0100
@@ -1251,11 +1251,11 @@
 // net page stuff
     connect(hwnet, SIGNAL(roomNameUpdated(const QString &)),
             ui.pageNetGame, SLOT(setRoomName(const QString &)), Qt::QueuedConnection);
-    connect(hwnet, SIGNAL(chatStringFromNet(const QString&)),
-            ui.pageNetGame->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
+    connect(hwnet, SIGNAL(roomChatAction(const QString&, const QString&)),
+            ui.pageNetGame->chatWidget, SLOT(onChatAction(const QString&, const QString&)), Qt::QueuedConnection);
+    connect(hwnet, SIGNAL(roomChatMessage(const QString&, const QString&)),
+            ui.pageNetGame->chatWidget, SLOT(onChatMessage(const QString&, const QString&)), Qt::QueuedConnection);
 
-    connect(hwnet, SIGNAL(chatStringFromMe(const QString&)),
-            ui.pageNetGame->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(roomMaster(bool)),
             ui.pageNetGame->chatWidget, SLOT(adminAccess(bool)), Qt::QueuedConnection);
     connect(ui.pageNetGame->chatWidget, SIGNAL(chatLine(const QString&)),
@@ -1289,12 +1289,10 @@
 // chatting
     connect(ui.pageRoomsList->chatWidget, SIGNAL(chatLine(const QString&)),
             hwnet, SLOT(chatLineToLobby(const QString&)));
-    connect(hwnet, SIGNAL(chatStringLobby(const QString&)),
-            ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
-    connect(hwnet, SIGNAL(chatStringLobby(const QString&, const QString&)),
-            ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&, const QString&)), Qt::QueuedConnection);
-    connect(hwnet, SIGNAL(chatStringFromMeLobby(const QString&)),
-            ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
+    connect(hwnet, SIGNAL(lobbyChatAction(const QString&,const QString&)),
+            ui.pageRoomsList->chatWidget, SLOT(onChatAction(const QString&,const QString&)), Qt::QueuedConnection);
+    connect(hwnet, SIGNAL(lobbyChatMessage(const QString&, const QString&)),
+            ui.pageRoomsList->chatWidget, SLOT(onChatMessage(const QString&, const QString&)), Qt::QueuedConnection);
 
 // nick list stuff
     connect(hwnet, SIGNAL(nickAdded(const QString&, bool)),
@@ -1305,6 +1303,8 @@
             ui.pageRoomsList->chatWidget, SLOT(nickAdded(const QString&, bool)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(nickRemovedLobby(const QString&)),
             ui.pageRoomsList->chatWidget, SLOT(nickRemoved(const QString&)), Qt::QueuedConnection);
+    connect(hwnet, SIGNAL(nickRemovedLobby(const QString&, const QString&)),
+            ui.pageRoomsList->chatWidget, SLOT(nickRemoved(const QString&, const QString&)), Qt::QueuedConnection);
 
 // teams selecting stuff
     connect(ui.pageNetGame->pNetTeamsWidget, SIGNAL(hhogsNumChanged(const HWTeam&)),
--- a/QTfrontend/net/newnetclient.cpp	Wed Mar 20 09:13:05 2013 +0400
+++ b/QTfrontend/net/newnetclient.cpp	Wed Mar 20 23:18:46 2013 +0100
@@ -336,10 +336,24 @@
             qWarning("Net: Empty CHAT message");
             return;
         }
+
+        QString action = HWProto::chatStringToAction(lst[2]);
+
         if (netClientState == InLobby)
-            emit chatStringLobby(lst[1], HWProto::formatChatMsgForFrontend(lst[2]));
+        {
+            if (action != NULL)
+                emit lobbyChatAction(lst[1], action);
+            else
+                emit lobbyChatMessage(lst[1], lst[2]);
+        }
         else
+        {
             emit chatStringFromNet(HWProto::formatChatMsg(lst[1], lst[2]));
+            if (action != NULL)
+                emit roomChatAction(lst[1], action);
+            else
+                emit roomChatMessage(lst[1], lst[2]);
+        }
         return;
     }
 
@@ -350,12 +364,13 @@
             qWarning("Net: Malformed INFO message");
             return;
         }
-        QStringList tmp = lst;
-        tmp.removeFirst();
-        if (netClientState == InLobby)
-            emit chatStringLobby(tmp.join("\n").prepend('\x01'));
-        else
+        emit playerInfo(lst[1], lst[2], lst[3], lst[4]);
+        if (netClientState != InLobby)
+        {
+            QStringList tmp = lst;
+            tmp.removeFirst();
             emit chatStringFromNet(tmp.join("\n").prepend('\x01'));
+        }
         return;
     }
 
@@ -492,7 +507,6 @@
 
             m_playersModel->addPlayer(lst[i]);
             emit nickAddedLobby(lst[i], false);
-            emit chatStringLobby(lst[i], tr("%1 *** %2 has joined").arg('\x03').arg("|nick|"));
         }
         return;
     }
@@ -539,11 +553,11 @@
             qWarning("Net: Bad LOBBY:LEFT message");
             return;
         }
-        emit nickRemovedLobby(lst[1]);
+
         if (lst.size() < 3)
-            emit chatStringLobby(tr("%1 *** %2 has left").arg('\x03').arg(lst[1]));
+            emit nickRemovedLobby(lst[1]);
         else
-            emit chatStringLobby(lst[1], tr("%1 *** %2 has left (%3)").arg('\x03').arg("|nick|", lst[2]));
+            emit nickRemovedLobby(lst[1], lst[2]);
 
         m_playersModel->removePlayer(lst[1]);
 
@@ -841,7 +855,11 @@
     if(str != "")
     {
         RawSendNet(QString("CHAT") + delimeter + str);
-        emit(chatStringFromMe(HWProto::formatChatMsg(mynick, str)));
+        QString action = HWProto::chatStringToAction(str);
+        if (action != NULL)
+            emit(roomChatAction(mynick, action));
+        else
+            emit(roomChatMessage(mynick, str));
     }
 }
 
@@ -850,7 +868,11 @@
     if(str != "")
     {
         RawSendNet(QString("CHAT") + delimeter + str);
-        emit chatStringLobby(mynick, HWProto::formatChatMsgForFrontend(str));
+        QString action = HWProto::chatStringToAction(str);
+        if (action != NULL)
+            emit(lobbyChatAction(mynick, action));
+        else
+            emit(lobbyChatMessage(mynick, str));
     }
 }
 
--- a/QTfrontend/net/newnetclient.h	Wed Mar 20 09:13:05 2013 +0400
+++ b/QTfrontend/net/newnetclient.h	Wed Mar 20 23:18:46 2013 +0100
@@ -103,6 +103,7 @@
         void nickRemoved(const QString& nick);
         void nickAddedLobby(const QString& nick, bool notifyNick);
         void nickRemovedLobby(const QString& nick);
+        void nickRemovedLobby(const QString& nick, const QString& message);
         void FromNet(const QByteArray & buf);
         void adminAccess(bool);
         void roomMaster(bool);
@@ -117,11 +118,16 @@
         void RemoveNetTeam(const HWTeam&);
         void hhnumChanged(const HWTeam&);
         void teamColorChanged(const HWTeam&);
-        void chatStringLobby(const QString&);
-        void chatStringLobby(const QString&, const QString&);
+        void playerInfo(
+            const QString & name,
+            const QString & ip,
+            const QString & version,
+            const QString & roomInfo);
+        void lobbyChatMessage(const QString & nick, const QString & message);
+        void lobbyChatAction(const QString & nick, const QString & action);
+        void roomChatMessage(const QString & nick, const QString & message);
+        void roomChatAction(const QString & nick, const QString & action);
         void chatStringFromNet(const QString&);
-        void chatStringFromMe(const QString&);
-        void chatStringFromMeLobby(const QString&);
 
         void roomsList(const QStringList&);
         void serverMessage(const QString &);
--- a/QTfrontend/net/proto.cpp	Wed Mar 20 09:13:05 2013 +0400
+++ b/QTfrontend/net/proto.cpp	Wed Mar 20 23:18:46 2013 +0100
@@ -45,11 +45,6 @@
     return buf;
 }
 
-QString HWProto::formatChatMsgForFrontend(const QString & msg)
-{
-    return formatChatMsg("|nick|", msg);
-}
-
 QString HWProto::formatChatMsg(const QString & nick, const QString & msg)
 {
     if(msg.left(4) == "/me ")
@@ -57,3 +52,11 @@
     else
         return QString("\x01%1: %2").arg(nick).arg(msg);
 }
+
+QString HWProto::chatStringToAction(const QString & string)
+{
+    if(string.left(4) == "/me ")
+        return string.mid(4);
+    else
+        return NULL;
+}
--- a/QTfrontend/net/proto.h	Wed Mar 20 09:13:05 2013 +0400
+++ b/QTfrontend/net/proto.h	Wed Mar 20 23:18:46 2013 +0100
@@ -35,6 +35,12 @@
         static QByteArray & addStringListToBuffer(QByteArray & buf, const QStringList & strList);
         static QString formatChatMsg(const QString & nick, const QString & msg);
         static QString formatChatMsgForFrontend(const QString & msg);
+        /**
+         * @brief Determines if a chat string represents a chat action and returns the action.
+         * @param string chat string
+         * @return the action-message or NULL if message is no action
+         */
+        static QString chatStringToAction(const QString & string);
 };
 
 #endif // _PROTO_H
--- a/QTfrontend/res/css/chat.css	Wed Mar 20 09:13:05 2013 +0400
+++ b/QTfrontend/res/css/chat.css	Wed Mar 20 23:18:46 2013 +0100
@@ -61,15 +61,20 @@
 .msg_FriendChat .nick { color: #30ff30; }
 .msg_UserJoin { color: #c0c0c0; }
 .msg_UserJoin .nick { color: #d0d0d0; }
+.msg_UserLeave { color: #b8b8b8; }
+.msg_UserLeave .nick { color: #c8c8c8; }
 .msg_FriendJoin { font-weight: bold; color: #c0f0c0; }
 .msg_FriendJoin .nick { color: #d8f0d8; }
+.msg_FriendLeave { font-weight: bold; color: #ffe090; }
+.msg_FriendLeave .nick { color: #f8e878; }
 .msg_UserAction { color: #ff80ff; }
 .msg_UserAction .nick { color: #ffa0ff;}
 .msg_FriendAction { color: #ff00ff; }
 .msg_FriendAction .nick { color: #ff30ff; }
 
-/* uncomment next line to disable join and leave messages of non-friends */
+/* uncomment next lines to disable join and leave messages of non-friends */
 /* .msg_UserJoin { display:none; } */
+/* .msg_UserLeave { display:none; } */
 
 /* timestamps */
 .timestamp {
--- a/QTfrontend/ui/widget/chatwidget.cpp	Wed Mar 20 09:13:05 2013 +0400
+++ b/QTfrontend/ui/widget/chatwidget.cpp	Wed Mar 20 23:18:46 2013 +0100
@@ -368,15 +368,43 @@
     return QString("<span class=\"nick\">%1</span>").arg(Qt::escape(nickname));
 }
 
+const QRegExp HWChatWidget::URLREGEXP = QRegExp("(http://)?(www\\.)?((hedgewars\\.org|code\\.google\\.com|googlecode\\.com|hh\\.unit22\\.org)(/[^ ]*)?)");
 
-void HWChatWidget::onChatString(const QString& str)
+bool HWChatWidget::containsHighlight(const QString & sender, const QString & message)
 {
-    onChatString("", str);
+    if ((sender != m_userNick) && (!m_userNick.isEmpty()))
+    {
+        QString lcStr = message.toLower();
+
+        foreach (const QRegExp & hl, m_highlights)
+        {
+            if (lcStr.contains(hl))
+                return true;
+        }
+    }
+    return false;
 }
 
-const QRegExp HWChatWidget::URLREGEXP = QRegExp("(http://)?(www\\.)?(hedgewars\\.org(/[^ ]*)?)");
+QString HWChatWidget::messageToHTML(const QString & message)
+{
+    QString formattedStr = Qt::escape(message);
+    // link some urls
+    formattedStr = formattedStr.replace(URLREGEXP, "<a href=\"http://\\3\">\\3</a>");
+    return formattedStr;
+}
 
-void HWChatWidget::onChatString(const QString& nick, const QString& str)
+void HWChatWidget::onChatAction(const QString & nick, const QString & action)
+{
+    printChatString(nick, "* " + linkedNick(nick) + " " + messageToHTML(action), "Action", containsHighlight(nick, action));
+}
+
+void HWChatWidget::onChatMessage(const QString & nick, const QString & message)
+{
+    printChatString(nick, linkedNick(nick) + ": " + messageToHTML(message), "Chat", containsHighlight(nick, message));
+}
+
+void HWChatWidget::printChatString(
+    const QString & nick, const QString & str, const QString & cssClassPart, bool highlight)
 {
     QSortFilterProxyModel * playersSortFilterModel = qobject_cast<QSortFilterProxyModel *>(chatNicks->model());
     if(!playersSortFilterModel)
@@ -387,58 +415,15 @@
     if(!players)
         return;
 
-    if (!nick.isEmpty())
-    {
-        // don't show chat lines that are from ignored nicks
-        if (players->isFlagSet(nick, PlayersListModel::Ignore))
-            return;
-    }
+    // don't show chat lines that are from ignored nicks
+    if (players->isFlagSet(nick, PlayersListModel::Ignore))
+        return;
 
     bool isFriend = (!nick.isEmpty()) && players->isFlagSet(nick, PlayersListModel::Friend);
 
-    QString formattedStr = Qt::escape(str.mid(1));
-    // make hedgewars.org urls actual links
-    formattedStr = formattedStr.replace(URLREGEXP, "<a href=\"http://\\3\">\\3</a>");
-
-    // link the nick
-    if(!nick.isEmpty())
-        formattedStr.replace("|nick|", linkedNick(nick));
-
-    QString cssClass("msg_UserChat");
+    QString cssClass = (isFriend ? "msg_Friend" : "msg_User") + cssClassPart;
 
-    // check first character for color code and set color properly
-    char c = str[0].toAscii();
-    switch (c)
-    {
-        case 3:
-            cssClass = (isFriend ? "msg_FriendJoin" : "msg_UserJoin");
-            break;
-        case 2:
-            cssClass = (isFriend ? "msg_FriendAction" : "msg_UserAction");
-            break;
-        default:
-            if (isFriend)
-                cssClass = "msg_FriendChat";
-    }
-
-    bool isHL = false;
-
-    if ((c != 3) && (!nick.isEmpty()) &&
-            (nick != m_userNick) && (!m_userNick.isEmpty()))
-    {
-        QString lcStr = str.toLower();
-
-        foreach (const QRegExp & hl, m_highlights)
-        {
-            if (lcStr.contains(hl))
-            {
-                isHL = true;
-                break;
-            }
-        }
-    }
-
-    addLine(cssClass, formattedStr, isHL);
+    addLine(cssClass, str, highlight);
 }
 
 void HWChatWidget::addLine(const QString & cssClass, QString line, bool isHighlight)
@@ -512,6 +497,9 @@
 
     emit nickCountUpdate(chatNicks->model()->rowCount());
 
+    if (!isIgnored)
+        printChatString(nick, QString("*** ") + tr("%1 has joined").arg(linkedNick(nick)), "Join", false);
+
     if (notifyNick && notify && (m_helloSounds.size() > 0))
     {
         SDLInteraction::instance().playSoundFile(
@@ -521,9 +509,19 @@
 
 void HWChatWidget::nickRemoved(const QString& nick)
 {
+    nickRemoved(nick, "");
+}
+
+void HWChatWidget::nickRemoved(const QString& nick, const QString & message)
+{
     chatEditLine->removeNickname(nick);
 
     emit nickCountUpdate(chatNicks->model()->rowCount());
+
+    if (message.isEmpty())
+        printChatString(nick, QString("*** ") + tr("%1 has left").arg(linkedNick(nick)), "Leave", false);
+    else
+        printChatString(nick, QString("*** ") + tr("%1 has left (%2)").arg(linkedNick(nick)).arg(messageToHTML(message)), "Leave", false);
 }
 
 void HWChatWidget::clear()
--- a/QTfrontend/ui/widget/chatwidget.h	Wed Mar 20 09:13:05 2013 +0400
+++ b/QTfrontend/ui/widget/chatwidget.h	Wed Mar 20 23:18:46 2013 +0100
@@ -86,12 +86,32 @@
         void beforeContentAdd();
         void afterContentAdd();
 
+        /**
+         * @brief Checks whether the message contains a highlight.
+         * @param sender the sender of the message
+         * @param message the message
+         * @return true if the sender is somebody else and the message contains a highlight, otherwise false
+         */
+        bool containsHighlight(const QString & sender, const QString & message);
+        /**
+         * @brief Escapes HTML chars in the message and converts URls to HTML links.
+         * @param message the message to be converted to HTML
+         * @return the HTML message
+         */
+        QString messageToHTML(const QString & message);
+        void printChatString(
+            const QString & nick,
+            const QString & str,
+            const QString & cssClassPart,
+            bool highlight);
+
     public slots:
-        void onChatString(const QString& str);
-        void onChatString(const QString& nick, const QString& str);
+        void onChatAction(const QString & nick, const QString & str);
+        void onChatMessage(const QString & nick, const QString & str);
         void onServerMessage(const QString& str);
         void nickAdded(const QString& nick, bool notifyNick);
         void nickRemoved(const QString& nick);
+        void nickRemoved(const QString& nick, const QString& message);
         void clear();
         void adminAccess(bool);