1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 2000-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 "userviewevent.h"
21
22 #include "config.h"
23
24 #include <QAction>
25 #include <QApplication>
26 #include <QCheckBox>
27 #include <QDesktopWidget>
28 #include <QFile>
29 #include <QGroupBox>
30 #include <QPushButton>
31 #include <QShortcut>
32 #include <QSplitter>
33 #include <QTreeWidgetItem>
34 #include <QVBoxLayout>
35
36 #ifdef USE_KDE
37 #include <KDE/KToolInvocation>
38 #endif
39
40 #include <licq/contactlist/usermanager.h>
41 #include <licq/daemon.h>
42 #include <licq/event.h>
43 #include <licq/icq/icq.h>
44 #include <licq/plugin/pluginmanager.h>
45 #include <licq/pluginsignal.h>
46 #include <licq/protocolmanager.h>
47 #include <licq/userevents.h>
48
49 #include "config/chat.h"
50 #include "config/iconmanager.h"
51
52 #include "core/gui-defines.h"
53 #include "core/licqgui.h"
54 #include "core/messagebox.h"
55 #include "core/signalmanager.h"
56
57 #include "dialogs/adduserdlg.h"
58 #include "dialogs/authdlg.h"
59 #include "dialogs/chatdlg.h"
60 #include "dialogs/filedlg.h"
61 #include "dialogs/forwarddlg.h"
62 #include "dialogs/joinchatdlg.h"
63 #include "dialogs/refusedlg.h"
64 #include "userdlg/userdlg.h"
65
66 #include "widgets/messagelist.h"
67 #include "widgets/mlview.h"
68 #include "widgets/skinnablebutton.h"
69
70 #include "usersendevent.h"
71
72 using Licq::gProtocolManager;
73 using namespace LicqQtGui;
74 /* TRANSLATOR LicqQtGui::UserViewEvent */
75
UserViewEvent(const Licq::UserId & userId,QWidget * parent)76 UserViewEvent::UserViewEvent(const Licq::UserId& userId, QWidget* parent)
77 : UserEventCommon(userId, parent, "UserViewEvent")
78 {
79 myReadSplitter = new QSplitter(Qt::Vertical);
80 myReadSplitter->setOpaqueResize();
81 myMainWidget->addWidget(myReadSplitter);
82
83 QShortcut* shortcutEscape = new QShortcut(Qt::Key_Escape, this);
84
85 myMessageList = new MessageList();
86 myReadSplitter->addWidget(myMessageList);
87
88 myMessageView = new MLView();
89 myMessageView->setSizeHintLines(8);
90 myReadSplitter->addWidget(myMessageView);
91
92 myReadSplitter->setStretchFactor(0, 0);
93 myReadSplitter->setStretchFactor(1, 1);
94
95 myActionsBox = new QGroupBox();
96 myMainWidget->addSpacing(10);
97 myMainWidget->addWidget(myActionsBox);
98
99 QHBoxLayout* h_action_lay = new QHBoxLayout(myActionsBox);
100
101 myRead1Button = new QPushButton();
102 myRead2Button = new QPushButton();
103 myRead3Button = new QPushButton();
104 myRead4Button = new QPushButton();
105
106 myRead1Button->setEnabled(false);
107 myRead2Button->setEnabled(false);
108 myRead3Button->setEnabled(false);
109 myRead4Button->setEnabled(false);
110
111 h_action_lay->addWidget(myRead1Button);
112 h_action_lay->addWidget(myRead2Button);
113 h_action_lay->addWidget(myRead3Button);
114 h_action_lay->addWidget(myRead4Button);
115
116 QHBoxLayout* h_lay = new QHBoxLayout();
117 myTopLayout->addLayout(h_lay);
118
119 if (!myIsOwner)
120 {
121 myAutoCloseCheck = new QCheckBox(tr("Aut&o Close"));
122 myAutoCloseCheck->setChecked(Config::Chat::instance()->autoClose());
123 h_lay->addWidget(myAutoCloseCheck);
124 }
125
126 h_lay->addStretch(1);
127
128 myReadNextButton = new QPushButton(tr("Nex&t"));
129 myReadNextButton->setEnabled(false);
130 h_lay->addWidget(myReadNextButton);
131 setTabOrder(myRead4Button, myReadNextButton);
132
133 myCloseButton = new SkinnableButton(tr("&Close"));
134 myCloseButton->setToolTip(tr("Normal Click - Close Window\n<CTRL>+Click - also delete User"));
135 h_lay->addWidget(myCloseButton);
136 setTabOrder(myReadNextButton, myCloseButton);
137
138 Licq::UserReadGuard u(myUsers.front());
139 if (u.isLocked() && u->NewMessages() > 0)
140 {
141 unsigned short i = 0;
142 // Create an item for the message we're currently viewing.
143 if (Config::Chat::instance()->msgChatView())
144 {
145 for (i = 0; i < u->NewMessages(); i++)
146 if (u->EventPeek(i)->eventType() != Licq::UserEvent::TypeMessage &&
147 u->EventPeek(i)->eventType() != Licq::UserEvent::TypeUrl)
148 break;
149 if (i == u->NewMessages())
150 i = 0;
151 }
152
153 MessageListItem* e = new MessageListItem(u->EventPeek(i), myMessageList);
154 myHighestEventId = u->EventPeek(i)->Id();
155
156 /* Create items for all the messages which already await
157 * in the queue. We cannot rely on getting CICQSignals for them
158 * since they might've arrived before the dialog appeared,
159 * possibly being undisplayed messages from previous licq session.
160 */
161 for (i++; i < u->NewMessages(); i++)
162 {
163 const Licq::UserEvent* event = u->EventPeek(i);
164 if (!Config::Chat::instance()->msgChatView() ||
165 (event->eventType() != Licq::UserEvent::TypeMessage &&
166 event->eventType() != Licq::UserEvent::TypeUrl))
167 {
168 new MessageListItem(event, myMessageList);
169 // Make sure we don't add this message again,
170 // even if we receive an userUpdated signal for it.
171 if (myHighestEventId < event->Id())
172 myHighestEventId = event->Id();
173 }
174 }
175
176 u.unlock();
177 for (int i = 0; i < myMessageList->columnCount(); i++)
178 myMessageList->resizeColumnToContents(i);
179 myMessageList->setCurrentItem(e, 0);
180 myMessageList->scrollToItem(e);
181 printMessage(e);
182 }
183 u.unlock();
184
185 QSize dialogSize = Config::Chat::instance()->viewDialogSize();
186 if (dialogSize.isValid())
187 resize(dialogSize);
188
189 connect(gLicqGui, SIGNAL(eventSent(const Licq::Event*)),
190 SLOT(sentEvent(const Licq::Event*)));
191 connect(myMessageList, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
192 SLOT(printMessage(QTreeWidgetItem*)));
193 connect(myRead1Button, SIGNAL(clicked()), SLOT(read1()));
194 connect(myRead2Button, SIGNAL(clicked()), SLOT(read2()));
195 connect(myRead3Button, SIGNAL(clicked()), SLOT(read3()));
196 connect(myRead4Button, SIGNAL(clicked()), SLOT(read4()));
197 connect(myReadNextButton, SIGNAL(clicked()), SLOT(readNext()));
198 connect(myCloseButton, SIGNAL(clicked()), SLOT(closeDialog()));
199 connect(shortcutEscape, SIGNAL(activated()), SLOT(closeDialog()));
200 connect(this, SIGNAL(encodingChanged()), SLOT(setEncoding()));
201 }
202
~UserViewEvent()203 UserViewEvent::~UserViewEvent()
204 {
205 // Empty
206 }
207
generateReply()208 void UserViewEvent::generateReply()
209 {
210 QString s = QString("> ");
211
212 if (!myMessageView->markedText().trimmed().isEmpty())
213 s += myMessageView->markedText().trimmed();
214 else
215 if (!myMessageView->toPlainText().trimmed().isEmpty())
216 s += myMessageView->toPlainText().trimmed();
217 else
218 s = QString::null;
219
220 s.replace("\n", "\n> ");
221 s = s.trimmed();
222 if (!s.isEmpty())
223 s += "\n\n";
224
225 sendMsg(s);
226 }
227
sendMsg(QString text)228 void UserViewEvent::sendMsg(QString text)
229 {
230 UserSendEvent* e = new UserSendEvent(MessageEvent, myUsers.front());
231
232 e->setText(text);
233
234 // Find a good position for the new window
235 if (Config::Chat::instance()->autoPosReplyWin())
236 {
237 int yp = myRead1Button->parentWidget()->mapToGlobal(QPoint(0, 0)).y();
238 if (yp + e->height() + 8 > QApplication::desktop()->height())
239 yp = QApplication::desktop()->height() - e->height() - 8;
240 e->move(x(), yp);
241 }
242
243 QTimer::singleShot(10, e, SLOT(show()));
244
245 connect(e, SIGNAL(autoCloseNotify()), SLOT(autoClose()));
246 }
247
updateNextButton()248 void UserViewEvent::updateNextButton()
249 {
250 int num = myMessageList->getNumUnread();
251 MessageListItem* e = myMessageList->getNextUnread();
252
253 myReadNextButton->setEnabled(num > 0);
254
255 if (num > 1)
256 myReadNextButton->setText(tr("Nex&t (%1)").arg(num));
257 else if (num == 1)
258 myReadNextButton->setText(tr("Nex&t"));
259
260 if (e != NULL && e->msg() != NULL)
261 myReadNextButton->setIcon(IconManager::instance()->iconForEvent(e->msg()->eventType()));
262 else
263 myReadNextButton->setIcon(QIcon());
264 }
265
userUpdated(const Licq::UserId & userId,unsigned long subSignal,int argument,unsigned long)266 void UserViewEvent::userUpdated(const Licq::UserId& userId, unsigned long subSignal, int argument, unsigned long /* cid */)
267 {
268 Licq::UserReadGuard u(userId);
269
270 if (!u.isLocked())
271 return;
272
273 if (subSignal == Licq::PluginSignal::UserEvents)
274 {
275 if (argument > 0)
276 {
277 int eventId = argument;
278 const Licq::UserEvent* e = u->EventPeekId(eventId);
279 // Making sure we didn't handle this message already.
280 if (e != NULL && myHighestEventId < eventId &&
281 (!Config::Chat::instance()->msgChatView() ||
282 (e->eventType() != Licq::UserEvent::TypeMessage &&
283 e->eventType() != Licq::UserEvent::TypeUrl)))
284 {
285 myHighestEventId = eventId;
286 MessageListItem* m = new MessageListItem(e, myMessageList);
287 myMessageList->scrollToItem(m);
288 }
289 }
290
291 if (argument != 0)
292 updateNextButton();
293 }
294 }
295
autoClose()296 void UserViewEvent::autoClose()
297 {
298 if (!myAutoCloseCheck->isChecked())
299 return;
300
301 bool doclose = false;
302
303 {
304 Licq::UserReadGuard u(myUsers.front());
305 if (u.isLocked())
306 doclose = (u->NewMessages() == 0);
307 }
308
309 if (doclose)
310 closeDialog();
311 }
312
read1()313 void UserViewEvent::read1()
314 {
315 if (myCurrentEvent == 0)
316 return;
317
318 switch (myCurrentEvent->eventType())
319 {
320 case Licq::UserEvent::TypeMessage: // reply/quote
321 case Licq::UserEvent::TypeUrl:
322 case Licq::UserEvent::TypeChat:
323 case Licq::UserEvent::TypeFile:
324 sendMsg("");
325 break;
326
327 case Licq::UserEvent::TypeAuthRequest:
328 {
329 Licq::EventAuthRequest* p = dynamic_cast<Licq::EventAuthRequest*>(myCurrentEvent);
330 new AuthDlg(AuthDlg::GrantAuth, p->userId());
331 break;
332 }
333
334 case Licq::UserEvent::TypeAuthGranted:
335 {
336 Licq::EventAuthGranted* p = dynamic_cast<Licq::EventAuthGranted*>(myCurrentEvent);
337 new AddUserDlg(p->userId(), this);
338 break;
339 }
340
341 case Licq::UserEvent::TypeAdded:
342 {
343 Licq::EventAdded* p = dynamic_cast<Licq::EventAdded*>(myCurrentEvent);
344 new AddUserDlg(p->userId(), this);
345 break;
346 }
347
348 case Licq::UserEvent::TypeContactList:
349 {
350 const Licq::EventContactList::ContactList& cl = dynamic_cast<Licq::EventContactList*>(myCurrentEvent)->Contacts();
351 Licq::EventContactList::ContactList::const_iterator it;
352
353 for (it = cl.begin(); it != cl.end(); ++it)
354 {
355 new AddUserDlg((*it)->userId(), this);
356 }
357
358 myRead1Button->setEnabled(false);
359 break;
360 }
361
362 case Licq::UserEvent::TypeEmailAlert:
363 {
364 // FIXME: For now assume MSN protocol, will need to be fixed soon.
365 Licq::EventEmailAlert* p = dynamic_cast<Licq::EventEmailAlert*>(myCurrentEvent);
366
367 // Create the HTML
368 QString url = Licq::gDaemon.baseDir().c_str();
369 url += ".msn_email.html";
370
371 QString strUser = QString::fromUtf8(p->to().c_str());
372 QString strHTML = QString(
373 "<html><head><noscript><meta http-equiv=Refresh content=\"0; url=http://www.hotmail.com\">"
374 "</noscript></head><body onload=\"document.pform.submit(); \"><form name=\"pform\" action=\""
375 "%1\" method=\"POST\"><input type=\"hidden\" name=\"mode\" value=\"ttl\">"
376 "<input type=\"hidden\" name=\"login\" value=\"%2\"><input type=\"hidden\" name=\"username\""
377 "value=\"%3\"><input type=\"hidden\" name=\"sid\" value=\"%4\"><input type=\"hidden\" name=\"kv\" value=\""
378 "%5\"><input type=\"hidden\" name=\"id\" value=\"%6\"><input type=\"hidden\" name=\"sl\" value=\"9\"><input "
379 "type=\"hidden\" name=\"rru\" value=\"%7\"><input type=\"hidden\" name=\"auth\" value=\"%8\""
380 "><input type=\"hidden\" name=\"creds\" value=\"%9\"><input type=\"hidden\" name=\"svc\" value=\"mail\">"
381 "<input type=\"hidden\" name=\"js\"value=\"yes\"></form></body></html>")
382 .arg(QString::fromUtf8(p->postUrl().c_str()))
383 .arg(strUser.left(strUser.indexOf("@")))
384 .arg(strUser)
385 .arg(QString::fromUtf8(p->sid().c_str()))
386 .arg(QString::fromUtf8(p->kv().c_str()))
387 .arg(QString::fromUtf8(p->id().c_str()))
388 .arg(QString::fromUtf8(p->msgUrl().c_str()))
389 .arg(QString::fromUtf8(p->mspAuth().c_str()))
390 .arg(QString::fromUtf8(p->creds().c_str()));
391
392 QFile fileHTML(url);
393 fileHTML.open(QIODevice::WriteOnly);
394 fileHTML.write(strHTML.toLatin1(), strHTML.length());
395 fileHTML.close();
396
397 // Now we have to add the file:// after it was created,
398 // but before it is executed.
399 url.prepend("file://");
400
401 gLicqGui->viewUrl(url);
402
403 break;
404 }
405 } // switch
406 }
407
read2()408 void UserViewEvent::read2()
409 {
410 if (myCurrentEvent == NULL)
411 return;
412
413 const Licq::UserId& frontUserId(myUsers.front());
414
415 switch (myCurrentEvent->eventType())
416 {
417 case Licq::UserEvent::TypeMessage: // quote
418 case Licq::UserEvent::TypeUrl:
419 generateReply();
420 break;
421
422 case Licq::UserEvent::TypeChat: // accept a chat request
423 {
424 Licq::IcqProtocol::Ptr icq = plugin_internal_cast<Licq::IcqProtocol>(
425 Licq::gPluginManager.getProtocolInstance(frontUserId.ownerId()));
426 if (!icq)
427 return;
428
429 myCurrentEvent->SetPending(false);
430 myRead2Button->setEnabled(false);
431 myRead3Button->setEnabled(false);
432 Licq::EventChat* c = dynamic_cast<Licq::EventChat*>(myCurrentEvent);
433 ChatDlg* chatDlg = new ChatDlg(frontUserId);
434 if (c->Port() != 0) // Joining a multiparty chat (we connect to them)
435 {
436 // FIXME: must have been done in CICQDaemon
437 if (chatDlg->StartAsClient(c->Port()))
438 icq->icqChatRequestAccept(frontUserId,
439 0, c->clients(), c->Sequence(),
440 c->MessageID()[0], c->MessageID()[1], c->IsDirect());
441 }
442 else // single party (other side connects to us)
443 {
444 // FIXME: must have been done in CICQDaemon
445 if (chatDlg->StartAsServer())
446 icq->icqChatRequestAccept(frontUserId,
447 chatDlg->LocalPort(), c->clients(), c->Sequence(),
448 c->MessageID()[0], c->MessageID()[1], c->IsDirect());
449 }
450 break;
451 }
452
453 case Licq::UserEvent::TypeFile: // accept a file transfer
454 {
455 myCurrentEvent->SetPending(false);
456 myRead2Button->setEnabled(false);
457 myRead3Button->setEnabled(false);
458 Licq::EventFile* f = dynamic_cast<Licq::EventFile*>(myCurrentEvent);
459 FileDlg* fileDlg = new FileDlg(frontUserId);
460
461 if (fileDlg->ReceiveFiles())
462 // FIXME: must have been done in CICQDaemon
463 gProtocolManager.fileTransferAccept(frontUserId,
464 fileDlg->LocalPort(), f->Sequence(), f->MessageID()[0], f->MessageID()[1],
465 f->fileDescription(), f->filename(), f->FileSize(), !f->IsDirect());
466 break;
467 }
468
469 case Licq::UserEvent::TypeAuthRequest:
470 {
471 Licq::EventAuthRequest* p = dynamic_cast<Licq::EventAuthRequest*>(myCurrentEvent);
472 new AuthDlg(AuthDlg::RefuseAuth, p->userId());
473 break;
474 }
475 } // switch
476 }
477
read3()478 void UserViewEvent::read3()
479 {
480 if (myCurrentEvent == NULL)
481 return;
482
483 const Licq::UserId& frontUserId(myUsers.front());
484
485 switch (myCurrentEvent->eventType())
486 {
487 case Licq::UserEvent::TypeMessage: // Forward
488 case Licq::UserEvent::TypeUrl:
489 {
490 ForwardDlg* f = new ForwardDlg(myCurrentEvent, this);
491 f->show();
492 break;
493 }
494
495 case Licq::UserEvent::TypeChat: // refuse a chat request
496 {
497 RefuseDlg* r = new RefuseDlg(frontUserId, tr("Chat"), this);
498
499 if (r->exec())
500 {
501 Licq::IcqProtocol::Ptr icq = plugin_internal_cast<Licq::IcqProtocol>(
502 Licq::gPluginManager.getProtocolInstance(frontUserId.ownerId()));
503 if (!icq)
504 return;
505
506 myCurrentEvent->SetPending(false);
507 Licq::EventChat* c = dynamic_cast<Licq::EventChat*>(myCurrentEvent);
508 myRead2Button->setEnabled(false);
509 myRead3Button->setEnabled(false);
510
511 // FIXME: must have been done in CICQDaemon
512 icq->icqChatRequestRefuse(frontUserId,
513 r->RefuseMessage().toUtf8().data(), myCurrentEvent->Sequence(),
514 c->MessageID()[0], c->MessageID()[1], c->IsDirect());
515 }
516 delete r;
517 break;
518 }
519
520 case Licq::UserEvent::TypeFile: // refuse a file transfer
521 {
522 RefuseDlg* r = new RefuseDlg(frontUserId, tr("File Transfer"), this);
523
524 if (r->exec())
525 {
526 myCurrentEvent->SetPending(false);
527 Licq::EventFile* f = dynamic_cast<Licq::EventFile*>(myCurrentEvent);
528 myRead2Button->setEnabled(false);
529 myRead3Button->setEnabled(false);
530
531 // FIXME: must have been done in CICQDaemon
532 gProtocolManager.fileTransferRefuse(frontUserId,
533 r->RefuseMessage().toUtf8().data(), myCurrentEvent->Sequence(),
534 f->MessageID()[0], f->MessageID()[1], !f->IsDirect());
535 }
536 delete r;
537 break;
538 }
539
540 case Licq::UserEvent::TypeAuthRequest:
541 {
542 Licq::EventAuthRequest* p = dynamic_cast<Licq::EventAuthRequest*>(myCurrentEvent);
543 new AddUserDlg(p->userId(), this);
544 break;
545 }
546 } // switch
547 }
548
read4()549 void UserViewEvent::read4()
550 {
551 if (myCurrentEvent == NULL)
552 return;
553
554 const Licq::UserId& frontUserId(myUsers.front());
555
556 switch (myCurrentEvent->eventType())
557 {
558 case Licq::UserEvent::TypeMessage:
559 gLicqGui->showEventDialog(ChatEvent, frontUserId);
560 break;
561
562 case Licq::UserEvent::TypeChat: // join to current chat
563 {
564 Licq::IcqProtocol::Ptr icq = plugin_internal_cast<Licq::IcqProtocol>(
565 Licq::gPluginManager.getProtocolInstance(frontUserId.ownerId()));
566 if (!icq)
567 return;
568
569 Licq::EventChat* c = dynamic_cast<Licq::EventChat*>(myCurrentEvent);
570 if (c->Port() != 0) // Joining a multiparty chat (we connect to them)
571 {
572 ChatDlg* chatDlg = new ChatDlg(frontUserId);
573 // FIXME: must have been done in CICQDaemon
574 if (chatDlg->StartAsClient(c->Port()))
575 icq->icqChatRequestAccept(frontUserId,
576 0, c->clients(), c->Sequence(), c->MessageID()[0], c->MessageID()[1], c->IsDirect());
577 }
578 else // single party (other side connects to us)
579 {
580 ChatDlg* chatDlg = NULL;
581 JoinChatDlg* j = new JoinChatDlg(this);
582 // FIXME: must have been done in CICQDaemon
583 if (j->exec() && (chatDlg = j->JoinedChat()) != NULL)
584 icq->icqChatRequestAccept(frontUserId,
585 chatDlg->LocalPort(), c->clients(), c->Sequence(), c->MessageID()[0], c->MessageID()[1], c->IsDirect());
586 delete j;
587 }
588 break;
589 }
590
591 case Licq::UserEvent::TypeUrl: // view a url
592 gLicqGui->viewUrl(QString::fromUtf8(dynamic_cast<const Licq::EventUrl*>(myCurrentEvent)->url().c_str()));
593 break;
594
595 case Licq::UserEvent::TypeAuthRequest:
596 case Licq::UserEvent::TypeAuthGranted:
597 case Licq::UserEvent::TypeAdded:
598 {
599 Licq::UserId userId;
600 #define GETINFO(sub, type) \
601 if (myCurrentEvent->eventType() == sub) \
602 { \
603 type* p = dynamic_cast<type*>(myCurrentEvent); \
604 userId = p->userId(); \
605 }
606
607 GETINFO(Licq::UserEvent::TypeAuthRequest, Licq::EventAuthRequest);
608 GETINFO(Licq::UserEvent::TypeAuthGranted, Licq::EventAuthGranted);
609 GETINFO(Licq::UserEvent::TypeAdded, Licq::EventAdded);
610 #undef GETINFO
611
612 {
613 Licq::UserReadGuard u(userId, true);
614 }
615
616 UserDlg::showDialog(userId, UserDlg::GeneralPage, true);
617 break;
618 }
619 } // switch
620 }
621
readNext()622 void UserViewEvent::readNext()
623 {
624 MessageListItem* e = myMessageList->getNextUnread();
625
626 updateNextButton();
627
628 if (e != NULL)
629 {
630 myMessageList->setCurrentItem(e, 0);
631 myMessageList->scrollToItem(e);
632 printMessage(e);
633 }
634 }
635
clearEvent()636 void UserViewEvent::clearEvent()
637 {
638 Licq::UserWriteGuard u(myUsers.front());
639
640 if (!u.isLocked())
641 return;
642
643 u->EventClearId(myCurrentEvent->Id());
644 }
645
closeDialog()646 void UserViewEvent::closeDialog()
647 {
648 myDeleteUser = myCloseButton->modifiersWhenPressed() & Qt::ControlModifier;
649 close();
650 }
651
printMessage(QTreeWidgetItem * item)652 void UserViewEvent::printMessage(QTreeWidgetItem* item)
653 {
654 if (item == NULL)
655 return;
656
657 MessageListItem* e = dynamic_cast<MessageListItem*>(item);
658
659 myRead1Button->setText("");
660 myRead2Button->setText("");
661 myRead3Button->setText("");
662 myRead4Button->setText("");
663 myEncoding->setEnabled(true);
664
665 Licq::UserEvent* m = e->msg();
666 myCurrentEvent = m;
667
668 // Set the color for the message
669 myMessageView->setBackground(QColor(m->color()->backRed(), m->color()->backGreen(), m->color()->backBlue()));
670 myMessageView->setForeground(QColor(m->color()->foreRed(), m->color()->foreGreen(), m->color()->foreBlue()));
671
672 // Set the text
673 myMessageText = QString::fromUtf8(m->text().c_str());
674
675 QString colorAttr;
676 colorAttr.sprintf("#%02x%02x%02x", m->color()->foreRed(), m->color()->foreGreen(), m->color()->foreBlue());
677 myMessageView->setText("<font color=\"" + colorAttr + "\">" + MLView::toRichText(myMessageText, true) + "</font>");
678
679 myMessageView->GotoHome();
680
681 if (m->isReceiver())
682 {
683 switch (m->eventType())
684 {
685 case Licq::UserEvent::TypeChat: // accept or refuse a chat request
686 case Licq::UserEvent::TypeFile: // accept or refuse a file transfer
687 myRead1Button->setText(tr("&Reply"));
688 if (m->IsCancelled())
689 myMessageView->append(tr("\n--------------------\nRequest was cancelled."));
690 else
691 {
692 if (m->Pending())
693 {
694 myRead2Button->setText(tr("A&ccept"));
695 myRead3Button->setText(tr("&Refuse"));
696 }
697 // If this is a chat, and we already have chats going, and this is
698 // not a join request, then we can join
699 if (m->eventType() == Licq::UserEvent::TypeChat &&
700 ChatDlg::chatDlgs.size() > 0 &&
701 dynamic_cast<Licq::EventChat*>(m)->Port() == 0)
702 myRead4Button->setText(tr("&Join"));
703 }
704 break;
705
706 case Licq::UserEvent::TypeMessage:
707 myRead1Button->setText(tr("&Reply"));
708 myRead2Button->setText(tr("&Quote"));
709 myRead3Button->setText(tr("&Forward"));
710 myRead4Button->setText(tr("Start Chat"));
711 break;
712
713 case Licq::UserEvent::TypeSms:
714 myEncoding->setEnabled(false);
715 break;
716
717 case Licq::UserEvent::TypeUrl: // view a url
718 myRead1Button->setText(tr("&Reply"));
719 myRead2Button->setText(tr("&Quote"));
720 myRead3Button->setText(tr("&Forward"));
721 myRead4Button->setText(tr("&View"));
722 break;
723
724 case Licq::UserEvent::TypeAuthRequest:
725 {
726 myRead1Button->setText(tr("A&uthorize"));
727 myRead2Button->setText(tr("&Refuse"));
728 Licq::EventAuthRequest* pAuthReq = dynamic_cast<Licq::EventAuthRequest*>(m);
729 if (!Licq::gUserManager.userExists(pAuthReq->userId()))
730 myRead3Button->setText(tr("A&dd User"));
731 myRead4Button->setText(tr("&View Info"));
732 break;
733 }
734
735 case Licq::UserEvent::TypeAuthGranted:
736 {
737 Licq::EventAuthGranted* pAuth = dynamic_cast<Licq::EventAuthGranted*>(m);
738 if (!Licq::gUserManager.userExists(pAuth->userId()))
739 myRead1Button->setText(tr("A&dd User"));
740 myRead4Button->setText(tr("&View Info"));
741 break;
742 }
743
744 case Licq::UserEvent::TypeAdded:
745 {
746 Licq::EventAdded* pAdd = dynamic_cast<Licq::EventAdded*>(m);
747 if (!Licq::gUserManager.userExists(pAdd->userId()))
748 myRead1Button->setText(tr("A&dd User"));
749 myRead4Button->setText(tr("&View Info"));
750 break;
751 }
752
753 case Licq::UserEvent::TypeContactList:
754 {
755 int s = dynamic_cast<Licq::EventContactList*>(m)->Contacts().size();
756 if (s > 1)
757 myRead1Button->setText(tr("A&dd %1 Users").arg(s));
758 else
759 if (s == 1)
760 myRead1Button->setText(tr("A&dd User"));
761 break;
762 }
763
764 case Licq::UserEvent::TypeEmailAlert:
765 myRead1Button->setText(tr("&View Email"));
766 break;
767 } // switch
768 } // if
769
770 myRead1Button->setEnabled(!myRead1Button->text().isEmpty());
771 myRead2Button->setEnabled(!myRead2Button->text().isEmpty());
772 myRead3Button->setEnabled(!myRead3Button->text().isEmpty());
773 myRead4Button->setEnabled(!myRead4Button->text().isEmpty());
774
775 myActionsBox->setVisible(
776 myRead1Button->isEnabled() || myRead2Button->isEnabled() ||
777 myRead3Button->isEnabled() || myRead4Button->isEnabled());
778
779 myRead1Button->setFocus();
780
781 if (e->isUnread())
782 {
783 // clear the event only after all the slots have been invoked
784 QTimer::singleShot(20, this, SLOT(clearEvent()));
785 e->MarkRead();
786 }
787 }
788
sentEvent(const Licq::Event * e)789 void UserViewEvent::sentEvent(const Licq::Event* e)
790 {
791 if (e->userId() != myUsers.front())
792 return;
793
794 if (!Config::Chat::instance()->msgChatView())
795 new MessageListItem(e->userEvent(), myMessageList);
796 }
797
setEncoding()798 void UserViewEvent::setEncoding()
799 {
800 // if we have an open view, just refresh it
801 if (myMessageList != NULL)
802 printMessage(myMessageList->currentItem());
803 }
804
resizeEvent(QResizeEvent * event)805 void UserViewEvent::resizeEvent(QResizeEvent* event)
806 {
807 Config::Chat::instance()->setViewDialogSize(size());
808 UserEventCommon::resizeEvent(event);
809 }
810