1 #include "tab_supervisor.h"
2
3 #include "abstractclient.h"
4 #include "main.h"
5 #include "pb/event_game_joined.pb.h"
6 #include "pb/event_notify_user.pb.h"
7 #include "pb/event_user_message.pb.h"
8 #include "pb/game_event_container.pb.h"
9 #include "pb/moderator_commands.pb.h"
10 #include "pb/room_commands.pb.h"
11 #include "pb/room_event.pb.h"
12 #include "pb/serverinfo_room.pb.h"
13 #include "pb/serverinfo_user.pb.h"
14 #include "pixmapgenerator.h"
15 #include "settingscache.h"
16 #include "tab_account.h"
17 #include "tab_admin.h"
18 #include "tab_deck_editor.h"
19 #include "tab_deck_storage.h"
20 #include "tab_game.h"
21 #include "tab_logs.h"
22 #include "tab_message.h"
23 #include "tab_replays.h"
24 #include "tab_room.h"
25 #include "tab_server.h"
26 #include "userlist.h"
27
28 #include <QApplication>
29 #include <QDebug>
30 #include <QMessageBox>
31 #include <QPainter>
32 #include <QSystemTrayIcon>
33
subElementRect(SubElement element,const QStyleOption * option,const QWidget * widget) const34 QRect MacOSTabFixStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
35 {
36 if (element != SE_TabBarTabText) {
37 return QProxyStyle::subElementRect(element, option, widget);
38 }
39
40 // Skip over QProxyStyle handling subElementRect,
41 // This fixes an issue with Qt 5.10 on OSX where the labels for tabs with a button and an icon
42 // get cut-off too early
43 return QCommonStyle::subElementRect(element, option, widget);
44 }
45
CloseButton(QWidget * parent)46 CloseButton::CloseButton(QWidget *parent) : QAbstractButton(parent)
47 {
48 setFocusPolicy(Qt::NoFocus);
49 setCursor(Qt::ArrowCursor);
50 resize(sizeHint());
51 }
52
sizeHint() const53 QSize CloseButton::sizeHint() const
54 {
55 ensurePolished();
56 int width = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, 0, this);
57 int height = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, 0, this);
58 return QSize(width, height);
59 }
60
enterEvent(QEvent * event)61 void CloseButton::enterEvent(QEvent *event)
62 {
63 update();
64 QAbstractButton::enterEvent(event);
65 }
66
leaveEvent(QEvent * event)67 void CloseButton::leaveEvent(QEvent *event)
68 {
69 update();
70 QAbstractButton::leaveEvent(event);
71 }
72
paintEvent(QPaintEvent *)73 void CloseButton::paintEvent(QPaintEvent * /*event*/)
74 {
75 QPainter p(this);
76 QStyleOption opt;
77 opt.init(this);
78 opt.state |= QStyle::State_AutoRaise;
79 if (isEnabled() && underMouse() && !isChecked() && !isDown())
80 opt.state |= QStyle::State_Raised;
81 if (isChecked())
82 opt.state |= QStyle::State_On;
83 if (isDown())
84 opt.state |= QStyle::State_Sunken;
85
86 if (const QTabBar *tb = qobject_cast<const QTabBar *>(parent())) {
87 int index = tb->currentIndex();
88 QTabBar::ButtonPosition position =
89 (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, tb);
90 if (tb->tabButton(index, position) == this)
91 opt.state |= QStyle::State_Selected;
92 }
93
94 style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p, this);
95 }
96
TabSupervisor(AbstractClient * _client,QWidget * parent)97 TabSupervisor::TabSupervisor(AbstractClient *_client, QWidget *parent)
98 : QTabWidget(parent), userInfo(0), client(_client), tabServer(0), tabUserLists(0), tabDeckStorage(0), tabReplays(0),
99 tabAdmin(0), tabLog(0)
100 {
101 setElideMode(Qt::ElideRight);
102 setMovable(true);
103 setIconSize(QSize(15, 15));
104
105 #if defined(Q_OS_MAC)
106 // This is necessary to fix an issue on macOS with qt5.10,
107 // where tabs with icons and buttons get drawn incorrectly
108 tabBar()->setStyle(new MacOSTabFixStyle);
109 #endif
110
111 connect(this, SIGNAL(currentChanged(int)), this, SLOT(updateCurrent(int)));
112
113 connect(client, SIGNAL(roomEventReceived(const RoomEvent &)), this, SLOT(processRoomEvent(const RoomEvent &)));
114 connect(client, SIGNAL(gameEventContainerReceived(const GameEventContainer &)), this,
115 SLOT(processGameEventContainer(const GameEventContainer &)));
116 connect(client, SIGNAL(gameJoinedEventReceived(const Event_GameJoined &)), this,
117 SLOT(gameJoined(const Event_GameJoined &)));
118 connect(client, SIGNAL(userMessageEventReceived(const Event_UserMessage &)), this,
119 SLOT(processUserMessageEvent(const Event_UserMessage &)));
120 connect(client, SIGNAL(maxPingTime(int, int)), this, SLOT(updatePingTime(int, int)));
121 connect(client, SIGNAL(notifyUserEventReceived(const Event_NotifyUser &)), this,
122 SLOT(processNotifyUserEvent(const Event_NotifyUser &)));
123
124 retranslateUi();
125 }
126
~TabSupervisor()127 TabSupervisor::~TabSupervisor()
128 {
129 stop();
130 }
131
retranslateUi()132 void TabSupervisor::retranslateUi()
133 {
134 QList<Tab *> tabs;
135 tabs.append(tabServer);
136 tabs.append(tabReplays);
137 tabs.append(tabDeckStorage);
138 tabs.append(tabAdmin);
139 tabs.append(tabUserLists);
140 tabs.append(tabLog);
141 QMapIterator<int, TabRoom *> roomIterator(roomTabs);
142 while (roomIterator.hasNext())
143 tabs.append(roomIterator.next().value());
144 QMapIterator<int, TabGame *> gameIterator(gameTabs);
145 while (gameIterator.hasNext())
146 tabs.append(gameIterator.next().value());
147 QListIterator<TabGame *> replayIterator(replayTabs);
148 while (replayIterator.hasNext())
149 tabs.append(replayIterator.next());
150 QListIterator<TabDeckEditor *> deckEditorIterator(deckEditorTabs);
151 while (deckEditorIterator.hasNext())
152 tabs.append(deckEditorIterator.next());
153 QMapIterator<QString, TabMessage *> messageIterator(messageTabs);
154 while (messageIterator.hasNext())
155 tabs.append(messageIterator.next().value());
156
157 for (int i = 0; i < tabs.size(); ++i)
158 if (tabs[i]) {
159 int idx = indexOf(tabs[i]);
160 QString tabText = tabs[i]->getTabText();
161 setTabText(idx, sanitizeTabName(tabText));
162 setTabToolTip(idx, sanitizeHtml(tabText));
163 tabs[i]->retranslateUi();
164 }
165 }
166
closeRequest()167 bool TabSupervisor::closeRequest()
168 {
169 if (getGameCount()) {
170 if (QMessageBox::question(this, tr("Are you sure?"),
171 tr("There are still open games. Are you sure you want to quit?"),
172 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) {
173 return false;
174 }
175 }
176
177 foreach (TabDeckEditor *tab, deckEditorTabs) {
178 if (!tab->confirmClose())
179 return false;
180 }
181
182 return true;
183 }
184
getClient() const185 AbstractClient *TabSupervisor::getClient() const
186 {
187 return localClients.isEmpty() ? client : localClients.first();
188 }
189
sanitizeTabName(QString dirty) const190 QString TabSupervisor::sanitizeTabName(QString dirty) const
191 {
192 return dirty.replace("&", "&&");
193 }
194
sanitizeHtml(QString dirty) const195 QString TabSupervisor::sanitizeHtml(QString dirty) const
196 {
197 return dirty.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
198 }
199
myAddTab(Tab * tab)200 int TabSupervisor::myAddTab(Tab *tab)
201 {
202 connect(tab, SIGNAL(userEvent(bool)), this, SLOT(tabUserEvent(bool)));
203 connect(tab, SIGNAL(tabTextChanged(Tab *, QString)), this, SLOT(updateTabText(Tab *, QString)));
204
205 QString tabText = tab->getTabText();
206 int idx = addTab(tab, sanitizeTabName(tabText));
207 setTabToolTip(idx, sanitizeHtml(tabText));
208
209 return idx;
210 }
211
start(const ServerInfo_User & _userInfo)212 void TabSupervisor::start(const ServerInfo_User &_userInfo)
213 {
214 isLocalGame = false;
215 userInfo = new ServerInfo_User(_userInfo);
216
217 tabServer = new TabServer(this, client);
218 connect(tabServer, SIGNAL(roomJoined(const ServerInfo_Room &, bool)), this,
219 SLOT(addRoomTab(const ServerInfo_Room &, bool)));
220 myAddTab(tabServer);
221
222 tabUserLists = new TabUserLists(this, client, *userInfo);
223 connect(tabUserLists, SIGNAL(openMessageDialog(const QString &, bool)), this,
224 SLOT(addMessageTab(const QString &, bool)));
225 connect(tabUserLists, SIGNAL(userJoined(ServerInfo_User)), this, SLOT(processUserJoined(ServerInfo_User)));
226 connect(tabUserLists, SIGNAL(userLeft(const QString &)), this, SLOT(processUserLeft(const QString &)));
227 myAddTab(tabUserLists);
228
229 updatePingTime(0, -1);
230
231 if (userInfo->user_level() & ServerInfo_User::IsRegistered) {
232 tabDeckStorage = new TabDeckStorage(this, client);
233 connect(tabDeckStorage, SIGNAL(openDeckEditor(const DeckLoader *)), this,
234 SLOT(addDeckEditorTab(const DeckLoader *)));
235 myAddTab(tabDeckStorage);
236
237 tabReplays = new TabReplays(this, client);
238 connect(tabReplays, SIGNAL(openReplay(GameReplay *)), this, SLOT(openReplay(GameReplay *)));
239 myAddTab(tabReplays);
240 } else {
241 tabDeckStorage = 0;
242 tabReplays = 0;
243 }
244
245 if (userInfo->user_level() & ServerInfo_User::IsModerator) {
246 tabAdmin = new TabAdmin(this, client, (userInfo->user_level() & ServerInfo_User::IsAdmin));
247 connect(tabAdmin, SIGNAL(adminLockChanged(bool)), this, SIGNAL(adminLockChanged(bool)));
248 myAddTab(tabAdmin);
249
250 tabLog = new TabLog(this, client);
251 myAddTab(tabLog);
252 } else {
253 tabAdmin = 0;
254 tabLog = 0;
255 }
256
257 retranslateUi();
258 }
259
startLocal(const QList<AbstractClient * > & _clients)260 void TabSupervisor::startLocal(const QList<AbstractClient *> &_clients)
261 {
262 tabUserLists = 0;
263 tabDeckStorage = 0;
264 tabReplays = 0;
265 tabAdmin = 0;
266 tabLog = 0;
267 isLocalGame = true;
268 userInfo = new ServerInfo_User;
269 localClients = _clients;
270 for (int i = 0; i < localClients.size(); ++i)
271 connect(localClients[i], SIGNAL(gameEventContainerReceived(const GameEventContainer &)), this,
272 SLOT(processGameEventContainer(const GameEventContainer &)));
273 connect(localClients.first(), SIGNAL(gameJoinedEventReceived(const Event_GameJoined &)), this,
274 SLOT(localGameJoined(const Event_GameJoined &)));
275 }
276
stop()277 void TabSupervisor::stop()
278 {
279 if ((!client) && localClients.isEmpty())
280 return;
281
282 if (!localClients.isEmpty()) {
283 for (int i = 0; i < localClients.size(); ++i)
284 localClients[i]->deleteLater();
285 localClients.clear();
286
287 emit localGameEnded();
288 } else {
289 if (tabUserLists)
290 tabUserLists->deleteLater();
291 if (tabServer)
292 tabServer->deleteLater();
293 if (tabDeckStorage)
294 tabDeckStorage->deleteLater();
295 if (tabReplays)
296 tabReplays->deleteLater();
297 if (tabAdmin)
298 tabAdmin->deleteLater();
299 if (tabLog)
300 tabLog->deleteLater();
301 }
302 tabUserLists = 0;
303 tabServer = 0;
304 tabDeckStorage = 0;
305 tabReplays = 0;
306 tabAdmin = 0;
307 tabLog = 0;
308
309 QMapIterator<int, TabRoom *> roomIterator(roomTabs);
310 while (roomIterator.hasNext())
311 roomIterator.next().value()->deleteLater();
312 roomTabs.clear();
313
314 QMapIterator<int, TabGame *> gameIterator(gameTabs);
315 while (gameIterator.hasNext())
316 gameIterator.next().value()->deleteLater();
317 gameTabs.clear();
318
319 QListIterator<TabGame *> replayIterator(replayTabs);
320 while (replayIterator.hasNext())
321 replayIterator.next()->deleteLater();
322 replayTabs.clear();
323
324 delete userInfo;
325 userInfo = 0;
326 }
327
updatePingTime(int value,int max)328 void TabSupervisor::updatePingTime(int value, int max)
329 {
330 if (!tabServer)
331 return;
332 if (tabServer->getContentsChanged())
333 return;
334
335 setTabIcon(indexOf(tabServer), QIcon(PingPixmapGenerator::generatePixmap(15, value, max)));
336 }
337
closeButtonPressed()338 void TabSupervisor::closeButtonPressed()
339 {
340 Tab *tab = static_cast<Tab *>(static_cast<CloseButton *>(sender())->property("tab").value<QObject *>());
341 tab->closeRequest();
342 }
343
addCloseButtonToTab(Tab * tab,int tabIndex)344 void TabSupervisor::addCloseButtonToTab(Tab *tab, int tabIndex)
345 {
346 QTabBar::ButtonPosition closeSide =
347 (QTabBar::ButtonPosition)tabBar()->style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, tabBar());
348 CloseButton *closeButton = new CloseButton;
349 connect(closeButton, SIGNAL(clicked()), this, SLOT(closeButtonPressed()));
350 closeButton->setProperty("tab", QVariant::fromValue((QObject *)tab));
351 tabBar()->setTabButton(tabIndex, closeSide, closeButton);
352 }
353
gameJoined(const Event_GameJoined & event)354 void TabSupervisor::gameJoined(const Event_GameJoined &event)
355 {
356 QMap<int, QString> roomGameTypes;
357 TabRoom *room = roomTabs.value(event.game_info().room_id());
358 if (room)
359 roomGameTypes = room->getGameTypes();
360 else
361 for (int i = 0; i < event.game_types_size(); ++i)
362 roomGameTypes.insert(event.game_types(i).game_type_id(),
363 QString::fromStdString(event.game_types(i).description()));
364
365 TabGame *tab = new TabGame(this, QList<AbstractClient *>() << client, event, roomGameTypes);
366 connect(tab, SIGNAL(gameClosing(TabGame *)), this, SLOT(gameLeft(TabGame *)));
367 connect(tab, SIGNAL(openMessageDialog(const QString &, bool)), this, SLOT(addMessageTab(const QString &, bool)));
368 connect(tab, SIGNAL(openDeckEditor(const DeckLoader *)), this, SLOT(addDeckEditorTab(const DeckLoader *)));
369 int tabIndex = myAddTab(tab);
370 addCloseButtonToTab(tab, tabIndex);
371 gameTabs.insert(event.game_info().game_id(), tab);
372 setCurrentWidget(tab);
373 }
374
localGameJoined(const Event_GameJoined & event)375 void TabSupervisor::localGameJoined(const Event_GameJoined &event)
376 {
377 TabGame *tab = new TabGame(this, localClients, event, QMap<int, QString>());
378 connect(tab, SIGNAL(gameClosing(TabGame *)), this, SLOT(gameLeft(TabGame *)));
379 connect(tab, SIGNAL(openDeckEditor(const DeckLoader *)), this, SLOT(addDeckEditorTab(const DeckLoader *)));
380 int tabIndex = myAddTab(tab);
381 addCloseButtonToTab(tab, tabIndex);
382 gameTabs.insert(event.game_info().game_id(), tab);
383 setCurrentWidget(tab);
384
385 for (int i = 1; i < localClients.size(); ++i) {
386 Command_JoinGame cmd;
387 cmd.set_game_id(event.game_info().game_id());
388 localClients[i]->sendCommand(localClients[i]->prepareRoomCommand(cmd, 0));
389 }
390 }
391
gameLeft(TabGame * tab)392 void TabSupervisor::gameLeft(TabGame *tab)
393 {
394 if (tab == currentWidget())
395 emit setMenu();
396
397 gameTabs.remove(tab->getGameId());
398 removeTab(indexOf(tab));
399
400 if (!localClients.isEmpty())
401 stop();
402 }
403
addRoomTab(const ServerInfo_Room & info,bool setCurrent)404 void TabSupervisor::addRoomTab(const ServerInfo_Room &info, bool setCurrent)
405 {
406 TabRoom *tab = new TabRoom(this, client, userInfo, info);
407 connect(tab, SIGNAL(maximizeClient()), this, SLOT(maximizeMainWindow()));
408 connect(tab, SIGNAL(roomClosing(TabRoom *)), this, SLOT(roomLeft(TabRoom *)));
409 connect(tab, SIGNAL(openMessageDialog(const QString &, bool)), this, SLOT(addMessageTab(const QString &, bool)));
410 int tabIndex = myAddTab(tab);
411 addCloseButtonToTab(tab, tabIndex);
412 roomTabs.insert(info.room_id(), tab);
413 if (setCurrent)
414 setCurrentWidget(tab);
415 }
416
roomLeft(TabRoom * tab)417 void TabSupervisor::roomLeft(TabRoom *tab)
418 {
419 if (tab == currentWidget())
420 emit setMenu();
421
422 roomTabs.remove(tab->getRoomId());
423 removeTab(indexOf(tab));
424 }
425
openReplay(GameReplay * replay)426 void TabSupervisor::openReplay(GameReplay *replay)
427 {
428 TabGame *replayTab = new TabGame(this, replay);
429 connect(replayTab, SIGNAL(gameClosing(TabGame *)), this, SLOT(replayLeft(TabGame *)));
430 int tabIndex = myAddTab(replayTab);
431 addCloseButtonToTab(replayTab, tabIndex);
432 replayTabs.append(replayTab);
433 setCurrentWidget(replayTab);
434 }
435
replayLeft(TabGame * tab)436 void TabSupervisor::replayLeft(TabGame *tab)
437 {
438 if (tab == currentWidget())
439 emit setMenu();
440
441 replayTabs.removeAt(replayTabs.indexOf(tab));
442 }
443
addMessageTab(const QString & receiverName,bool focus)444 TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus)
445 {
446 if (receiverName == QString::fromStdString(userInfo->name()))
447 return nullptr;
448
449 ServerInfo_User otherUser;
450 UserListTWI *twi = tabUserLists->getAllUsersList()->getUsers().value(receiverName);
451 if (twi)
452 otherUser = twi->getUserInfo();
453 else
454 otherUser.set_name(receiverName.toStdString());
455
456 TabMessage *tab;
457 tab = messageTabs.value(QString::fromStdString(otherUser.name()));
458 if (tab) {
459 if (focus)
460 setCurrentWidget(tab);
461 return tab;
462 }
463
464 tab = new TabMessage(this, client, *userInfo, otherUser);
465 connect(tab, SIGNAL(talkClosing(TabMessage *)), this, SLOT(talkLeft(TabMessage *)));
466 connect(tab, SIGNAL(maximizeClient()), this, SLOT(maximizeMainWindow()));
467 int tabIndex = myAddTab(tab);
468 addCloseButtonToTab(tab, tabIndex);
469 messageTabs.insert(receiverName, tab);
470 if (focus)
471 setCurrentWidget(tab);
472 return tab;
473 }
474
maximizeMainWindow()475 void TabSupervisor::maximizeMainWindow()
476 {
477 emit showWindowIfHidden();
478 }
479
talkLeft(TabMessage * tab)480 void TabSupervisor::talkLeft(TabMessage *tab)
481 {
482 if (tab == currentWidget())
483 emit setMenu();
484
485 messageTabs.remove(tab->getUserName());
486 removeTab(indexOf(tab));
487 }
488
addDeckEditorTab(const DeckLoader * deckToOpen)489 TabDeckEditor *TabSupervisor::addDeckEditorTab(const DeckLoader *deckToOpen)
490 {
491 TabDeckEditor *tab = new TabDeckEditor(this);
492 if (deckToOpen)
493 tab->setDeck(new DeckLoader(*deckToOpen));
494 connect(tab, SIGNAL(deckEditorClosing(TabDeckEditor *)), this, SLOT(deckEditorClosed(TabDeckEditor *)));
495 int tabIndex = myAddTab(tab);
496 addCloseButtonToTab(tab, tabIndex);
497 deckEditorTabs.append(tab);
498 setCurrentWidget(tab);
499 return tab;
500 }
501
deckEditorClosed(TabDeckEditor * tab)502 void TabSupervisor::deckEditorClosed(TabDeckEditor *tab)
503 {
504 if (tab == currentWidget())
505 emit setMenu();
506
507 deckEditorTabs.removeAt(deckEditorTabs.indexOf(tab));
508 removeTab(indexOf(tab));
509 }
510
tabUserEvent(bool globalEvent)511 void TabSupervisor::tabUserEvent(bool globalEvent)
512 {
513 Tab *tab = static_cast<Tab *>(sender());
514 if (tab != currentWidget()) {
515 tab->setContentsChanged(true);
516 setTabIcon(indexOf(tab), QPixmap("theme:icons/tab_changed"));
517 }
518 if (globalEvent && SettingsCache::instance().getNotificationsEnabled())
519 QApplication::alert(this);
520 }
521
updateTabText(Tab * tab,const QString & newTabText)522 void TabSupervisor::updateTabText(Tab *tab, const QString &newTabText)
523 {
524 int idx = indexOf(tab);
525 setTabText(idx, sanitizeTabName(newTabText));
526 setTabToolTip(idx, sanitizeHtml(newTabText));
527 }
528
processRoomEvent(const RoomEvent & event)529 void TabSupervisor::processRoomEvent(const RoomEvent &event)
530 {
531 TabRoom *tab = roomTabs.value(event.room_id(), 0);
532 if (tab)
533 tab->processRoomEvent(event);
534 }
535
processGameEventContainer(const GameEventContainer & cont)536 void TabSupervisor::processGameEventContainer(const GameEventContainer &cont)
537 {
538 TabGame *tab = gameTabs.value(cont.game_id());
539 if (tab)
540 tab->processGameEventContainer(cont, qobject_cast<AbstractClient *>(sender()));
541 else
542 qDebug() << "gameEvent: invalid gameId";
543 }
544
processUserMessageEvent(const Event_UserMessage & event)545 void TabSupervisor::processUserMessageEvent(const Event_UserMessage &event)
546 {
547 QString senderName = QString::fromStdString(event.sender_name());
548 TabMessage *tab = messageTabs.value(senderName);
549 if (!tab)
550 tab = messageTabs.value(QString::fromStdString(event.receiver_name()));
551 if (!tab) {
552 UserListTWI *twi = tabUserLists->getAllUsersList()->getUsers().value(senderName);
553 if (twi) {
554 UserLevelFlags userLevel = UserLevelFlags(twi->getUserInfo().user_level());
555 if (SettingsCache::instance().getIgnoreUnregisteredUserMessages() &&
556 !userLevel.testFlag(ServerInfo_User::IsRegistered))
557 // Flags are additive, so reg/mod/admin are all IsRegistered
558 return;
559 }
560 tab = addMessageTab(QString::fromStdString(event.sender_name()), false);
561 }
562 if (!tab)
563 return;
564 tab->processUserMessageEvent(event);
565 }
566
actShowPopup(const QString & message)567 void TabSupervisor::actShowPopup(const QString &message)
568 {
569 qDebug() << "ACT SHOW POPUP";
570 if (trayIcon && (QApplication::activeWindow() == nullptr || QApplication::focusWidget() == nullptr)) {
571 qDebug() << "LAUNCHING POPUP";
572 // disconnect(trayIcon, SIGNAL(messageClicked()), nullptr, nullptr);
573 trayIcon->showMessage(message, tr("Click to view"));
574 // connect(trayIcon, SIGNAL(messageClicked()), chatView, SLOT(actMessageClicked()));
575 }
576 }
577
processUserLeft(const QString & userName)578 void TabSupervisor::processUserLeft(const QString &userName)
579 {
580 TabMessage *tab = messageTabs.value(userName);
581 if (tab)
582 tab->processUserLeft();
583 }
584
processUserJoined(const ServerInfo_User & userInfoJoined)585 void TabSupervisor::processUserJoined(const ServerInfo_User &userInfoJoined)
586 {
587 QString userName = QString::fromStdString(userInfoJoined.name());
588 if (isUserBuddy(userName)) {
589 Tab *tab = static_cast<Tab *>(getUserListsTab());
590
591 if (tab != currentWidget()) {
592 tab->setContentsChanged(true);
593 QPixmap avatarPixmap =
594 UserLevelPixmapGenerator::generatePixmap(13, (UserLevelFlags)userInfoJoined.user_level(), true,
595 QString::fromStdString(userInfoJoined.privlevel()));
596 setTabIcon(indexOf(tab), QPixmap(avatarPixmap));
597 }
598
599 if (SettingsCache::instance().getBuddyConnectNotificationsEnabled()) {
600 QApplication::alert(this);
601 this->actShowPopup(tr("Your buddy %1 has signed on!").arg(userName));
602 }
603 }
604
605 TabMessage *tab = messageTabs.value(userName);
606 if (tab)
607 tab->processUserJoined(userInfoJoined);
608 }
609
updateCurrent(int index)610 void TabSupervisor::updateCurrent(int index)
611 {
612 if (index != -1) {
613 Tab *tab = static_cast<Tab *>(widget(index));
614 if (tab->getContentsChanged()) {
615 setTabIcon(index, QIcon());
616 tab->setContentsChanged(false);
617 }
618 emit setMenu(static_cast<Tab *>(widget(index))->getTabMenus());
619 tab->tabActivated();
620 } else
621 emit setMenu();
622 }
623
624 /**
625 * Determine if a user is a moderator/administrator
626 * By seeing if they have the admin tab open & unlocked
627 * @return if the admin tab is open & unlocked
628 */
getAdminLocked() const629 bool TabSupervisor::getAdminLocked() const
630 {
631 if (!tabAdmin)
632 return true;
633 return tabAdmin->getLocked();
634 }
635
processNotifyUserEvent(const Event_NotifyUser & event)636 void TabSupervisor::processNotifyUserEvent(const Event_NotifyUser &event)
637 {
638
639 switch ((Event_NotifyUser::NotificationType)event.type()) {
640 case Event_NotifyUser::UNKNOWN:
641 QMessageBox::information(
642 this, tr("Unknown Event"),
643 tr("The server has sent you a message that your client does not understand.\nThis message might mean "
644 "there is a new version of Cockatrice available or this server is running a custom or pre-release "
645 "version.\n\nTo update your client, go to Help -> Check for Updates."));
646 break;
647 case Event_NotifyUser::IDLEWARNING:
648 QMessageBox::information(this, tr("Idle Timeout"), tr("You are about to be logged out due to inactivity."));
649 break;
650 case Event_NotifyUser::PROMOTED:
651 QMessageBox::information(
652 this, tr("Promotion"),
653 tr("You have been promoted. Please log out and back in for changes to take effect."));
654 break;
655 case Event_NotifyUser::WARNING: {
656 if (!QString::fromStdString(event.warning_reason()).simplified().isEmpty())
657 QMessageBox::warning(this, tr("Warned"),
658 tr("You have received a warning due to %1.\nPlease refrain from engaging in this "
659 "activity or further actions may be taken against you. If you have any "
660 "questions, please private message a moderator.")
661 .arg(QString::fromStdString(event.warning_reason()).simplified()));
662 break;
663 }
664 case Event_NotifyUser::CUSTOM: {
665 if (!QString::fromStdString(event.custom_title()).simplified().isEmpty() &&
666 !QString::fromStdString(event.custom_content()).simplified().isEmpty()) {
667 QMessageBox msgBox;
668 msgBox.setParent(this);
669 msgBox.setWindowFlags(Qt::Dialog);
670 msgBox.setIcon(QMessageBox::Information);
671 msgBox.setWindowTitle(QString::fromStdString(event.custom_title()).simplified());
672 msgBox.setText(tr("You have received the following message from the server.\n(custom messages like "
673 "these could be untranslated)"));
674 msgBox.setDetailedText(QString::fromStdString(event.custom_content()).simplified());
675 msgBox.setMinimumWidth(200);
676 msgBox.exec();
677 }
678 break;
679 }
680 default:;
681 }
682 }
683
isOwnUserRegistered() const684 bool TabSupervisor::isOwnUserRegistered() const
685 {
686 return static_cast<bool>(getUserInfo()->user_level() & ServerInfo_User::IsRegistered);
687 }
688
getOwnUsername() const689 QString TabSupervisor::getOwnUsername() const
690 {
691 return userInfo ? QString::fromStdString(userInfo->name()) : QString();
692 }
693
isUserBuddy(const QString & userName) const694 bool TabSupervisor::isUserBuddy(const QString &userName) const
695 {
696 if (!getUserListsTab())
697 return false;
698 if (!getUserListsTab()->getBuddyList())
699 return false;
700 QMap<QString, UserListTWI *> buddyList = getUserListsTab()->getBuddyList()->getUsers();
701 bool senderIsBuddy = buddyList.contains(userName);
702 return senderIsBuddy;
703 }
704
isUserIgnored(const QString & userName) const705 bool TabSupervisor::isUserIgnored(const QString &userName) const
706 {
707 if (!getUserListsTab())
708 return false;
709 if (!getUserListsTab()->getIgnoreList())
710 return false;
711 QMap<QString, UserListTWI *> buddyList = getUserListsTab()->getIgnoreList()->getUsers();
712 bool senderIsBuddy = buddyList.contains(userName);
713 return senderIsBuddy;
714 }
715
getOnlineUser(const QString & userName) const716 const ServerInfo_User *TabSupervisor::getOnlineUser(const QString &userName) const
717 {
718 if (!getUserListsTab())
719 return nullptr;
720 if (!getUserListsTab()->getAllUsersList())
721 return nullptr;
722 QMap<QString, UserListTWI *> userList = getUserListsTab()->getAllUsersList()->getUsers();
723 const QString &userNameToMatchLower = userName.toLower();
724 QMap<QString, UserListTWI *>::iterator i;
725
726 for (i = userList.begin(); i != userList.end(); ++i)
727 if (i.key().toLower() == userNameToMatchLower) {
728 const ServerInfo_User &userInfo = i.value()->getUserInfo();
729 return &userInfo;
730 }
731
732 return nullptr;
733 };
734