1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 2000-2012 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 "usereventtabdlg.h"
21
22 #include "config.h"
23
24 #include <licq/contactlist/user.h>
25 #include <licq/userevents.h>
26
27 #include <QAction>
28 #include <QActionGroup>
29 #include <QTimer>
30 #include <QVBoxLayout>
31
32 #ifdef USE_KDE
33 #include <KDE/KWindowSystem>
34 #endif
35
36 #include "config/chat.h"
37 #include "config/iconmanager.h"
38 #include "config/shortcuts.h"
39
40 #include "helpers/support.h"
41
42 #include "widgets/tabwidget.h"
43
44 #include "usereventcommon.h"
45 #include "usersendevent.h"
46
47 using namespace LicqQtGui;
48 /* TRANSLATOR LicqQtGui::UserEventTabDlg */
49
50 using std::list;
51 using std::string;
52
UserEventTabDlg(QWidget * parent,const char * name)53 UserEventTabDlg::UserEventTabDlg(QWidget* parent, const char* name)
54 : QWidget(parent)
55 {
56 Support::setWidgetProps(this, name);
57 setAttribute(Qt::WA_DeleteOnClose, true);
58
59 QVBoxLayout* lay = new QVBoxLayout(this);
60 lay->setContentsMargins(0, 0, 0, 0);
61
62 if (Config::Chat::instance()->tabDialogRect().isValid())
63 setGeometry(Config::Chat::instance()->tabDialogRect());
64
65 myTabs = new TabWidget();
66 lay->addWidget(myTabs);
67
68 connect(myTabs, SIGNAL(currentChanged(int)), SLOT(currentChanged(int)));
69 connect(myTabs, SIGNAL(mouseMiddleClick(QWidget*)), SLOT(removeTab(QWidget*)));
70
71 QActionGroup* tabActionGroup = new QActionGroup(this);
72 connect(tabActionGroup, SIGNAL(triggered(QAction*)), SLOT(switchTab(QAction*)));
73
74 #define ADD_TABSHORTCUT(var, shortcut, index) \
75 var = new QAction(tabActionGroup); \
76 var->setData(index);
77
78 ADD_TABSHORTCUT(myTabSwitch01Action, Config::Shortcuts::ChatTab01, 0);
79 ADD_TABSHORTCUT(myTabSwitch02Action, Config::Shortcuts::ChatTab02, 1);
80 ADD_TABSHORTCUT(myTabSwitch03Action, Config::Shortcuts::ChatTab03, 2);
81 ADD_TABSHORTCUT(myTabSwitch04Action, Config::Shortcuts::ChatTab04, 3);
82 ADD_TABSHORTCUT(myTabSwitch05Action, Config::Shortcuts::ChatTab05, 4);
83 ADD_TABSHORTCUT(myTabSwitch06Action, Config::Shortcuts::ChatTab06, 5);
84 ADD_TABSHORTCUT(myTabSwitch07Action, Config::Shortcuts::ChatTab07, 6);
85 ADD_TABSHORTCUT(myTabSwitch08Action, Config::Shortcuts::ChatTab08, 7);
86 ADD_TABSHORTCUT(myTabSwitch09Action, Config::Shortcuts::ChatTab09, 8);
87 ADD_TABSHORTCUT(myTabSwitch10Action, Config::Shortcuts::ChatTab10, 9);
88
89 #undef ADD_TABSHORTCUT
90
91 addActions(tabActionGroup->actions());
92 updateShortcuts();
93 connect(Config::Shortcuts::instance(), SIGNAL(shortcutsChanged()), SLOT(updateShortcuts()));
94 }
95
updateShortcuts()96 void UserEventTabDlg::updateShortcuts()
97 {
98 const Config::Shortcuts* shortcuts = Config::Shortcuts::instance();
99 myTabSwitch01Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab01));
100 myTabSwitch02Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab02));
101 myTabSwitch03Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab03));
102 myTabSwitch04Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab04));
103 myTabSwitch05Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab05));
104 myTabSwitch06Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab06));
105 myTabSwitch07Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab07));
106 myTabSwitch08Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab08));
107 myTabSwitch09Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab09));
108 myTabSwitch10Action->setShortcut(shortcuts->getShortcut(Config::Shortcuts::ChatTab10));
109 }
110
~UserEventTabDlg()111 UserEventTabDlg::~UserEventTabDlg()
112 {
113 saveGeometry();
114 emit signal_done();
115 }
116
addTab(UserEventCommon * tab,int index)117 void UserEventTabDlg::addTab(UserEventCommon* tab, int index)
118 {
119 // Insert tab before we lock the user as our event() function will be called
120 // when tab is inserted and will also need to fetch user.
121 // Tab label will be set later by updateTabLabel()
122 myTabs->insertTab(index, tab, QString());
123
124 Licq::UserReadGuard u(tab->userId());
125 if (!u.isLocked())
126 return;
127
128 updateTabLabel(tab, *u);
129 }
130
switchTab(QAction * action)131 void UserEventTabDlg::switchTab(QAction* action)
132 {
133 int index = action->data().toInt();
134
135 myTabs->setCurrentIndex(index);
136 }
137
selectTab(QWidget * tab)138 void UserEventTabDlg::selectTab(QWidget* tab)
139 {
140 myTabs->setCurrentIndex(myTabs->indexOf(tab));
141 updateTitle(tab);
142 }
143
replaceTab(QWidget * oldTab,UserEventCommon * newTab)144 void UserEventTabDlg::replaceTab(QWidget* oldTab, UserEventCommon* newTab)
145 {
146 addTab(newTab, myTabs->indexOf(oldTab) + 1);
147 removeTab(oldTab);
148 }
149
tabIsSelected(QWidget * tab)150 bool UserEventTabDlg::tabIsSelected(QWidget* tab)
151 {
152 return (myTabs->currentIndex() == myTabs->indexOf(tab));
153 }
154
tabExists(QWidget * tab)155 bool UserEventTabDlg::tabExists(QWidget* tab)
156 {
157 return (myTabs->indexOf(tab) != -1);
158 }
159
updateConvoLabel(UserEventCommon * tab)160 void UserEventTabDlg::updateConvoLabel(UserEventCommon* tab)
161 {
162 // Show the list of users in the conversation
163 list<Licq::UserId> users = tab->convoUsers();
164 list<Licq::UserId>::iterator it;
165 QString newLabel = QString::null;
166
167 for (it = users.begin(); it != users.end(); ++it)
168 {
169 if (!newLabel.isEmpty())
170 newLabel += ", ";
171
172 Licq::UserReadGuard u(*it);
173 if (!u.isLocked())
174 newLabel += tr("[UNKNOWN_USER]");
175 else
176 newLabel += QString::fromUtf8(u->getAlias().c_str());
177 }
178
179 myTabs->setTabText(myTabs->indexOf(tab), newLabel);
180 }
181
updateTabLabel(const Licq::User * u)182 void UserEventTabDlg::updateTabLabel(const Licq::User* u)
183 {
184 if (u == NULL)
185 return;
186
187 for (int index = 0; index < myTabs->count(); index++)
188 {
189 UserEventCommon* tab = dynamic_cast<UserEventCommon*>(myTabs->widget(index));
190
191 if (tab->isUserInConvo(u->id()))
192 updateTabLabel(tab, u);
193 }
194 }
195
updateTabLabel(UserEventCommon * tab,const Licq::User * u)196 void UserEventTabDlg::updateTabLabel(UserEventCommon* tab, const Licq::User* u)
197 {
198 if (tab == NULL)
199 return;
200
201 int index = myTabs->indexOf(tab);
202 myTabs->setTabText(index, QString::fromUtf8(u->getAlias().c_str()));
203
204 QIcon icon;
205
206 if (u->NewMessages() > 0) // use an event icon
207 {
208 unsigned eventType = Licq::UserEvent::TypeMessage;
209 for (unsigned short i = 0; i < u->NewMessages(); i++)
210 switch (u->EventPeek(i)->eventType())
211 {
212 case Licq::UserEvent::TypeFile:
213 eventType = Licq::UserEvent::TypeFile;
214 break;
215 case Licq::UserEvent::TypeChat:
216 if (eventType != Licq::UserEvent::TypeFile)
217 eventType = Licq::UserEvent::TypeChat;
218 break;
219 case Licq::UserEvent::TypeUrl:
220 if (eventType != Licq::UserEvent::TypeFile &&
221 eventType != Licq::UserEvent::TypeChat)
222 eventType = Licq::UserEvent::TypeUrl;
223 break;
224 case Licq::UserEvent::TypeContactList:
225 if (eventType != Licq::UserEvent::TypeFile &&
226 eventType != Licq::UserEvent::TypeChat &&
227 eventType != Licq::UserEvent::TypeUrl)
228 eventType = Licq::UserEvent::TypeContactList;
229 break;
230 }
231
232 icon = IconManager::instance()->iconForEvent(eventType);
233 myTabs->setTabColor(tab, QColor("blue"));
234
235 // to clear it..
236 tab->setTyping(u->isTyping());
237 }
238 else // use status icon
239 {
240 icon = IconManager::instance()->iconForUser(u);
241
242 if (u->isTyping())
243 myTabs->setTabColor(tab, Config::Chat::instance()->tabTypingColor());
244 else
245 myTabs->setTabColor(tab, QColor());
246 }
247
248 myTabs->setTabIcon(index, icon);
249 if (myTabs->currentIndex() == index)
250 setWindowIcon(icon);
251 }
252
setTyping(const Licq::User * u,int convoId)253 void UserEventTabDlg::setTyping(const Licq::User* u, int convoId)
254 {
255 for (int index = 0; index < myTabs->count(); index++)
256 {
257 UserEventCommon* tab = dynamic_cast<UserEventCommon*>(myTabs->widget(index));
258
259 if (tab->convoId() == static_cast<unsigned long>(convoId) &&
260 tab->isUserInConvo(u->id()))
261 tab->setTyping(u->isTyping());
262 }
263 }
264
265 #ifdef USE_KDE
266 /* KDE 3.2 handles app-icon updates differently, since KDE 3.2 a simple setIcon() call
267 does no longer update the icon in kicker anymore :(
268 So we do it the "kde-way" here */
setIcon(const QPixmap & icon)269 void UserEventTabDlg::setIcon(const QPixmap& icon)
270 {
271 KWindowSystem::setIcons(winId(), icon, icon);
272 }
273 #endif
274
275 /*! This slot should get called when the current tab has
276 * changed.
277 */
currentChanged(int index)278 void UserEventTabDlg::currentChanged(int index)
279 {
280 QWidget* tab = myTabs->widget(index);
281 tab->setFocus(); // prevents users from accidentally typing in the wrong widget
282 updateTitle(tab);
283 clearEvents(tab);
284 }
285
moveLeft()286 void UserEventTabDlg::moveLeft()
287 {
288 myTabs->setPreviousPage();
289 }
290
moveRight()291 void UserEventTabDlg::moveRight()
292 {
293 myTabs->setNextPage();
294 }
295
removeTab(QWidget * tab)296 void UserEventTabDlg::removeTab(QWidget* tab)
297 {
298 if (myTabs->count() > 1)
299 {
300 int index = myTabs->indexOf(tab);
301 myTabs->removeTab(index);
302 tab->close();
303 tab->setEnabled(false);
304 tab->deleteLater();
305 }
306 else
307 close();
308 }
309
setMsgWinSticky(bool sticky)310 void UserEventTabDlg::setMsgWinSticky(bool sticky)
311 {
312 Support::changeWinSticky(winId(), sticky);
313 }
314
updateTitle(QWidget * tab)315 void UserEventTabDlg::updateTitle(QWidget* tab)
316 {
317 QString title = tab->windowTitle();
318 if (!title.isEmpty())
319 setWindowTitle(title);
320
321 setWindowIconText(tab->windowIconText());
322
323 QIcon icon = myTabs->tabIcon(myTabs->indexOf(tab));
324 if (!icon.isNull())
325 setWindowIcon(icon);
326 }
327
clearEvents(QWidget * tab)328 void UserEventTabDlg::clearEvents(QWidget* tab)
329 {
330 if (!isActiveWindow())
331 return;
332
333 UserSendEvent* e = dynamic_cast<UserSendEvent*>(tab);
334 QTimer::singleShot(e->clearDelay, e, SLOT(clearNewEvents()));
335 }
336
saveGeometry()337 void UserEventTabDlg::saveGeometry()
338 {
339 QRect geom = geometry();
340
341 // When first showing window, we may get a rect without frame which will be
342 // become wrong if used for a window with a frame
343 if (geom == frameGeometry())
344 return;
345
346 // For setGeometry to get it right we need position including frame but
347 // size without frame
348 geom.moveTo(frameGeometry().topLeft());
349
350 Config::Chat::instance()->setTabDialogRect(geom);
351 }
352
moveEvent(QMoveEvent * event)353 void UserEventTabDlg::moveEvent(QMoveEvent* event)
354 {
355 saveGeometry();
356 QWidget::moveEvent(event);
357 }
358
resizeEvent(QResizeEvent * event)359 void UserEventTabDlg::resizeEvent(QResizeEvent* event)
360 {
361 saveGeometry();
362 QWidget::resizeEvent(event);
363 }
364