1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 1999-2014 Licq developers <licq-dev@googlegroups.com>
4 *
5 * Licq is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * Licq is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Licq; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "mainwin.h"
21
22 #include "config.h"
23
24 #include <boost/foreach.hpp>
25 #include <cctype>
26
27 #ifdef USE_KDE
28 #include <KDE/KApplication>
29 #include <KDE/KGlobal>
30 #include <KDE/KGlobalSettings>
31 #include <KDE/KStandardDirs>
32 #include <KDE/KWindowSystem>
33 #include <KDE/KIconLoader>
34 #include <KDE/KUrl>
35 #else
36 #include <QApplication>
37 #endif
38
39 #include <QAction>
40 #include <QActionGroup>
41 #include <QCloseEvent>
42 #include <QDateTime>
43 #include <QDesktopWidget>
44 #include <QHBoxLayout>
45 #include <QImage>
46 #include <QKeyEvent>
47 #include <QMenu>
48 #include <QMoveEvent>
49 #include <QMouseEvent>
50 #include <QPainter>
51 #include <QPixmap>
52 #include <QPushButton>
53 #include <QResizeEvent>
54 #include <QShortcut>
55 #include <QStyle>
56 #include <QStyleFactory>
57 #include <QTextEdit>
58 #include <QVBoxLayout>
59
60 #if defined(Q_WS_X11)
61 #include <QX11Info>
62 #endif /* defined(Q_WS_X11) */
63
64 #include <licq/logging/log.h>
65 #include <licq/contactlist/group.h>
66 #include <licq/contactlist/owner.h>
67 #include <licq/contactlist/usermanager.h>
68 #include <licq/daemon.h>
69 #include <licq/event.h>
70 #include <licq/icq/icq.h>
71 #include <licq/plugin/protocolplugin.h>
72 #include <licq/pluginsignal.h>
73
74 #include "config/contactlist.h"
75 #include "config/general.h"
76 #include "config/iconmanager.h"
77 #include "config/shortcuts.h"
78 #include "config/skin.h"
79
80 #include "contactlist/contactlist.h"
81
82 #include "dockicons/dockicon.h"
83
84 #include "dialogs/aboutdlg.h"
85 #include "dialogs/adduserdlg.h"
86 #include "dialogs/awaymsgdlg.h"
87 #include "dialogs/hintsdlg.h"
88 #include "dialogs/historydlg.h"
89 #include "dialogs/logwindow.h"
90 #include "dialogs/ownermanagerdlg.h"
91 #include "dialogs/showawaymsgdlg.h"
92 #include "dialogs/statsdlg.h"
93
94 #include "helpers/support.h"
95
96 #include "widgets/skinnablebutton.h"
97 #include "widgets/skinnablecombobox.h"
98 #include "widgets/skinnablelabel.h"
99
100 #include "views/userview.h"
101
102 #include "messagebox.h"
103 #include "gui-defines.h"
104 #include "licqgui.h"
105 #include "signalmanager.h"
106 #include "systemmenu.h"
107 #include "usermenu.h"
108
109 using namespace LicqQtGui;
110 /* TRANSLATOR LicqQtGui::MainWindow */
111
112 MainWindow* LicqQtGui::gMainWindow = NULL;
113
MainWindow(bool bStartHidden,QWidget * parent)114 MainWindow::MainWindow(bool bStartHidden, QWidget* parent)
115 : QWidget(parent),
116 myInMiniMode(false)
117 {
118 Support::setWidgetProps(this, "MainWindow");
119 setAttribute(Qt::WA_AlwaysShowToolTips, true);
120
121 assert(gMainWindow == NULL);
122 gMainWindow = this;
123
124 Config::General* conf = Config::General::instance();
125
126 connect(conf, SIGNAL(mainwinChanged()), SLOT(updateConfig()));
127 connect(Config::ContactList::instance(),
128 SIGNAL(currentListChanged()), SLOT(updateCurrentGroup()));
129
130 myCaption = "Licq";
131 setWindowTitle(myCaption);
132 setWindowIconText(myCaption);
133
134 // Group Combo Box
135 myUserGroupsBox = new SkinnableComboBox(this);
136 connect(myUserGroupsBox, SIGNAL(activated(int)), SLOT(setCurrentGroup(int)));
137
138 // Widgets controlled completely by the skin
139 mySystemButton = NULL;
140 myMessageField = NULL;
141 myStatusField = NULL;
142 myMenuBar = NULL;
143 connect(IconManager::instance(),
144 SIGNAL(statusIconsChanged()), SLOT(updateStatus()));
145
146 mySystemMenu = new SystemMenu(this);
147
148 QActionGroup* userFuncGroup = new QActionGroup(this);
149 userFuncGroup->setExclusive(false);
150 connect(userFuncGroup,
151 SIGNAL(triggered(QAction*)), SLOT(callUserFunction(QAction*)));
152 #define ADD_USERFUNCACTION(var, data) \
153 var = new QAction(userFuncGroup); \
154 var->setData(data);
155
156 ADD_USERFUNCACTION(myViewEventAction, -1)
157 ADD_USERFUNCACTION(mySendMessageAction, MessageEvent)
158 ADD_USERFUNCACTION(mySendUrlAction, UrlEvent)
159 ADD_USERFUNCACTION(mySendFileAction, ChatEvent)
160 ADD_USERFUNCACTION(mySendChatRequestAction, FileEvent)
161 #undef ADD_USERFUNCACTION
162 addActions(userFuncGroup->actions());
163
164 myCheckUserArAction = new QAction(this);
165 addAction(myCheckUserArAction);
166 connect(myCheckUserArAction, SIGNAL(triggered()), SLOT(checkUserAutoResponse()));
167 myViewHistoryAction = new QAction(this);
168 addAction(myViewHistoryAction);
169 connect(myViewHistoryAction, SIGNAL(triggered()), SLOT(showUserHistory()));
170 QShortcut* shortcut;
171 shortcut = new QShortcut(Qt::CTRL + Qt::Key_Delete, this);
172 connect(shortcut, SIGNAL(activated()), SLOT(removeUserFromList()));
173 shortcut = new QShortcut(Qt::Key_Delete, this);
174 connect(shortcut, SIGNAL(activated()), SLOT(removeUserFromGroup()));
175
176 updateShortcuts();
177 connect(Config::Shortcuts::instance(), SIGNAL(shortcutsChanged()), SLOT(updateShortcuts()));
178
179 CreateUserView();
180
181 usprintfHelp = tr(
182 "<ul>"
183 "<li><tt>%a - </tt>user alias</li>"
184 "<li><tt>%c - </tt>cellular number</li>"
185 "<li><tt>%e - </tt>email</li>"
186 "<li><tt>%f - </tt>first name</li>"
187 "<li><tt>%h - </tt>phone number</li>"
188 "<li><tt>%i - </tt>user ip</li>"
189 "<li><tt>%l - </tt>last name</li>"
190 "<li><tt>%L - </tt>local time</li>"
191 "<li><tt>%m - </tt># pending messages</li>"
192 "<li><tt>%M - </tt># pending messages (if any)</li>"
193 "<li><tt>%n - </tt>full name</li>"
194 "<li><tt>%o - </tt>last seen online</li>"
195 "<li><tt>%O - </tt>online since</li>"
196 "<li><tt>%p - </tt>user port</li>"
197 "<li><tt>%P - </tt>Protocol</li>"
198 "<li><tt>%s - </tt>full status</li>"
199 "<li><tt>%S - </tt>abbreviated status</li>"
200 "<li><tt>%u - </tt>uin</li>"
201 "<li><tt>%w - </tt>webpage</li></ul>");
202
203 connect(gGuiSignalManager, SIGNAL(updatedList(unsigned long, int, const Licq::UserId&)),
204 SLOT(slot_updatedList(unsigned long)));
205 connect(gGuiSignalManager, SIGNAL(updatedUser(const Licq::UserId&, unsigned long, int, unsigned long)),
206 SLOT(slot_updatedUser(const Licq::UserId&, unsigned long, int)));
207 connect(gGuiSignalManager, SIGNAL(updatedStatus(const Licq::UserId&)),
208 SLOT(updateStatus()));
209 connect(gGuiSignalManager, SIGNAL(ownerAdded(const Licq::UserId&)),
210 SLOT(updateStatus()));
211 connect(gGuiSignalManager, SIGNAL(ownerRemoved(const Licq::UserId&)),
212 SLOT(updateStatus()));
213 connect(gGuiSignalManager, SIGNAL(logon()),
214 SLOT(slot_logon()));
215 connect(gGuiSignalManager, SIGNAL(ui_showuserlist()), SLOT(unhide()));
216 connect(gGuiSignalManager, SIGNAL(ui_hideuserlist()), SLOT(hide()));
217
218 if (conf->mainwinRect().isValid())
219 setGeometry(conf->mainwinRect());
220 else
221 {
222 QSize newSize = myUserView->sizeHint();
223 if (newSize.width() > newSize.height())
224 newSize.transpose();
225 myUserView->resize(newSize);
226 adjustSize();
227 }
228 updateSkin();
229 connect(Config::Skin::active(), SIGNAL(changed()), SLOT(updateSkin()));
230 connect(Config::General::instance(), SIGNAL(styleChanged()), SLOT(updateSkin()));
231
232 updateGroups(true);
233
234 setMiniMode(conf->miniMode());
235 if(!conf->mainwinStartHidden() && !bStartHidden)
236 {
237 setVisible(true);
238 raise();
239 }
240
241 // verify we exist
242 if (Licq::gUserManager.NumOwners() == 0)
243 OwnerManagerDlg::showOwnerManagerDlg();
244
245 updateStatus();
246
247 // Check if MainWin should be sticky
248 if (Config::General::instance()->mainwinSticky())
249 setMainwinSticky(true);
250 }
251
~MainWindow()252 MainWindow::~MainWindow()
253 {
254 delete myUserView;
255
256 gMainWindow = NULL;
257 }
258
updateConfig()259 void MainWindow::updateConfig()
260 {
261 Config::General* generalConfig = Config::General::instance();
262
263 setMainwinSticky(generalConfig->mainwinSticky());
264 setMiniMode(generalConfig->miniMode());
265
266 // Redraw group/event label with new settings
267 updateEvents();
268 }
269
updateShortcuts()270 void MainWindow::updateShortcuts()
271 {
272 Config::Shortcuts* shortcuts = Config::Shortcuts::instance();
273
274 myViewEventAction->setShortcut(shortcuts->getShortcut(Config::Shortcuts::MainwinUserViewMessage));
275 mySendMessageAction->setShortcut(shortcuts->getShortcut(Config::Shortcuts::MainwinUserSendMessage));
276 mySendUrlAction->setShortcut(shortcuts->getShortcut(Config::Shortcuts::MainwinUserSendUrl));
277 mySendFileAction->setShortcut(shortcuts->getShortcut(Config::Shortcuts::MainwinUserSendFile));
278 mySendChatRequestAction->setShortcut(shortcuts->getShortcut(Config::Shortcuts::MainwinUserSendChatRequest));
279 myCheckUserArAction->setShortcut(shortcuts->getShortcut(Config::Shortcuts::MainwinUserCheckAutoresponse));
280 myViewHistoryAction->setShortcut(shortcuts->getShortcut(Config::Shortcuts::MainwinUserViewHistory));
281 }
282
trayIconClicked()283 void MainWindow::trayIconClicked()
284 {
285 if (isVisible() && !isMinimized() && isActiveWindow())
286 hide();
287 else
288 unhide();
289 }
290
unhide()291 void MainWindow::unhide()
292 {
293 show();
294 #ifdef USE_KDE
295 KWindowSystem::setOnDesktop(winId(), KWindowSystem::currentDesktop());
296 #endif
297 if (isMaximized())
298 showMaximized();
299 else
300 showNormal();
301
302 // Sticky state is lost when window is hidden so restore it now
303 if (Config::General::instance()->mainwinSticky())
304 setMainwinSticky(true);
305
306 activateWindow();
307 raise();
308 }
309
updateSkin()310 void MainWindow::updateSkin()
311 {
312 Config::Skin* skin = Config::Skin::active();
313
314 #define CLEAR(elem) \
315 if ((elem) != NULL) \
316 { \
317 delete (elem); \
318 (elem) = NULL; \
319 }
320
321 // Set the background pixmap and mask
322 if (skin->frame.pixmap.isNull())
323 setPalette(QPalette());
324
325 if (skin->frame.mask.isNull())
326 clearMask();
327
328 // System Button
329 CLEAR(mySystemButton);
330 CLEAR(myMenuBar);
331
332 if (skin->frame.hasMenuBar ||
333 skin->btnSys.rect.isNull())
334 {
335 #ifdef USE_KDE
336 myMenuBar = new KMenuBar(this);
337 #else
338 myMenuBar = new QMenuBar(this);
339 #endif
340 mySystemMenu->setTitle(skin->btnSys.caption.isNull() ?
341 tr("&System") : skin->btnSys.caption);
342 myMenuBar->addMenu(mySystemMenu);
343 myMenuBar->setMinimumWidth(mySystemMenu->width());
344 myMenuBar->show();
345 #ifndef Q_WS_MAC
346 skin->AdjustForMenuBar(myMenuBar->height());
347 #endif
348 }
349 else
350 {
351 mySystemButton = new SkinnableButton(skin->btnSys, tr("System"), this);
352 mySystemButton->setMenu(mySystemMenu);
353 mySystemButton->show();
354 }
355
356 unsigned minHeight = skin->frame.border.top + skin->frame.border.bottom;
357 setMinimumHeight(minHeight);
358 setMaximumHeight(Config::General::instance()->miniMode() ?
359 minHeight : QWIDGETSIZE_MAX);
360
361 // Group Combo Box
362 myUserGroupsBox->applySkin(skin->cmbGroups);
363 myUserGroupsBox->setVisible(!skin->cmbGroups.rect.isNull());
364
365 // Message Label
366 CLEAR(myMessageField);
367 if (!skin->lblMsg.rect.isNull())
368 {
369 myMessageField = new SkinnableLabel(skin->lblMsg,
370 mySystemMenu->getGroupMenu(), this);
371 connect(myMessageField, SIGNAL(doubleClicked()),
372 gLicqGui, SLOT(showNextEvent()));
373 connect(myMessageField, SIGNAL(wheelDown()), SLOT(nextGroup()));
374 connect(myMessageField, SIGNAL(wheelUp()), SLOT(prevGroup()));
375 myMessageField->setToolTip(tr("Right click - User groups\n"
376 "Double click - Show next message"));
377 myMessageField->show();
378 }
379
380 // Status Label
381 CLEAR(myStatusField);
382 if (!skin->lblStatus.rect.isNull())
383 {
384 myStatusField = new SkinnableLabel(skin->lblStatus,
385 mySystemMenu->getStatusMenu(), this);
386 connect(myStatusField, SIGNAL(doubleClicked()), SLOT(showAwayMsgDlg()));
387 myStatusField->setToolTip(tr("Right click - Status menu\n"
388 "Double click - Set auto response"));
389 myStatusField->show();
390 }
391
392 #undef CLEAR
393
394 // update geometry and contents of the elements
395 resizeEvent(NULL);
396 updateEvents();
397 updateStatus();
398 }
399
CreateUserView()400 void MainWindow::CreateUserView()
401 {
402 myUserView = new UserView(gGuiContactList, this);
403 connect (myUserView, SIGNAL(userDoubleClicked(const Licq::UserId&)),
404 gLicqGui, SLOT(showDefaultEventDialog(const Licq::UserId&)));
405 }
406
resizeEvent(QResizeEvent *)407 void MainWindow::resizeEvent(QResizeEvent* /* e */)
408 {
409 Config::Skin* skin = Config::Skin::active();
410
411 myUserView->setGeometry(skin->frame.border.left, skin->frame.border.top,
412 width() - skin->frameWidth(), height() - skin->frameHeight());
413
414 // Resize the background pixmap and mask
415 QPixmap pixmap = skin->mainwinPixmap(width(), height());
416 if (!pixmap.isNull())
417 {
418 QPalette pal(palette());
419 pal.setBrush(backgroundRole(), pixmap);
420 setPalette(pal);
421 }
422 QPixmap mask = skin->mainwinMask(width(), height());
423 if (!mask.isNull())
424 setMask(mask);
425
426 #define UPDATE(wid, group) \
427 if ((wid) != NULL) \
428 (wid)->setGeometry(skin->group.borderToRect(this));
429
430 // Set geometry of our widgets
431 UPDATE(myUserGroupsBox, cmbGroups);
432 UPDATE(myMessageField, lblMsg);
433 UPDATE(myStatusField, lblStatus);
434 UPDATE(mySystemButton, btnSys)
435 else
436 myMenuBar->resize(contentsRect().width(), myMenuBar->height());
437
438 #undef UPDATE
439
440 if (isVisible())
441 saveGeometry();
442 }
443
saveGeometry()444 void MainWindow::saveGeometry()
445 {
446 Config::General* conf = Config::General::instance();
447 QRect geom = geometry();
448
449 // When first showing window, we may get a rect without frame which will be
450 // become wrong if used for a window with a frame
451 if (geom == frameGeometry())
452 return;
453
454 // For setGeometry to get it right we need position including frame but
455 // size without frame
456 geom.moveTo(frameGeometry().topLeft());
457
458 if (myInMiniMode)
459 geom.setHeight(conf->mainwinRect().height());
460
461 conf->setMainwinRect(geom);
462 }
463
moveEvent(QMoveEvent *)464 void MainWindow::moveEvent(QMoveEvent* /* e */)
465 {
466 saveGeometry();
467 }
468
closeEvent(QCloseEvent * e)469 void MainWindow::closeEvent(QCloseEvent* e)
470 {
471 e->ignore();
472
473 if (gLicqGui->dockIcon() != NULL)
474 hide();
475 else
476 slot_shutdown();
477 }
478
removeUserFromList()479 void MainWindow::removeUserFromList()
480 {
481 Licq::UserId userId = myUserView->currentUserId();
482
483 gLicqGui->removeUserFromList(userId, this);
484 }
485
removeUserFromGroup()486 void MainWindow::removeUserFromGroup()
487 {
488 int groupId = Config::ContactList::instance()->groupId();
489
490 // Removing "All users" is the same as removing user from the list
491 if (groupId == ContactListModel::MostUsersGroupId ||
492 groupId == ContactListModel::AllGroupsGroupId)
493 {
494 removeUserFromList();
495 return;
496 }
497
498 // Get currently selected user
499 Licq::UserId userId = myUserView->currentUserId();
500
501 gLicqGui->setUserInGroup(userId, groupId, false);
502 }
503
callUserFunction(QAction * action)504 void MainWindow::callUserFunction(QAction* action)
505 {
506 int index = action->data().toInt();
507 Licq::UserId userId = myUserView->currentUserId();
508
509 if (index == -1)
510 gLicqGui->showViewEventDialog(userId);
511 else
512 gLicqGui->showEventDialog(index, userId);
513 }
514
checkUserAutoResponse()515 void MainWindow::checkUserAutoResponse()
516 {
517 Licq::UserId userId = myUserView->currentUserId();
518 if (userId.isValid())
519 new ShowAwayMsgDlg(userId, true);
520 }
521
showUserHistory()522 void MainWindow::showUserHistory()
523 {
524 Licq::UserId userId = myUserView->currentUserId();
525 if (userId.isValid())
526 new HistoryDlg(userId);
527 }
528
hide()529 void MainWindow::hide()
530 {
531 if (gLicqGui->dockIcon() != NULL)
532 QWidget::hide();
533 }
534
mousePressEvent(QMouseEvent * m)535 void MainWindow::mousePressEvent(QMouseEvent* m)
536 {
537 myMouseX = m->x();
538 myMouseY = m->y();
539 }
540
541 /*! \brief Drags the mainwindow around
542 *
543 * If the appropriate option is set (EnableMainwinMouseMovement = 1)
544 * this drags the mainwindow around when moving the mouse and left
545 * button is pressed.
546 */
mouseMoveEvent(QMouseEvent * m)547 void MainWindow::mouseMoveEvent(QMouseEvent* m)
548 {
549 if (Config::General::instance()->mainwinDraggable() && (m->buttons() == Qt::LeftButton))
550 {
551 int deltaX = m->x() - myMouseX;
552 int deltaY = m->y() - myMouseY;
553 move(x() + deltaX, y() + deltaY);
554 }
555 }
556
slot_updatedUser(const Licq::UserId & userId,unsigned long subSignal,int argument)557 void MainWindow::slot_updatedUser(const Licq::UserId& userId, unsigned long subSignal, int argument)
558 {
559 switch(subSignal)
560 {
561 case Licq::PluginSignal::UserEvents:
562 {
563 // Skip all this if it was just an away message check
564 if (argument == 0)
565 break;
566
567 // Otherwise an event was added or removed
568 updateEvents();
569 // autoRaise if needed
570 if (Config::General::instance()->autoRaiseMainwin() &&
571 argument > 0)
572 raise();
573
574 // Fall through
575 }
576 case Licq::PluginSignal::UserStatus:
577 case Licq::PluginSignal::UserBasic: // for alias
578 case Licq::PluginSignal::UserSettings: // for online notify
579 case Licq::PluginSignal::UserSecurity:
580 case Licq::PluginSignal::UserTyping:
581 {
582 Licq::UserReadGuard u(userId);
583 if (!u.isLocked())
584 {
585 Licq::gLog.warning("MainWindow::slot_updatedUser(): Invalid user received: %s",
586 userId.toString().c_str());
587 break;
588 }
589
590 if (subSignal == Licq::PluginSignal::UserStatus &&
591 argument == 1 &&
592 Config::General::instance()->trayMsgOnlineNotify())
593 {
594 // User on notify list went online -> show popup at systray icon
595 if (gLicqGui->dockIcon() != NULL && u->OnlineNotify())
596 {
597 QString alias = QString::fromUtf8(u->getAlias().c_str());
598 QPixmap px = IconManager::instance()->iconForUser(*u);
599 gLicqGui->dockIcon()->popupMessage(alias, tr("is online"), px, 4000);
600 }
601 }
602
603 break;
604 }
605 }
606 }
607
slot_updatedList(unsigned long subSignal)608 void MainWindow::slot_updatedList(unsigned long subSignal)
609 {
610 switch(subSignal)
611 {
612 case Licq::PluginSignal::ListUserRemoved:
613 updateEvents();
614 break;
615 }
616 }
617
updateEvents()618 void MainWindow::updateEvents()
619 {
620 QString szCaption;
621 unsigned short nNumOwnerEvents = 0;
622
623 {
624 Licq::OwnerListGuard ownerList;
625 BOOST_FOREACH(const Licq::Owner* owner, **ownerList)
626 {
627 Licq::OwnerReadGuard o(owner);
628 nNumOwnerEvents += o->NewMessages();
629 }
630 }
631
632 unsigned short nNumUserEvents = Licq::User::getNumUserEvents() - nNumOwnerEvents;
633
634 if (myMessageField != NULL)
635 myMessageField->setBold(false);
636 QString s, l;
637
638 if (nNumOwnerEvents > 0)
639 {
640 s = tr("SysMsg");
641 l = tr("System Message");
642 if (Config::General::instance()->boldOnMsg() &&
643 myMessageField != NULL)
644 myMessageField->setBold(true);
645 szCaption = "* " + myCaption;
646 }
647 else if (nNumUserEvents > 0)
648 {
649 s = tr("%1 msg%2").arg(nNumUserEvents).arg(nNumUserEvents == 1 ? tr(" ") : tr("s"));
650 l = tr("%1 message%2").arg(nNumUserEvents).arg(nNumUserEvents == 1 ? tr(" ") : tr("s"));
651 if (Config::General::instance()->boldOnMsg() &&
652 myMessageField != NULL)
653 myMessageField->setBold(true);
654 szCaption = "* " + myCaption;
655 }
656 else
657 {
658 // Update the msg label if necessary
659 if (Config::General::instance()->showGroupIfNoMsg() && Licq::User::getNumUserEvents() == 0)
660 {
661 s = myUserGroupsBox->currentText();
662 l = myUserGroupsBox->currentText();
663 }
664 else
665 {
666 s = tr("No msgs");
667 l = tr("No messages");
668 }
669 szCaption = myCaption;
670 }
671
672 setWindowTitle(szCaption);
673 setWindowIconText(szCaption);
674
675 if (myMessageField != NULL)
676 {
677 if (myMessageField->fontMetrics().width(l) +
678 myMessageField->margin() > myMessageField->width())
679 myMessageField->setText(s);
680 else
681 myMessageField->setText(l);
682 myMessageField->update();
683 }
684
685 if (gLicqGui->dockIcon() != NULL)
686 gLicqGui->dockIcon()->updateIconMessages(nNumUserEvents, nNumOwnerEvents);
687 }
688
setCurrentGroup(int index)689 void MainWindow::setCurrentGroup(int index)
690 {
691 int groupId = myUserGroupsBox->itemData(index).toInt();
692
693 Config::ContactList::instance()->setGroup(groupId);
694 }
695
nextGroup()696 void MainWindow::nextGroup()
697 {
698 int curGroupId = Config::ContactList::instance()->groupId();
699 int groupId = 0;
700
701 // Threaded view is selected, set all users
702 if (curGroupId == ContactListModel::AllGroupsGroupId)
703 {
704 Config::ContactList::instance()->setGroup(ContactListModel::MostUsersGroupId);
705 return;
706 }
707
708 {
709 Licq::GroupListGuard groupList;
710 BOOST_FOREACH(Licq::Group *g, **groupList)
711 {
712 Licq::GroupReadGuard group(g);
713
714 // If current selection is all users, select first group in list
715 if (groupId == 0 && curGroupId == ContactListModel::MostUsersGroupId)
716 {
717 Config::ContactList::instance()->setGroup(group->id());
718 return;
719 }
720
721 // If previous group is selected, select current group
722 if (groupId != 0 && curGroupId == groupId)
723 {
724 Config::ContactList::instance()->setGroup(group->id());
725 return;
726 }
727
728 groupId = group->id();
729 }
730 }
731
732 // Last user group is currently selected, set first system group
733 if (groupId != 0 && curGroupId == groupId)
734 {
735 Config::ContactList::instance()->setGroup(ContactListModel::SystemGroupOffset + 0);
736 return;
737 }
738
739 // No users groups exist and current selection is all users, set first system group
740 if (groupId == 0 && curGroupId == ContactListModel::MostUsersGroupId)
741 {
742 Config::ContactList::instance()->setGroup(ContactListModel::SystemGroupOffset + 0);
743 return;
744 }
745
746 groupId = 0;
747
748 for (int i = ContactListModel::SystemGroupOffset; i <= ContactListModel::LastSystemGroup; ++i)
749 {
750 // If previous system group is selected, set current group
751 if (groupId != 0 && groupId == curGroupId)
752 {
753 Config::ContactList::instance()->setGroup(i);
754 return;
755 }
756 groupId = i;
757 }
758
759 // Last system group is currently selected or selection not found, set thread view
760 Config::ContactList::instance()->setGroup(ContactListModel::AllGroupsGroupId);
761 }
762
763
prevGroup()764 void MainWindow::prevGroup()
765 {
766 int curGroupId = Config::ContactList::instance()->groupId();
767 int groupId = 0;
768
769 // All users is selected, set thread view
770 if (curGroupId == ContactListModel::MostUsersGroupId)
771 {
772 Config::ContactList::instance()->setGroup(ContactListModel::AllGroupsGroupId);
773 return;
774 }
775
776 {
777 Licq::GroupListGuard groupList;
778 BOOST_FOREACH(Licq::Group* g, **groupList)
779 {
780 Licq::GroupReadGuard group(g);
781
782 // If current group is selected, set previous group
783 if (curGroupId == group->id())
784 {
785 if (groupId == 0)
786 Config::ContactList::instance()->setGroup(ContactListModel::MostUsersGroupId);
787 else
788 Config::ContactList::instance()->setGroup(groupId);
789 return;
790 }
791
792 groupId = group->id();
793 }
794 }
795
796 // If first system group is selected, set last user group
797 if (groupId != 0 && curGroupId == ContactListModel::SystemGroupOffset + 0)
798 {
799 if (groupId == 0)
800 Config::ContactList::instance()->setGroup(ContactListModel::MostUsersGroupId);
801 else
802 Config::ContactList::instance()->setGroup(groupId);
803 return;
804 }
805 groupId = 0;
806
807 for (int i = ContactListModel::SystemGroupOffset; i <= ContactListModel::LastSystemGroup; ++i)
808 {
809 // If current system group is selected, set previous group
810 if (curGroupId == i)
811 {
812 Config::ContactList::instance()->setGroup(groupId);
813 return;
814 }
815 groupId = i;
816 }
817
818 // If current selection is thread view or selection not found, set last system group
819 Config::ContactList::instance()->setGroup(ContactListModel::LastSystemGroup);
820 }
updateCurrentGroup()821 void MainWindow::updateCurrentGroup()
822 {
823 int groupId = Config::ContactList::instance()->groupId();
824
825 // Update the combo box
826 int index = myUserGroupsBox->findData(groupId);
827 if (index == -1)
828 return;
829 myUserGroupsBox->setCurrentIndex(index);
830
831 // Update the msg label if necessary
832 if (myMessageField != NULL &&
833 Config::General::instance()->showGroupIfNoMsg() &&
834 Licq::User::getNumUserEvents() == 0)
835 myMessageField->setText(myUserGroupsBox->currentText());
836 }
837
updateGroups(bool initial)838 void MainWindow::updateGroups(bool initial)
839 {
840 if (!initial)
841 {
842 // update group list in user and system menus
843 mySystemMenu->updateGroups();
844 }
845
846 // update the combo box
847 myUserGroupsBox->clear();
848
849 #define ADD_SYSTEMGROUP(groupId) \
850 myUserGroupsBox->addItem(ContactListModel::systemGroupName(groupId), groupId);
851
852 ADD_SYSTEMGROUP(ContactListModel::AllGroupsGroupId);
853 ADD_SYSTEMGROUP(ContactListModel::MostUsersGroupId);
854
855 {
856 Licq::GroupListGuard groupList(true);
857 BOOST_FOREACH(const Licq::Group* group, **groupList)
858 {
859 Licq::GroupReadGuard pGroup(group);
860 myUserGroupsBox->addItem(QString::fromLocal8Bit(pGroup->name().c_str()), pGroup->id());
861 }
862 }
863
864 for (int i = ContactListModel::SystemGroupOffset; i <= ContactListModel::LastSystemGroup; i++)
865 {
866 ADD_SYSTEMGROUP(i);
867 }
868
869 #undef ADD_SYSTEMGROUP
870
871 updateCurrentGroup();
872 }
873
updateStatus()874 void MainWindow::updateStatus()
875 {
876 if (gLicqGui->dockIcon() != NULL)
877 gLicqGui->dockIcon()->updateIconStatus();
878
879 if (myStatusField == NULL)
880 return;
881
882 IconManager* iconman = IconManager::instance();
883 Config::Skin* skin = Config::Skin::active();
884 QColor theColor = skin->offlineColor;
885
886 myStatusField->clearPixmaps();
887 myStatusField->clearPrependPixmap();
888 myStatusField->setText(QString::null);
889
890 {
891 Licq::OwnerListGuard ownerList;
892 Licq::OwnerList::const_iterator it = ownerList->begin();
893 switch (ownerList->size())
894 {
895 case 0:
896 break;
897 case 1:
898 {
899 Licq::OwnerReadGuard o(*it);
900 myStatusField->setText(Licq::User::statusToString(o->status()).c_str());
901 myStatusField->setPrependPixmap(iconman->iconForUser(*o));
902 if (o->status() == Licq::User::OfflineStatus)
903 theColor = skin->offlineColor;
904 else if (o->status() & Licq::User::AwayStatuses)
905 theColor = skin->awayColor;
906 else
907 theColor = skin->onlineColor;
908 break;
909 }
910 default:
911 BOOST_FOREACH(Licq::Owner* owner, **ownerList)
912 {
913 Licq::OwnerReadGuard o(owner);
914 myStatusField->addPixmap(iconman->iconForUser(*o));
915 }
916 }
917 }
918
919 myStatusField->update();
920
921 // set the color if it isn't set by the skin
922 if (!skin->lblStatus.foreground.isValid() && theColor.isValid())
923 {
924 QPalette pal(myStatusField->palette());
925 pal.setColor(QPalette::WindowText, theColor);
926 myStatusField->setPalette(pal);
927 }
928 }
929
showAwayMsgDlg()930 void MainWindow::showAwayMsgDlg()
931 {
932 // Find an owner that can hold a status message
933 // If multiple exist, get the worst status (e.g. most away)
934 unsigned status = Licq::User::OfflineStatus;
935 {
936 Licq::OwnerListGuard ownerList;
937 BOOST_FOREACH(const Licq::Owner* owner, **ownerList)
938 {
939 Licq::OwnerReadGuard o(owner);
940 if ((o->protocolCapabilities() & Licq::ProtocolPlugin::CanHoldStatusMsg) == 0)
941 continue;
942
943 if (o->status() > status)
944 status = o->status();
945 }
946 }
947
948 // If no owner supports status message or all are offline, don't bother
949 if (status == Licq::User::OfflineStatus)
950 return;
951
952 AwayMsgDlg::showAwayMsgDlg(status);
953 }
954
slot_shutdown()955 void MainWindow::slot_shutdown()
956 {
957 Licq::gDaemon.Shutdown();
958 }
959
slot_logon()960 void MainWindow::slot_logon()
961 {
962 updateStatus();
963 }
964
showAboutBox()965 void MainWindow::showAboutBox()
966 {
967 new AboutDlg(this);
968 }
969
showStats()970 void MainWindow::showStats()
971 {
972 new StatsDlg(this);
973 }
974
setMiniMode(bool miniMode)975 void MainWindow::setMiniMode(bool miniMode)
976 {
977 if (miniMode == myInMiniMode)
978 return;
979
980 myInMiniMode = miniMode;
981
982 if (miniMode)
983 setMaximumHeight(minimumHeight());
984 else
985 {
986 setMaximumHeight(QWIDGETSIZE_MAX);
987 resize(width(), Config::General::instance()->mainwinRect().height());
988 }
989
990 if (myUserView != NULL)
991 myUserView->setVisible(!miniMode);
992 }
993
showHints()994 void MainWindow::showHints()
995 {
996 QString hints = tr(
997 "<h2>Hints for Using<br>the Licq %1 Plugin</h2><hr>"
998 "<ul>"
999 "<li>Change your status by right clicking on the status label.</li>"
1000 "<li>Change your auto response by double-clicking on the status label.</li>"
1001 "<li>View system messages by double clicking on the message label.</li>"
1002 "<li>Change groups by right clicking on the message label.</li>"
1003 "<li>Hold control while clicking on close in the function window to remove"
1004 " the user from your contact list.</li>"
1005 "<li>Hit Ctrl-Enter from most text entry fields to select \"Ok\" or \"Accept\"."
1006 " For example in the send tab of the user function window.</li>"
1007 "<li>Here is the complete list of user % options, which can be used in <b>OnEvent</b>"
1008 " parameters and <b>auto responses</b>:")
1009 .arg(DISPLAY_PLUGIN_NAME) +
1010 gMainWindow->usprintfHelp +
1011 "</li></ul><hr>" +
1012 #ifndef USE_KDE
1013 "<h2>" + tr("Qt URL handling") + "</h2>"
1014 "<center><table border=1 cellpadding=5>"
1015 "<tr><th colspan=2>Web</th><th colspan=2>E-mail (mailto:)</th></tr>"
1016 "<tr><th>KDE</th><th>GNOME</th><th>GNOME</th><th>KDE</th></tr>"
1017 "<tr><td align=center colspan=4>xdg-open</td></tr>"
1018 "<tr><td align=center colspan=2>$DEFAULT_BROWSER</td>"
1019 "<td colspan=2 rowspan=2> </td></tr>"
1020 "<tr><td align=center colspan=2>$BROWSER</td></tr>"
1021 "<tr><td align=center>kfmclient openURL</td>"
1022 "<td align=center colspan=2>gnome-open</td>"
1023 "<td align=center>kfmclient exec</td></tr>"
1024 "<tr><td align=center colspan=4>firefox</td></tr>"
1025 "<tr><td align=center colspan=4>mozilla</td></tr>"
1026 "<tr><td align=center colspan=4>netscape</td></tr>"
1027 "<tr><td align=center colspan=4>opera</td></tr>"
1028 "</table></center><hr>" +
1029 #endif
1030 tr("<p>For more information, see the Licq webpage (<tt>http://www.licq.org</tt>).</p>");
1031
1032 new HintsDlg(hints);
1033 }
1034
showAutoResponseHints(QWidget * parent)1035 void MainWindow::showAutoResponseHints(QWidget* parent)
1036 {
1037 AwayMsgDlg::showAutoResponseHints(parent);
1038 }
1039
addUser(const Licq::UserId & userId)1040 void MainWindow::addUser(const Licq::UserId& userId)
1041 {
1042 if (!userId.isValid())
1043 return;
1044
1045 new AddUserDlg(userId);
1046 }
1047
setMainwinSticky(bool sticky)1048 void MainWindow::setMainwinSticky(bool sticky)
1049 {
1050 Support::changeWinSticky(winId(), sticky);
1051 }
1052