diff -r 88cfcd9161d3 -r 42b256eca362 QTfrontend/chatwidget.cpp --- a/QTfrontend/chatwidget.cpp Fri Oct 28 17:41:39 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,584 +0,0 @@ -/* - * Hedgewars, a free turn based strategy game - * Copyright (c) 2007 Igor Ulyanov - * Copyright (c) 2007-2011 Andrey Korotaev - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hwconsts.h" -#include "SDLs.h" -#include "gameuiconfig.h" -#include "chatwidget.h" - -ListWidgetNickItem::ListWidgetNickItem(const QString& nick, bool isFriend, bool isIgnored) : QListWidgetItem(nick) -{ - this->aFriend = isFriend; - this->isIgnored = isIgnored; -} - -void ListWidgetNickItem::setFriend(bool isFriend) -{ - this->aFriend = isFriend; -} - -void ListWidgetNickItem::setIgnored(bool isIgnored) -{ - this->isIgnored = isIgnored; -} - -bool ListWidgetNickItem::isFriend() -{ - return aFriend; -} - -bool ListWidgetNickItem::ignored() -{ - return isIgnored; -} - -bool ListWidgetNickItem::operator< (const QListWidgetItem & other) const -{ - // case in-sensitive comparison of the associated strings - // chars that are no letters are sorted at the end of the list - - ListWidgetNickItem otherNick = const_cast(dynamic_cast(other)); - - // ignored always down - if (isIgnored != otherNick.ignored()) - return !isIgnored; - - // friends always up - if (aFriend != otherNick.isFriend()) - return aFriend; - - QString txt1 = text().toLower(); - QString txt2 = other.text().toLower(); - - bool firstIsShorter = (txt1.size() < txt2.size()); - int len = firstIsShorter?txt1.size():txt2.size(); - - for (int i = 0; i < len; i++) - { - if (txt1[i] == txt2[i]) - continue; - if (txt1[i].isLetter() != txt2[i].isLetter()) - return txt1[i].isLetter(); - return (txt1[i] < txt2[i]); - } - - return firstIsShorter; -} - -const char* HWChatWidget::STYLE = -"\ -a { color:#c8c8ff; }\ -.nick { text-decoration: none; }\ -.UserChat .nick { color:#ffec20; }\ -.FriendChat { color: #08e008; }\ -.FriendChat .nick { color: #20ff20; }\ -.UserJoin { color: #c0c0c0; }\ -.UserJoin .nick { color: #d0d0d0; }\ -.FriendJoin { color: #c0e0c0; }\ -.FriendJoin .nick { color: #d0f0d0; }\ -.UserAction { color: #ff80ff; }\ -.UserAction .nick { color: #ffa0ff; }\ -.FriendAction { color: #ff00ff; }\ -.FriendAction .nick { color: #ff30ff; }\ -.Error { color: #ff0000 }\ -.Warning { color: #ff8000 }\ -.Notice { color: #fefefe }\ -"; - -HWChatWidget::HWChatWidget(QWidget* parent, QSettings * gameSettings, SDLInteraction * sdli, bool notify) : - QWidget(parent), - mainLayout(this) -{ - this->gameSettings = gameSettings; - this->sdli = sdli; - this->notify = notify; - if(notify && gameSettings->value("frontend/sound", true).toBool()) { - QFile tmpfile; - sdli->SDLMusicInit(); - for(int i=0;i<4;i++) { - tmpfile.setFileName(cfgdir->absolutePath() + "/Data/Sounds/voices/Classic/Hello.ogg"); - if (tmpfile.exists()) sound[i] = Mix_LoadWAV(QFileInfo(tmpfile).absoluteFilePath().toLocal8Bit().constData()); - else sound[i] = Mix_LoadWAV(QString(datadir->absolutePath() + - "/Sounds/voices/Classic/Hello.ogg").toLocal8Bit().constData()); - } - } - - mainLayout.setSpacing(1); - mainLayout.setMargin(1); - mainLayout.setSizeConstraint(QLayout::SetMinimumSize); - mainLayout.setColumnStretch(0, 76); - mainLayout.setColumnStretch(1, 24); - - chatEditLine = new QLineEdit(this); - chatEditLine->setMaxLength(300); - connect(chatEditLine, SIGNAL(returnPressed()), this, SLOT(returnPressed())); - - mainLayout.addWidget(chatEditLine, 2, 0); - - chatText = new QTextBrowser(this); - chatText->document()->setDefaultStyleSheet(STYLE); - chatText->setMinimumHeight(20); - chatText->setMinimumWidth(10); - chatText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - chatText->setOpenLinks(false); - connect(chatText, SIGNAL(anchorClicked(const QUrl&)), - this, SLOT(linkClicked(const QUrl&))); - mainLayout.addWidget(chatText, 0, 0, 2, 1); - - chatNicks = new QListWidget(this); - chatNicks->setMinimumHeight(10); - chatNicks->setMinimumWidth(10); - chatNicks->setSortingEnabled(true); - chatNicks->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - chatNicks->setContextMenuPolicy(Qt::ActionsContextMenu); - connect(chatNicks, SIGNAL(itemDoubleClicked(QListWidgetItem *)), - this, SLOT(chatNickDoubleClicked(QListWidgetItem *))); - connect(chatNicks, SIGNAL(currentRowChanged(int)), - this, SLOT(chatNickSelected(int))); - - mainLayout.addWidget(chatNicks, 0, 1, 3, 1); - - acInfo = new QAction(QAction::tr("Info"), chatNicks); - acInfo->setIcon(QIcon(":/res/info.png")); - connect(acInfo, SIGNAL(triggered(bool)), this, SLOT(onInfo())); - acKick = new QAction(QAction::tr("Kick"), chatNicks); - acKick->setIcon(QIcon(":/res/kick.png")); - connect(acKick, SIGNAL(triggered(bool)), this, SLOT(onKick())); - acBan = new QAction(QAction::tr("Ban"), chatNicks); - acBan->setIcon(QIcon(":/res/ban.png")); - connect(acBan, SIGNAL(triggered(bool)), this, SLOT(onBan())); - acFollow = new QAction(QAction::tr("Follow"), chatNicks); - acFollow->setIcon(QIcon(":/res/follow.png")); - connect(acFollow, SIGNAL(triggered(bool)), this, SLOT(onFollow())); - acIgnore = new QAction(QAction::tr("Ignore"), chatNicks); - acIgnore->setIcon(QIcon(":/res/ignore.png")); - connect(acIgnore, SIGNAL(triggered(bool)), this, SLOT(onIgnore())); - acFriend = new QAction(QAction::tr("Add friend"), chatNicks); - acFriend->setIcon(QIcon(":/res/addfriend.png")); - connect(acFriend, SIGNAL(triggered(bool)), this, SLOT(onFriend())); - - chatNicks->insertAction(0, acFriend); - chatNicks->insertAction(0, acInfo); - chatNicks->insertAction(0, acIgnore); - - showReady = false; - setShowFollow(true); -} - -void HWChatWidget::linkClicked(const QUrl & link) -{ - if (link.scheme() == "http") - QDesktopServices::openUrl(link); - if (link.scheme() == "hwnick") - { - // decode nick - const QString& nick = QString::fromUtf8(QByteArray::fromBase64(link.encodedQuery())); - QList items = chatNicks->findItems(nick, Qt::MatchExactly); - if (items.size() < 1) - return; - QMenu * popup = new QMenu(this); - // selecting an item will automatically scroll there, so let's save old position - QScrollBar * scrollBar = chatNicks->verticalScrollBar(); - int oldScrollPos = scrollBar->sliderPosition(); - // select the nick which we want to see the actions for - chatNicks->setCurrentItem(items[0], QItemSelectionModel::Clear); - // selecting an item will automatically scroll there, so let's save old position - scrollBar->setSliderPosition(oldScrollPos); - // load actions - popup->addActions(chatNicks->actions()); - // display menu popup at mouse cursor position - popup->popup(QCursor::pos()); - } -} - -void HWChatWidget::setShowFollow(bool enabled) -{ - if (enabled) { - if (!(chatNicks->actions().contains(acFollow))) - chatNicks->insertAction(acFriend, acFollow); - } - else { - if (chatNicks->actions().contains(acFollow)) - chatNicks->removeAction(acFollow); - } -} - -void HWChatWidget::loadList(QStringList & list, const QString & file) -{ - list.clear(); - QFile txt(cfgdir->absolutePath() + "/" + file); - if(!txt.open(QIODevice::ReadOnly)) - return; - QTextStream stream(&txt); - stream.setCodec("UTF-8"); - - while(!stream.atEnd()) - { - QString str = stream.readLine(); - if(str.startsWith(";") || str.length() == 0) - continue; - list << str.trimmed(); - } - //readd once we require newer Qt than 4.4 - //list.removeDuplicates(); - txt.close(); -} - -void HWChatWidget::saveList(QStringList & list, const QString & file) -{ - QFile txt(cfgdir->absolutePath() + "/" + file); - if(!txt.open(QIODevice::WriteOnly | QIODevice::Truncate)) - return; - QTextStream stream(&txt); - stream.setCodec("UTF-8"); - - stream << "; this list is used by Hedgewars - do not edit it unless you know what you're doing!" << endl; - for(int i = 0; i < list.size(); i++) - stream << list[i] << endl; - txt.close(); -} - -void HWChatWidget::updateNickItem(QListWidgetItem *nickItem) -{ - QString nick = nickItem->text(); - ListWidgetNickItem * item = dynamic_cast(nickItem); - - item->setFriend(friendsList.contains(nick, Qt::CaseInsensitive)); - item->setIgnored(ignoreList.contains(nick, Qt::CaseInsensitive)); - - if(item->ignored()) - { - item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_ignore_on.png" : ":/res/chat_ignore_off.png") : ":/res/chat_ignore.png")); - item->setForeground(Qt::gray); - } - else if(item->isFriend()) - { - item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_friend_on.png" : ":/res/chat_friend_off.png") : ":/res/chat_friend.png")); - item->setForeground(Qt::green); - } - else - { - item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_default_on.png" : ":/res/chat_default_off.png") : ":/res/chat_default.png")); - item->setForeground(QBrush(QColor(0xff, 0xcc, 0x00))); - } -} - -void HWChatWidget::updateNickItems() -{ - for(int i = 0; i < chatNicks->count(); i++) - updateNickItem(chatNicks->item(i)); - - chatNicks->sortItems(); -} - -void HWChatWidget::loadLists(const QString & nick) -{ - loadList(ignoreList, nick.toLower() + "_ignore.txt"); - loadList(friendsList, nick.toLower() + "_friends.txt"); - updateNickItems(); -} - -void HWChatWidget::saveLists(const QString & nick) -{ - saveList(ignoreList, nick.toLower() + "_ignore.txt"); - saveList(friendsList, nick.toLower() + "_friends.txt"); -} - -void HWChatWidget::returnPressed() -{ - QStringList lines = chatEditLine->text().split('\n'); - chatEditLine->clear(); - foreach (const QString &line, lines) - emit chatLine(line); -} - - -void HWChatWidget::onChatString(const QString& str) -{ - onChatString("", str); -} - -const QRegExp HWChatWidget::URLREGEXP = QRegExp("(http://)?(www\\.)?(hedgewars\\.org(/[^ ]*)?)"); - -void HWChatWidget::onChatString(const QString& nick, const QString& str) -{ - bool isFriend = false; - - if (!nick.isEmpty()) { - // don't show chat lines that are from ignored nicks - if (ignoreList.contains(nick, Qt::CaseInsensitive)) - return; - // friends will get special treatment, of course - isFriend = friendsList.contains(nick, Qt::CaseInsensitive); - } - - QString formattedStr = Qt::escape(str.mid(1)); - // make hedgewars.org urls actual links - formattedStr = formattedStr.replace(URLREGEXP, "\\3"); - - // "link" nick, but before that encode it in base64 to make sure it can't intefere with html/url syntax - // the nick is put as querystring as putting it as host would convert it to it's lower case variant - if(!nick.isEmpty()) - formattedStr.replace("|nick|",QString("%2").arg(QString(nick.toUtf8().toBase64())).arg(nick)); - - QString cssClass("UserChat"); - - // check first character for color code and set color properly - switch (str[0].toAscii()) { - case 3: - cssClass = (isFriend ? "FriendJoin" : "UserJoin"); - break; - case 2: - cssClass = (isFriend ? "FriendAction" : "UserAction"); - break; - default: - if (isFriend) - cssClass = "FriendChat"; - } - - addLine(cssClass,formattedStr); -} - -void HWChatWidget::addLine(const QString& cssClass, QString line) -{ - if (chatStrings.size() > 250) - chatStrings.removeFirst(); - - line = QString("%1").arg(line).arg(cssClass); - - chatStrings.append(line); - - chatText->setHtml(chatStrings.join("
")); - - chatText->moveCursor(QTextCursor::End); -} - -void HWChatWidget::onServerMessage(const QString& str) -{ - if (chatStrings.size() > 250) - chatStrings.removeFirst(); - - chatStrings.append("
" + str + "
"); - - chatText->setHtml(chatStrings.join("
")); - - chatText->moveCursor(QTextCursor::End); -} - -void HWChatWidget::nickAdded(const QString& nick, bool notifyNick) -{ - QListWidgetItem * item = new ListWidgetNickItem(nick, friendsList.contains(nick, Qt::CaseInsensitive), ignoreList.contains(nick, Qt::CaseInsensitive)); - updateNickItem(item); - chatNicks->addItem(item); - - emit nickCountUpdate(chatNicks->count()); - - if(notifyNick && notify && gameSettings->value("frontend/sound", true).toBool()) { - Mix_PlayChannel(-1, sound[rand()%4], 0); - } -} - -void HWChatWidget::nickRemoved(const QString& nick) -{ - foreach(QListWidgetItem * item, chatNicks->findItems(nick, Qt::MatchExactly)) - chatNicks->takeItem(chatNicks->row(item)); - - emit nickCountUpdate(chatNicks->count()); -} - -void HWChatWidget::clear() -{ - chatText->clear(); - chatStrings.clear(); - chatNicks->clear(); -} - -void HWChatWidget::onKick() -{ - QListWidgetItem * curritem = chatNicks->currentItem(); - if (curritem) - emit kick(curritem->text()); -} - -void HWChatWidget::onBan() -{ - QListWidgetItem * curritem = chatNicks->currentItem(); - if (curritem) - emit ban(curritem->text()); -} - -void HWChatWidget::onInfo() -{ - QListWidgetItem * curritem = chatNicks->currentItem(); - if (curritem) - emit info(curritem->text()); -} - -void HWChatWidget::onFollow() -{ - QListWidgetItem * curritem = chatNicks->currentItem(); - if (curritem) - emit follow(curritem->text()); -} - -void HWChatWidget::onIgnore() -{ - QListWidgetItem * curritem = chatNicks->currentItem(); - if(!curritem) - return; - - if(ignoreList.contains(curritem->text(), Qt::CaseInsensitive)) // already on list - remove him - { - ignoreList.removeAll(curritem->text().toLower()); - onChatString(HWChatWidget::tr("%1 *** %2 has been removed from your ignore list").arg('\x03').arg(curritem->text())); - } - else // not on list - add - { - // don't consider ignored people friends - if(friendsList.contains(curritem->text(), Qt::CaseInsensitive)) - emit onFriend(); - - // scroll down on first ignore added so that people see where that nick went to - if (ignoreList.isEmpty()) - chatNicks->scrollToBottom(); - - ignoreList << curritem->text().toLower(); - onChatString(HWChatWidget::tr("%1 *** %2 has been added to your ignore list").arg('\x03').arg(curritem->text())); - } - updateNickItem(curritem); // update icon/sort order/etc - chatNicks->sortItems(); - chatNickSelected(0); // update context menu -} - -void HWChatWidget::onFriend() -{ - QListWidgetItem * curritem = chatNicks->currentItem(); - if(!curritem) - return; - - if(friendsList.contains(curritem->text(), Qt::CaseInsensitive)) // already on list - remove him - { - friendsList.removeAll(curritem->text().toLower()); - onChatString(HWChatWidget::tr("%1 *** %2 has been removed from your friends list").arg('\x03').arg(curritem->text())); - } - else // not on list - add - { - // don't ignore the new friend - if(ignoreList.contains(curritem->text(), Qt::CaseInsensitive)) - emit onIgnore(); - - // scroll up on first friend added so that people see where that nick went to - if (friendsList.isEmpty()) - chatNicks->scrollToTop(); - - friendsList << curritem->text().toLower(); - onChatString(HWChatWidget::tr("%1 *** %2 has been added to your friends list").arg('\x03').arg(curritem->text())); - } - updateNickItem(curritem); // update icon/sort order/etc - chatNicks->sortItems(); - chatNickSelected(0); // update context menu -} - -void HWChatWidget::chatNickDoubleClicked(QListWidgetItem * item) -{ - Q_UNUSED(item); - - QList actions = chatNicks->actions(); - actions.first()->activate(QAction::Trigger); -} - -void HWChatWidget::chatNickSelected(int index) -{ - Q_UNUSED(index); - - QListWidgetItem* item = chatNicks->currentItem(); - if (!item) - return; - - // update context menu labels according to possible action - if(ignoreList.contains(item->text(), Qt::CaseInsensitive)) - { - acIgnore->setText(QAction::tr("Unignore")); - acIgnore->setIcon(QIcon(":/res/unignore.png")); - } - else - { - acIgnore->setText(QAction::tr("Ignore")); - acIgnore->setIcon(QIcon(":/res/ignore.png")); - } - - if(friendsList.contains(item->text(), Qt::CaseInsensitive)) - { - acFriend->setText(QAction::tr("Remove friend")); - acFriend->setIcon(QIcon(":/res/remfriend.png")); - } - else - { - acFriend->setText(QAction::tr("Add friend")); - acFriend->setIcon(QIcon(":/res/addfriend.png")); - } -} - -void HWChatWidget::setShowReady(bool s) -{ - showReady = s; -} - -void HWChatWidget::setReadyStatus(const QString & nick, bool isReady) -{ - QList items = chatNicks->findItems(nick, Qt::MatchExactly); - if (items.size() != 1) - { - qWarning("Bug: cannot find user in chat"); - return; - } - - items[0]->setData(Qt::UserRole, isReady); // bulb status - updateNickItem(items[0]); - - // ensure we're still showing the status bulbs - showReady = true; -} - -void HWChatWidget::adminAccess(bool b) -{ - chatNicks->removeAction(acKick); - chatNicks->removeAction(acBan); - - if(b) - { - chatNicks->insertAction(0, acKick); -// chatNicks->insertAction(0, acBan); - } -}