Merge pull request #847 from poixen/pm_toolbar_alert

Desktop Notifications
This commit is contained in:
poixen 2015-03-26 20:22:29 +01:00
commit 8ce5c5a276
15 changed files with 302 additions and 120 deletions

View file

@ -5,6 +5,7 @@
#include <QDesktopServices>
#include <QApplication>
#include <QDebug>
#include <QSystemTrayIcon>
#include "chatview.h"
#include "user_level.h"
#include "user_context_menu.h"
@ -223,6 +224,10 @@ void ChatView::appendMessage(QString message, QString sender, UserLevelFlags use
cursor.insertText("@" + userName, mentionFormat);
message = message.mid(mention.size());
QApplication::alert(this);
if (shouldShowSystemPopup()) {
QString ref = sender.left(sender.length() - 2);
showSystemPopup(ref);
}
} else {
int mentionEndIndex = message.indexOf(QRegExp("\\W"), 1);// from 1 as @ is non-char
if (mentionEndIndex == -1)
@ -251,6 +256,22 @@ void ChatView::appendMessage(QString message, QString sender, UserLevelFlags use
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
}
void ChatView::actMessageClicked() {
emit messageClickedSignal();
}
bool ChatView::shouldShowSystemPopup() {
return tabSupervisor->currentIndex() != tabSupervisor->indexOf(this) ||
QApplication::activeWindow() == 0 || QApplication::focusWidget() == 0;
}
void ChatView::showSystemPopup(QString &sender) {
disconnect(trayIcon, SIGNAL(messageClicked()), 0, 0);
trayIcon->showMessage(sender + tr(" mentioned you."), tr("Click to view"));
connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(actMessageClicked()));
}
QColor ChatView::getCustomMentionColor() {
QColor customColor;
customColor.setNamedColor("#" + settingsCache->getChatMentionColor());

View file

@ -5,6 +5,7 @@
#include <QTextFragment>
#include <QTextCursor>
#include <QColor>
#include <QAction>
#include "userlist.h"
#include "user_level.h"
#include "tab_supervisor.h"
@ -32,14 +33,18 @@ private:
bool showTimestamps;
HoveredItemType hoveredItemType;
QString hoveredContent;
QAction *messageClicked;
QTextFragment getFragmentUnderMouse(const QPoint &pos) const;
QTextCursor prepareBlock(bool same = false);
void appendCardTag(QTextCursor &cursor, const QString &cardName);
void appendUrlTag(QTextCursor &cursor, QString url);
QString getNameFromUserList(QMap<QString, UserListTWI *> &userList, QString &userName);
QColor getCustomMentionColor();
bool shouldShowSystemPopup();
void showSystemPopup(QString &sender);
private slots:
void openLink(const QUrl &link);
void actMessageClicked();
public:
ChatView(const TabSupervisor *_tabSupervisor, TabGame *_game, bool _showTimestamps, QWidget *parent = 0);
void retranslateUi();
@ -59,6 +64,7 @@ signals:
void showCardInfoPopup(QPoint pos, QString cardName);
void deleteCardInfoPopup(QString cardName);
void addMentionTag(QString mentionTag);
void messageClickedSignal();
};
#endif

View file

@ -598,6 +598,12 @@ MessagesSettingsPage::MessagesSettingsPage()
updateMentionPreview();
connect(mentionColor, SIGNAL(textChanged(QString)), this, SLOT(updateColor(QString)));
messagePopups.setChecked(settingsCache->getShowMessagePopup());
connect(&messagePopups, SIGNAL(stateChanged(int)), settingsCache, SLOT(setShowMessagePopups(int)));
mentionPopups.setChecked(settingsCache->getShowMentionPopup());
connect(&mentionPopups, SIGNAL(stateChanged(int)), settingsCache, SLOT(setShowMentionPopups(int)));
QGridLayout *chatGrid = new QGridLayout;
chatGrid->addWidget(&chatMentionCheckBox, 0, 0);
chatGrid->addWidget(&invertMentionForeground, 0, 1);
@ -605,6 +611,8 @@ MessagesSettingsPage::MessagesSettingsPage()
chatGrid->addWidget(&ignoreUnregUsersMainChat, 1, 0);
chatGrid->addWidget(&hexLabel, 1, 2);
chatGrid->addWidget(&ignoreUnregUserMessages, 2, 0);
chatGrid->addWidget(&messagePopups, 3, 0);
chatGrid->addWidget(&mentionPopups, 4, 0);
chatGroupBox = new QGroupBox;
chatGroupBox->setLayout(chatGrid);
@ -699,6 +707,8 @@ void MessagesSettingsPage::retranslateUi()
ignoreUnregUsersMainChat.setText(tr("Ignore chat room messages sent by unregistered users."));
ignoreUnregUserMessages.setText(tr("Ignore private messages sent by unregistered users."));
invertMentionForeground.setText(tr("Invert text color"));
messagePopups.setText(tr("Enable desktop notifications for private messages."));
mentionPopups.setText(tr("Enable desktop notification for mentions."));
hexLabel.setText(tr("(Color is hexadecimal)"));
}

View file

@ -169,6 +169,8 @@ private:
QCheckBox invertMentionForeground;
QCheckBox ignoreUnregUsersMainChat;
QCheckBox ignoreUnregUserMessages;
QCheckBox messagePopups;
QCheckBox mentionPopups;
QGroupBox *chatGroupBox;
QGroupBox *messageShortcuts;
QLineEdit *mentionColor;

View file

@ -31,6 +31,7 @@
#include <QDir>
#include <QDesktopServices>
#include <QDebug>
#include <QSystemTrayIcon>
#include "main.h"
#include "window_main.h"
@ -48,6 +49,8 @@ QTranslator *translator, *qtTranslator;
SettingsCache *settingsCache;
RNG_Abstract *rng;
SoundEngine *soundEngine;
QSystemTrayIcon *trayIcon;
const QString translationPrefix = "cockatrice";
#ifdef TRANSLATION_PATH

View file

@ -3,10 +3,12 @@
class CardDatabase;
class QTranslator;
class QSystemTrayIcon;
class SoundEngine;
extern CardDatabase *db;
extern QSystemTrayIcon *trayIcon;
extern QTranslator *translator;
extern const QString translationPrefix;
extern QString translationPath;

View file

@ -75,6 +75,8 @@ SettingsCache::SettingsCache()
attemptAutoConnect = settings->value("server/auto_connect", 0).toBool();
scaleCards = settings->value("cards/scaleCards", true).toBool();
showMessagePopups = settings->value("chat/showmessagepopups", true).toBool();
showMentionPopups = settings->value("chat/showmentionpopups", true).toBool();
}
void SettingsCache::setCardScaling(const int _scaleCards) {
@ -82,6 +84,16 @@ void SettingsCache::setCardScaling(const int _scaleCards) {
settings->setValue("cards/scaleCards", scaleCards);
}
void SettingsCache::setShowMessagePopups(const int _showMessagePopups) {
showMessagePopups = _showMessagePopups;
settings->setValue("chat/showmessagepopups", showMessagePopups);
}
void SettingsCache::setShowMentionPopups(const int _showMentionPopus) {
showMentionPopups = _showMentionPopus;
settings->setValue("chat/showmentionpopups", showMentionPopups);
}
void SettingsCache::setLang(const QString &_lang)
{
lang = _lang;

View file

@ -75,6 +75,8 @@ private:
bool attemptAutoConnect;
int pixmapCacheSize;
bool scaleCards;
bool showMessagePopups;
bool showMentionPopups;
public:
SettingsCache();
const QByteArray &getMainWindowGeometry() const { return mainWindowGeometry; }
@ -127,6 +129,8 @@ public:
bool getAutoConnect() const { return attemptAutoConnect; }
int getPixmapCacheSize() const { return pixmapCacheSize; }
bool getScaleCards() const { return scaleCards; }
bool getShowMessagePopup() const { return showMessagePopups; }
bool getShowMentionPopup() const { return showMentionPopups; }
public slots:
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
void setLang(const QString &_lang);
@ -172,6 +176,8 @@ public slots:
void setAutoConnect(const bool &_autoConnect);
void setPixmapCacheSize(const int _pixmapCacheSize);
void setCardScaling(const int _scaleCards);
void setShowMessagePopups(const int _showMessagePopups);
void setShowMentionPopups(const int _showMentionPopups);
};
extern SettingsCache *settingsCache;

View file

@ -6,6 +6,10 @@
#include "tab_message.h"
#include "abstractclient.h"
#include "chatview.h"
#include "main.h"
#include "settingscache.h"
#include <QSystemTrayIcon>
#include <QApplication>
#include "pending_command.h"
#include "pb/session_commands.pb.h"
@ -107,9 +111,29 @@ void TabMessage::processUserMessageEvent(const Event_UserMessage &event)
{
const UserLevelFlags userLevel(event.sender_name() == otherUserInfo->name() ? otherUserInfo->user_level() : ownUserInfo->user_level());
chatView->appendMessage(QString::fromStdString(event.message()), QString::fromStdString(event.sender_name()), userLevel, true);
if (settingsCache->getShowMessagePopup() && shouldShowSystemPopup(event))
showSystemPopup(event);
emit userEvent();
}
bool TabMessage::shouldShowSystemPopup(const Event_UserMessage &event) {
return (event.sender_name() == otherUserInfo->name() &&
tabSupervisor->currentIndex() != tabSupervisor->indexOf(this)) ||
QApplication::activeWindow() == 0 || QApplication::focusWidget() == 0;
}
void TabMessage::showSystemPopup(const Event_UserMessage &event) {
disconnect(trayIcon, SIGNAL(messageClicked()), 0, 0);
trayIcon->showMessage(tr("Private message from ") + otherUserInfo->name().c_str(), event.message().c_str());
connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked()));
}
void TabMessage::messageClicked() {
tabSupervisor->setCurrentIndex(tabSupervisor->indexOf(this));
QApplication::setActiveWindow(this);
}
void TabMessage::processUserLeft()
{
chatView->appendMessage(tr("%1 has left the server.").arg(QString::fromStdString(otherUserInfo->name())));

View file

@ -30,6 +30,7 @@ private slots:
void actLeave();
void messageSent(const Response &response);
void addMentionTag(QString mentionTag);
void messageClicked();
public:
TabMessage(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User &_ownUserInfo, const ServerInfo_User &_otherUserInfo);
~TabMessage();
@ -40,8 +41,12 @@ public:
QString getTabText() const;
void processUserMessageEvent(const Event_UserMessage &event);
void processUserLeft();
void processUserJoined(const ServerInfo_User &_userInfo);
private:
bool shouldShowSystemPopup(const Event_UserMessage &event);
void showSystemPopup(const Event_UserMessage &event);
};
#endif

View file

@ -9,6 +9,7 @@
#include <QLabel>
#include <QToolButton>
#include <QSplitter>
#include <QApplication>
#include "tab_supervisor.h"
#include "tab_room.h"
#include "tab_userlists.h"
@ -42,6 +43,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, AbstractClient *_client, ServerI
connect(userList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool)));
chatView = new ChatView(tabSupervisor, 0, true);
connect(chatView, SIGNAL(messageClickedSignal()), this, SLOT(focusTab()));
connect(chatView, SIGNAL(openMessageDialog(QString, bool)), this, SIGNAL(openMessageDialog(QString, bool)));
connect(chatView, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString)));
connect(chatView, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString)));
@ -125,6 +127,11 @@ void TabRoom::retranslateUi()
aOpenChatSettings->setText(tr("Chat Settings..."));
}
void TabRoom::focusTab() {
QApplication::setActiveWindow(this);
tabSupervisor->setCurrentIndex(tabSupervisor->indexOf(this));
}
void TabRoom::closeRequest()
{
actLeaveRoom();

View file

@ -56,6 +56,7 @@ private slots:
void actClearChat();
void actOpenChatSettings();
void addMentionTag(QString mentionTag);
void focusTab();
void processListGamesEvent(const Event_ListGames &event);
void processJoinRoomEvent(const Event_JoinRoom &event);

View file

@ -28,6 +28,8 @@
#include <QFileDialog>
#include <QThread>
#include <QDateTime>
#include <QSystemTrayIcon>
#include <QApplication>
#include "main.h"
#include "window_main.h"
@ -413,6 +415,11 @@ MainWindow::MainWindow(QWidget *parent)
resize(900, 700);
restoreGeometry(settingsCache->getMainWindowGeometry());
aFullScreen->setChecked(windowState() & Qt::WindowFullScreen);
if (QSystemTrayIcon::isSystemTrayAvailable()) {
createTrayActions();
createTrayIcon();
}
}
MainWindow::~MainWindow()
@ -421,6 +428,37 @@ MainWindow::~MainWindow()
clientThread->wait();
}
void MainWindow::createTrayIcon() {
QMenu *trayIconMenu = new QMenu(this);
trayIconMenu->addAction(closeAction);
trayIcon = new QSystemTrayIcon(this);
trayIcon->setContextMenu(trayIconMenu);
trayIcon->setIcon(QIcon(":/resources/appicon.svg"));
trayIcon->show();
connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,
SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
}
void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::DoubleClick) {
if (windowState() != Qt::WindowMinimized)
showMinimized();
else {
showNormal();
QApplication::setActiveWindow(this);
}
}
}
void MainWindow::createTrayActions() {
closeAction = new QAction(tr("&Exit"), this);
connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
}
void MainWindow::closeEvent(QCloseEvent *event)
{
// workaround Qt bug where closeEvent gets called twice

View file

@ -21,6 +21,7 @@
#define WINDOW_H
#include <QMainWindow>
#include <QSystemTrayIcon>
#include "abstractclient.h"
#include "pb/response.pb.h"
@ -56,18 +57,28 @@ private slots:
void actExit();
void actAbout();
void iconActivated(QSystemTrayIcon::ActivationReason reason);
private:
static const QString appName;
void setClientStatusTitle();
void retranslateUi();
void createActions();
void createMenus();
void createTrayIcon();
void createTrayActions();
QList<QMenu *> tabMenus;
QMenu *cockatriceMenu, *helpMenu;
QAction *aConnect, *aDisconnect, *aSinglePlayer, *aWatchReplay, *aDeckEditor, *aFullScreen, *aSettings, *aExit,
*aAbout;
TabSupervisor *tabSupervisor;
QMenu *trayIconMenu;
QAction *closeAction;
RemoteClient *client;
QThread *clientThread;

View file

@ -555,6 +555,19 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatView</name>
<message>
<location filename="../src/chatview.cpp" line="265"/>
<source> mentioned you.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/chatview.cpp" line="265"/>
<source>Click to view</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DBPriceUpdater</name>
<message>
@ -1092,19 +1105,19 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<context>
<name>DlgSettings</name>
<message>
<location filename="../src/dlg_settings.cpp" line="853"/>
<location filename="../src/dlg_settings.cpp" line="859"/>
<location filename="../src/dlg_settings.cpp" line="865"/>
<location filename="../src/dlg_settings.cpp" line="863"/>
<location filename="../src/dlg_settings.cpp" line="869"/>
<location filename="../src/dlg_settings.cpp" line="875"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="807"/>
<location filename="../src/dlg_settings.cpp" line="817"/>
<source>Unknown Error loading card database</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="816"/>
<location filename="../src/dlg_settings.cpp" line="826"/>
<source>Your card database is invalid.
Cockatrice may not function correctly with an invalid database
@ -1115,7 +1128,7 @@ Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="823"/>
<location filename="../src/dlg_settings.cpp" line="833"/>
<source>Your card database version is too old.
This can cause problems loading card information or images
@ -1126,7 +1139,7 @@ Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="830"/>
<location filename="../src/dlg_settings.cpp" line="840"/>
<source>Your card database did not finish loading
Please file a ticket at http://github.com/Daenyth/Cockatrice/issues with your cards.xml attached
@ -1135,21 +1148,21 @@ Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="836"/>
<location filename="../src/dlg_settings.cpp" line="846"/>
<source>File Error loading your card database.
Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="841"/>
<location filename="../src/dlg_settings.cpp" line="851"/>
<source>Your card database was loaded but contains no cards.
Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="846"/>
<location filename="../src/dlg_settings.cpp" line="856"/>
<source>Unknown card database load status
Please file a ticket at http://github.com/Daenyth/Cockatrice/issues
@ -1158,42 +1171,42 @@ Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="859"/>
<location filename="../src/dlg_settings.cpp" line="869"/>
<source>The path to your deck directory is invalid. Would you like to go back and set the correct path?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="865"/>
<location filename="../src/dlg_settings.cpp" line="875"/>
<source>The path to your card pictures directory is invalid. Would you like to go back and set the correct path?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="874"/>
<location filename="../src/dlg_settings.cpp" line="884"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="876"/>
<location filename="../src/dlg_settings.cpp" line="886"/>
<source>General</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="877"/>
<location filename="../src/dlg_settings.cpp" line="887"/>
<source>Appearance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="878"/>
<location filename="../src/dlg_settings.cpp" line="888"/>
<source>User interface</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="879"/>
<location filename="../src/dlg_settings.cpp" line="889"/>
<source>Deck editor</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="880"/>
<location filename="../src/dlg_settings.cpp" line="890"/>
<source>Chat Settings</source>
<translation type="unfinished"></translation>
</message>
@ -1487,54 +1500,54 @@ Would you like to change your database location setting?</source>
<context>
<name>MainWindow</name>
<message>
<location filename="../src/window_main.cpp" line="67"/>
<location filename="../src/window_main.cpp" line="69"/>
<source>There are too many concurrent connections from your address.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="78"/>
<location filename="../src/window_main.cpp" line="80"/>
<source>Scheduled server shutdown.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="69"/>
<location filename="../src/window_main.cpp" line="71"/>
<source>Banned by moderator</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="71"/>
<location filename="../src/window_main.cpp" line="73"/>
<source>Expected end time: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="73"/>
<location filename="../src/window_main.cpp" line="75"/>
<source>This ban lasts indefinitely.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="79"/>
<location filename="../src/window_main.cpp" line="261"/>
<location filename="../src/window_main.cpp" line="81"/>
<location filename="../src/window_main.cpp" line="263"/>
<source>Invalid username.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="82"/>
<location filename="../src/window_main.cpp" line="84"/>
<source>Connection closed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="82"/>
<location filename="../src/window_main.cpp" line="84"/>
<source>The server has terminated your connection.
Reason: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="87"/>
<location filename="../src/window_main.cpp" line="89"/>
<source>Scheduled server shutdown</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location filename="../src/window_main.cpp" line="87"/>
<location filename="../src/window_main.cpp" line="89"/>
<source>The server is going to be restarted in %n minute(s).
All running games will be lost.
Reason for shutdown: %1</source>
@ -1544,240 +1557,241 @@ Reason for shutdown: %1</source>
</translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="136"/>
<location filename="../src/window_main.cpp" line="138"/>
<source>Number of players</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="136"/>
<location filename="../src/window_main.cpp" line="138"/>
<source>Please enter the number of players.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="145"/>
<location filename="../src/window_main.cpp" line="151"/>
<location filename="../src/window_main.cpp" line="147"/>
<location filename="../src/window_main.cpp" line="153"/>
<source>Player %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="163"/>
<location filename="../src/window_main.cpp" line="165"/>
<source>Load replay</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="217"/>
<location filename="../src/window_main.cpp" line="219"/>
<source>About Cockatrice</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="219"/>
<location filename="../src/window_main.cpp" line="221"/>
<source>Version %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="220"/>
<location filename="../src/window_main.cpp" line="222"/>
<source>Authors:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="221"/>
<location filename="../src/window_main.cpp" line="223"/>
<source>Translators:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="222"/>
<location filename="../src/window_main.cpp" line="224"/>
<source>Spanish:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="223"/>
<location filename="../src/window_main.cpp" line="225"/>
<source>Portugese (Portugal):</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="224"/>
<location filename="../src/window_main.cpp" line="226"/>
<source>Portugese (Brazil):</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="225"/>
<location filename="../src/window_main.cpp" line="227"/>
<source>French:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="226"/>
<location filename="../src/window_main.cpp" line="228"/>
<source>Japanese:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="227"/>
<location filename="../src/window_main.cpp" line="229"/>
<source>Korean:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="228"/>
<location filename="../src/window_main.cpp" line="230"/>
<source>Russian:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="229"/>
<location filename="../src/window_main.cpp" line="231"/>
<source>Italian:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="230"/>
<location filename="../src/window_main.cpp" line="232"/>
<source>Swedish:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="236"/>
<location filename="../src/window_main.cpp" line="243"/>
<location filename="../src/window_main.cpp" line="246"/>
<location filename="../src/window_main.cpp" line="257"/>
<location filename="../src/window_main.cpp" line="261"/>
<location filename="../src/window_main.cpp" line="264"/>
<location filename="../src/window_main.cpp" line="267"/>
<location filename="../src/window_main.cpp" line="273"/>
<location filename="../src/window_main.cpp" line="279"/>
<location filename="../src/window_main.cpp" line="238"/>
<location filename="../src/window_main.cpp" line="245"/>
<location filename="../src/window_main.cpp" line="248"/>
<location filename="../src/window_main.cpp" line="259"/>
<location filename="../src/window_main.cpp" line="263"/>
<location filename="../src/window_main.cpp" line="266"/>
<location filename="../src/window_main.cpp" line="269"/>
<location filename="../src/window_main.cpp" line="275"/>
<location filename="../src/window_main.cpp" line="281"/>
<location filename="../src/window_main.cpp" line="283"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="236"/>
<location filename="../src/window_main.cpp" line="238"/>
<source>Server timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="243"/>
<location filename="../src/window_main.cpp" line="245"/>
<source>Incorrect username or password. Please check your authentication information and try again.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="246"/>
<location filename="../src/window_main.cpp" line="248"/>
<source>There is already an active session using this user name.
Please close that session first and re-login.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="251"/>
<location filename="../src/window_main.cpp" line="253"/>
<source>You are banned until %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="253"/>
<location filename="../src/window_main.cpp" line="255"/>
<source>You are banned indefinitely.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="264"/>
<location filename="../src/window_main.cpp" line="266"/>
<source>This server requires user registration.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="267"/>
<location filename="../src/window_main.cpp" line="269"/>
<source>Unknown login error: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="273"/>
<location filename="../src/window_main.cpp" line="275"/>
<source>Socket error: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="279"/>
<location filename="../src/window_main.cpp" line="281"/>
<source>You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server.
Local version is %1, remote version is %2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="281"/>
<location filename="../src/window_main.cpp" line="283"/>
<source>Your Cockatrice client is obsolete. Please update your Cockatrice version.
Local version is %1, remote version is %2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="287"/>
<location filename="../src/window_main.cpp" line="289"/>
<source>Connecting to %1...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="288"/>
<location filename="../src/window_main.cpp" line="290"/>
<source>Disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="289"/>
<location filename="../src/window_main.cpp" line="291"/>
<source>Connected, logging in at %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="290"/>
<location filename="../src/window_main.cpp" line="292"/>
<source>Logged in as %1 at %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="299"/>
<location filename="../src/window_main.cpp" line="301"/>
<source>&amp;Connect...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="300"/>
<location filename="../src/window_main.cpp" line="302"/>
<source>&amp;Disconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="301"/>
<location filename="../src/window_main.cpp" line="303"/>
<source>Start &amp;local game...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="302"/>
<location filename="../src/window_main.cpp" line="304"/>
<source>&amp;Watch replay...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="303"/>
<location filename="../src/window_main.cpp" line="305"/>
<source>&amp;Deck editor</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="304"/>
<location filename="../src/window_main.cpp" line="306"/>
<source>&amp;Full screen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="305"/>
<location filename="../src/window_main.cpp" line="307"/>
<source>Ctrl+F</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="306"/>
<location filename="../src/window_main.cpp" line="308"/>
<source>&amp;Settings...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="307"/>
<location filename="../src/window_main.cpp" line="309"/>
<location filename="../src/window_main.cpp" line="457"/>
<source>&amp;Exit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="310"/>
<location filename="../src/window_main.cpp" line="312"/>
<source>A&amp;ctions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="312"/>
<location filename="../src/window_main.cpp" line="314"/>
<source>&amp;Cockatrice</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="314"/>
<location filename="../src/window_main.cpp" line="316"/>
<source>&amp;About Cockatrice</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="315"/>
<location filename="../src/window_main.cpp" line="317"/>
<source>&amp;Help</source>
<translation type="unfinished"></translation>
</message>
@ -2990,62 +3004,72 @@ Local version is %1, remote version is %2.</source>
<context>
<name>MessagesSettingsPage</name>
<message>
<location filename="../src/dlg_settings.cpp" line="693"/>
<location filename="../src/dlg_settings.cpp" line="701"/>
<source>&amp;Add</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="694"/>
<location filename="../src/dlg_settings.cpp" line="702"/>
<source>&amp;Remove</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="695"/>
<location filename="../src/dlg_settings.cpp" line="703"/>
<source>Chat settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="696"/>
<location filename="../src/dlg_settings.cpp" line="704"/>
<source>Enable chat mentions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="697"/>
<location filename="../src/dlg_settings.cpp" line="705"/>
<source>In-game message macros</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="698"/>
<location filename="../src/dlg_settings.cpp" line="706"/>
<source>Ignore unregistered users in main chat</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="699"/>
<location filename="../src/dlg_settings.cpp" line="707"/>
<source>Ignore chat room messages sent by unregistered users.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="700"/>
<location filename="../src/dlg_settings.cpp" line="708"/>
<source>Ignore private messages sent by unregistered users.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="701"/>
<location filename="../src/dlg_settings.cpp" line="709"/>
<source>Invert text color</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="702"/>
<location filename="../src/dlg_settings.cpp" line="710"/>
<source>Enable desktop notifications for private messages.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="711"/>
<source>Enable desktop notification for mentions.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="712"/>
<source>(Color is hexadecimal)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="676"/>
<location filename="../src/dlg_settings.cpp" line="684"/>
<source>Add message</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="676"/>
<location filename="../src/dlg_settings.cpp" line="684"/>
<source>Message:</source>
<translation type="unfinished"></translation>
</message>
@ -3657,37 +3681,37 @@ Local version is %1, remote version is %2.</source>
<context>
<name>QMenuBar</name>
<message>
<location filename="../src/window_main.cpp" line="350"/>
<location filename="../src/window_main.cpp" line="352"/>
<source>Services</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="351"/>
<location filename="../src/window_main.cpp" line="353"/>
<source>Hide %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="352"/>
<location filename="../src/window_main.cpp" line="354"/>
<source>Hide Others</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="353"/>
<location filename="../src/window_main.cpp" line="355"/>
<source>Show All</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="354"/>
<location filename="../src/window_main.cpp" line="356"/>
<source>Preferences...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="355"/>
<location filename="../src/window_main.cpp" line="357"/>
<source>Quit %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/window_main.cpp" line="356"/>
<location filename="../src/window_main.cpp" line="358"/>
<source>About %1</source>
<translation type="unfinished"></translation>
</message>
@ -3695,7 +3719,7 @@ Local version is %1, remote version is %2.</source>
<context>
<name>QObject</name>
<message>
<location filename="../src/window_main.cpp" line="165"/>
<location filename="../src/window_main.cpp" line="167"/>
<source>Cockatrice replays (*.cor)</source>
<translation type="unfinished"></translation>
</message>
@ -4337,17 +4361,22 @@ Please enter a name:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_game.cpp" line="1095"/>
<location filename="../src/tab_game.cpp" line="859"/>
<source>You are flooding the game. Please wait a couple of seconds.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_game.cpp" line="1106"/>
<source>You have been kicked out of the game.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_game.cpp" line="1189"/>
<location filename="../src/tab_game.cpp" line="1200"/>
<source>Replay %1: %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_game.cpp" line="1191"/>
<location filename="../src/tab_game.cpp" line="1202"/>
<source>Game %1: %2</source>
<translation type="unfinished"></translation>
</message>
@ -4355,32 +4384,37 @@ Please enter a name:</source>
<context>
<name>TabMessage</name>
<message>
<location filename="../src/tab_message.cpp" line="54"/>
<location filename="../src/tab_message.cpp" line="58"/>
<source>Private &amp;chat</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="55"/>
<location filename="../src/tab_message.cpp" line="59"/>
<source>&amp;Leave</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="71"/>
<location filename="../src/tab_message.cpp" line="75"/>
<source>%1 - Private chat</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="98"/>
<location filename="../src/tab_message.cpp" line="102"/>
<source>This user is ignoring you.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="115"/>
<location filename="../src/tab_message.cpp" line="128"/>
<source>Private message from </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="139"/>
<source>%1 has left the server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="121"/>
<location filename="../src/tab_message.cpp" line="145"/>
<source>%1 has joined the server.</source>
<translation type="unfinished"></translation>
</message>
@ -4448,42 +4482,42 @@ Please enter a name:</source>
<context>
<name>TabRoom</name>
<message>
<location filename="../src/tab_room.cpp" line="57"/>
<location filename="../src/tab_room.cpp" line="59"/>
<source>F12</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_room.cpp" line="120"/>
<location filename="../src/tab_room.cpp" line="122"/>
<source>&amp;Say:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_room.cpp" line="121"/>
<location filename="../src/tab_room.cpp" line="123"/>
<source>Chat</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_room.cpp" line="122"/>
<location filename="../src/tab_room.cpp" line="124"/>
<source>&amp;Room</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_room.cpp" line="123"/>
<location filename="../src/tab_room.cpp" line="125"/>
<source>&amp;Leave room</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_room.cpp" line="124"/>
<location filename="../src/tab_room.cpp" line="126"/>
<source>&amp;Clear chat</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_room.cpp" line="125"/>
<location filename="../src/tab_room.cpp" line="127"/>
<source>Chat Settings...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_room.cpp" line="164"/>
<location filename="../src/tab_room.cpp" line="171"/>
<source>You are flooding the chat. Please wait a couple of seconds.</source>
<translation type="unfinished"></translation>
</message>