From 81a8141fe5aa239ac5fd2a4ea6adf92a348913e5 Mon Sep 17 00:00:00 2001 From: Matt Lowe Date: Wed, 18 Mar 2015 16:36:07 +0100 Subject: [PATCH] Added system tray icon + Can be used for setting client size and closing the client. Will expand on by sending client alerts to the tray. Updated to push message notifactions to the toolbar Preview image: Added setting to enable/disable message popups Added functionality + updated popup message and translation + Double clicking tray icon will now bring up the app/minimize it + can now be alerted of mentions + added setting to set if you want mentions on desktop + clicking mention message will take you to the main chat + added translations for icon menu + removed maximize/minimize/restore from menu, not needed. Added disconnect + Disconnects any previous message slots/signals from the system icon message bubble --- cockatrice/src/chatview.cpp | 21 ++ cockatrice/src/chatview.h | 6 + cockatrice/src/dlg_settings.cpp | 10 + cockatrice/src/dlg_settings.h | 2 + cockatrice/src/main.cpp | 3 + cockatrice/src/main.h | 2 + cockatrice/src/settingscache.cpp | 12 + cockatrice/src/settingscache.h | 6 + cockatrice/src/tab_message.cpp | 24 ++ cockatrice/src/tab_message.h | 5 + cockatrice/src/tab_room.cpp | 7 + cockatrice/src/tab_room.h | 1 + cockatrice/src/window_main.cpp | 38 ++++ cockatrice/src/window_main.h | 11 + cockatrice/translations/cockatrice_en.ts | 274 +++++++++++++---------- 15 files changed, 302 insertions(+), 120 deletions(-) diff --git a/cockatrice/src/chatview.cpp b/cockatrice/src/chatview.cpp index 3b72afe2..c0a7e577 100644 --- a/cockatrice/src/chatview.cpp +++ b/cockatrice/src/chatview.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #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()); diff --git a/cockatrice/src/chatview.h b/cockatrice/src/chatview.h index 4589fb26..4fec655a 100644 --- a/cockatrice/src/chatview.h +++ b/cockatrice/src/chatview.h @@ -5,6 +5,7 @@ #include #include #include +#include #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 &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 diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp index fcc8d8ef..1807cb4c 100644 --- a/cockatrice/src/dlg_settings.cpp +++ b/cockatrice/src/dlg_settings.cpp @@ -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)")); } diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h index 1acda925..64814e87 100644 --- a/cockatrice/src/dlg_settings.h +++ b/cockatrice/src/dlg_settings.h @@ -169,6 +169,8 @@ private: QCheckBox invertMentionForeground; QCheckBox ignoreUnregUsersMainChat; QCheckBox ignoreUnregUserMessages; + QCheckBox messagePopups; + QCheckBox mentionPopups; QGroupBox *chatGroupBox; QGroupBox *messageShortcuts; QLineEdit *mentionColor; diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index 7e0eb3fa..b21cc374 100644 --- a/cockatrice/src/main.cpp +++ b/cockatrice/src/main.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #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 diff --git a/cockatrice/src/main.h b/cockatrice/src/main.h index 9237f23c..dc10de84 100644 --- a/cockatrice/src/main.h +++ b/cockatrice/src/main.h @@ -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; diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index 105afa70..552c1b81 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -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; diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h index 587bafa1..4bad12de 100644 --- a/cockatrice/src/settingscache.h +++ b/cockatrice/src/settingscache.h @@ -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; diff --git a/cockatrice/src/tab_message.cpp b/cockatrice/src/tab_message.cpp index 1c55d8d5..fbfaf699 100644 --- a/cockatrice/src/tab_message.cpp +++ b/cockatrice/src/tab_message.cpp @@ -6,6 +6,10 @@ #include "tab_message.h" #include "abstractclient.h" #include "chatview.h" +#include "main.h" +#include "settingscache.h" +#include +#include #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()))); diff --git a/cockatrice/src/tab_message.h b/cockatrice/src/tab_message.h index 9f2b19d2..b6fe1f03 100644 --- a/cockatrice/src/tab_message.h +++ b/cockatrice/src/tab_message.h @@ -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 diff --git a/cockatrice/src/tab_room.cpp b/cockatrice/src/tab_room.cpp index d0f435c1..06600b5b 100644 --- a/cockatrice/src/tab_room.cpp +++ b/cockatrice/src/tab_room.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #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(); diff --git a/cockatrice/src/tab_room.h b/cockatrice/src/tab_room.h index 115093fd..4783b11f 100644 --- a/cockatrice/src/tab_room.h +++ b/cockatrice/src/tab_room.h @@ -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); diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index 7f1c16f1..1f5743e0 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #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 diff --git a/cockatrice/src/window_main.h b/cockatrice/src/window_main.h index 8e2b48e2..f8799ccf 100644 --- a/cockatrice/src/window_main.h +++ b/cockatrice/src/window_main.h @@ -21,6 +21,7 @@ #define WINDOW_H #include +#include #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 tabMenus; QMenu *cockatriceMenu, *helpMenu; QAction *aConnect, *aDisconnect, *aSinglePlayer, *aWatchReplay, *aDeckEditor, *aFullScreen, *aSettings, *aExit, *aAbout; TabSupervisor *tabSupervisor; + QMenu *trayIconMenu; + + QAction *closeAction; + RemoteClient *client; QThread *clientThread; diff --git a/cockatrice/translations/cockatrice_en.ts b/cockatrice/translations/cockatrice_en.ts index e655f96a..36014c73 100644 --- a/cockatrice/translations/cockatrice_en.ts +++ b/cockatrice/translations/cockatrice_en.ts @@ -555,6 +555,19 @@ This is only saved for moderators and cannot be seen by the banned person. + + ChatView + + + mentioned you. + + + + + Click to view + + + DBPriceUpdater @@ -1092,19 +1105,19 @@ This is only saved for moderators and cannot be seen by the banned person. DlgSettings - - - + + + Error - + Unknown Error loading card database - + 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? - + 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? - + 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? - + File Error loading your card database. Would you like to change your database location setting? - + Your card database was loaded but contains no cards. Would you like to change your database location setting? - + 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? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? - + Settings - + General - + Appearance - + User interface - + Deck editor - + Chat Settings @@ -1487,54 +1500,54 @@ Would you like to change your database location setting? MainWindow - + There are too many concurrent connections from your address. - + Scheduled server shutdown. - + Banned by moderator - + Expected end time: %1 - + This ban lasts indefinitely. - - + + Invalid username. - + Connection closed - + The server has terminated your connection. Reason: %1 - + Scheduled server shutdown - + The server is going to be restarted in %n minute(s). All running games will be lost. Reason for shutdown: %1 @@ -1544,240 +1557,241 @@ Reason for shutdown: %1 - + Number of players - + Please enter the number of players. - - + + Player %1 - + Load replay - + About Cockatrice - + Version %1 - + Authors: - + Translators: - + Spanish: - + Portugese (Portugal): - + Portugese (Brazil): - + French: - + Japanese: - + Korean: - + Russian: - + Italian: - + Swedish: - - - - - - - - - + + + + + + + + + Error - + Server timeout - + Incorrect username or password. Please check your authentication information and try again. - + There is already an active session using this user name. Please close that session first and re-login. - + You are banned until %1. - + You are banned indefinitely. - + This server requires user registration. - + Unknown login error: %1 - + Socket error: %1 - + 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. - + Your Cockatrice client is obsolete. Please update your Cockatrice version. Local version is %1, remote version is %2. - + Connecting to %1... - + Disconnected - + Connected, logging in at %1 - + Logged in as %1 at %2 - + &Connect... - + &Disconnect - + Start &local game... - + &Watch replay... - + &Deck editor - + &Full screen - + Ctrl+F - + &Settings... - + + &Exit - + A&ctions - + &Cockatrice - + &About Cockatrice - + &Help @@ -2990,62 +3004,72 @@ Local version is %1, remote version is %2. MessagesSettingsPage - + &Add - + &Remove - + Chat settings - + Enable chat mentions - + In-game message macros - + Ignore unregistered users in main chat - + Ignore chat room messages sent by unregistered users. - + Ignore private messages sent by unregistered users. - + Invert text color - + + Enable desktop notifications for private messages. + + + + + Enable desktop notification for mentions. + + + + (Color is hexadecimal) - + Add message - + Message: @@ -3657,37 +3681,37 @@ Local version is %1, remote version is %2. QMenuBar - + Services - + Hide %1 - + Hide Others - + Show All - + Preferences... - + Quit %1 - + About %1 @@ -3695,7 +3719,7 @@ Local version is %1, remote version is %2. QObject - + Cockatrice replays (*.cor) @@ -4337,17 +4361,22 @@ Please enter a name: - + + You are flooding the game. Please wait a couple of seconds. + + + + You have been kicked out of the game. - + Replay %1: %2 - + Game %1: %2 @@ -4355,32 +4384,37 @@ Please enter a name: TabMessage - + Private &chat - + &Leave - + %1 - Private chat - + This user is ignoring you. - + + Private message from + + + + %1 has left the server. - + %1 has joined the server. @@ -4448,42 +4482,42 @@ Please enter a name: TabRoom - + F12 - + &Say: - + Chat - + &Room - + &Leave room - + &Clear chat - + Chat Settings... - + You are flooding the chat. Please wait a couple of seconds.