source: psi/trunk/src/psipopup.cpp@ 183

Last change on this file since 183 was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 10.8 KB
Line 
1/*
2 * psipopup.cpp - the Psi passive popup class
3 * Copyright (C) 2003 Michail Pishchagin
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program 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 this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include "psipopup.h"
22#include "common.h"
23#include "fancypopup.h"
24#include "fancylabel.h"
25#include "userlist.h"
26#include "alerticon.h"
27#include "psievent.h"
28#include "im.h"
29#include "psicon.h"
30#include "psiaccount.h"
31
32#include <qapplication.h>
33#include <qlayout.h>
34
35//----------------------------------------------------------------------------
36// PsiPopupList
37//----------------------------------------------------------------------------
38
39class PsiPopupList : public QObject, public QPtrList<PsiPopup>
40{
41 Q_OBJECT
42private:
43 int numPopups;
44
45public:
46 PsiPopupList()
47 : QObject(qApp)
48 {
49 setAutoDelete(true);
50 }
51
52 PsiPopup *last()
53 {
54 if ( !count() )
55 return 0;
56 return QPtrList<PsiPopup>::first();
57 }
58
59 void prepend(const PsiPopup *d)
60 {
61 if ( isEmpty() )
62 emit started();
63
64 connect(d, SIGNAL(destroyed(QObject *)), SLOT(popupDestroyed(QObject *)));
65 QPtrList<PsiPopup>::prepend(d);
66 }
67
68signals:
69 void started();
70 void finished();
71
72private slots:
73 void popupDestroyed(QObject *p)
74 {
75 setAutoDelete(false);
76 remove((PsiPopup *)p);
77 setAutoDelete(true);
78
79 if ( isEmpty() )
80 emit finished();
81 }
82};
83
84static PsiPopupList *psiPopupList = 0;
85
86//----------------------------------------------------------------------------
87// PsiPopup::Private
88//----------------------------------------------------------------------------
89
90class PsiPopup::Private : public QObject
91{
92 Q_OBJECT
93public:
94 Private(PsiPopup *p);
95 ~Private();
96
97 void init(const Icon *titleIcon, QString titleText, PsiAccount *_acc, PopupType type);
98 QString clipText(QString);
99 QBoxLayout *createContactInfo(const Icon *icon, QString text);
100
101private slots:
102 void popupDestroyed();
103 void popupClicked(int);
104 void eventDestroyed();
105
106public:
107 PsiCon *psi;
108 PsiAccount *account;
109 FancyPopup *popup;
110 PsiPopup *psiPopup;
111 QString id;
112 PopupType popupType;
113 Jid jid;
114 Status status;
115 PsiEvent *event;
116 Icon *titleIcon;
117 bool display;
118};
119
120PsiPopup::Private::Private(PsiPopup *p)
121{
122 psiPopup = p;
123 popup = 0;
124 popupType = AlertNone;
125 event = 0;
126 titleIcon = 0;
127}
128
129PsiPopup::Private::~Private()
130{
131 if ( popup )
132 delete popup;
133 if ( titleIcon )
134 delete titleIcon;
135 popup = 0;
136}
137
138void PsiPopup::Private::init(const Icon *_titleIcon, QString titleText, PsiAccount *acc, PopupType type)
139{
140 psi = acc->psi();
141 account = acc;
142 display = true;
143
144 if ( !psiPopupList )
145 psiPopupList = new PsiPopupList();
146
147 FancyPopup *last = 0;
148 if ( psiPopupList->last() )
149 last = psiPopupList->last()->popup();
150
151 if ( type != AlertNone )
152 titleIcon = new AlertIcon(_titleIcon);
153 else
154 titleIcon = new Icon(*_titleIcon);
155
156 FancyPopup::setHideTimeout( option.ppHideTime );
157 FancyPopup::setBorderColor( option.ppBorderColor );
158
159 popup = new FancyPopup(titleText, titleIcon, last, false);
160 connect(popup, SIGNAL(clicked(int)), SLOT(popupClicked(int)));
161 connect(popup, SIGNAL(destroyed()), SLOT(popupDestroyed()));
162
163 // create id
164 if ( _titleIcon )
165 id += _titleIcon->name();
166 id += titleText;
167}
168
169void PsiPopup::Private::popupDestroyed()
170{
171 popup = 0;
172 psiPopup->deleteLater();
173}
174
175void PsiPopup::Private::popupClicked(int button)
176{
177 if ( button == (int)LeftButton ) {
178 if ( event )
179 psi->processEvent( event );
180 else if ( account ) {
181 // FIXME: it should work in most cases, but
182 // maybe it's better to fix UserList::find()?
183 Jid j( jid.userHost() );
184 account->actionDefault( j );
185 }
186 }
187
188 if ( popup )
189 popup->hide();
190}
191
192void PsiPopup::Private::eventDestroyed()
193{
194 if ( (popupType == AlertMessage || popupType == AlertHeadline) && !option.popupMsgs )
195 delete popup;
196 if ( popupType == AlertChat && !option.popupChats /*&& option.alertOpenChats*/ )
197 delete popup;
198 if ( popupType == AlertHeadline && !option.popupHeadlines)
199 delete popup;
200 if ( popupType == AlertFile && !option.popupFiles)
201 delete popup;
202
203 event = 0;
204}
205
206QString PsiPopup::Private::clipText(QString text)
207{
208 if ( option.ppTextClip > 0 ) {
209 // richtext will give us trouble here
210 if ( ((int)text.length()) > option.ppTextClip ) {
211 text = text.left( option.ppTextClip );
212
213 // delete last unclosed tag
214 /*if ( text.find("</") > text.find(">") ) {
215
216 text = text.left( text.find("</") );
217 }*/
218
219 text += "...";
220 }
221 }
222
223 return text;
224}
225
226QBoxLayout *PsiPopup::Private::createContactInfo(const Icon *icon, QString text)
227{
228 QHBoxLayout *dataBox = new QHBoxLayout(0);
229
230 if ( icon ) {
231 IconLabel *iconLabel = new IconLabel(popup);
232 iconLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
233 iconLabel->setIcon(icon);
234 dataBox->addWidget(iconLabel);
235
236 dataBox->addSpacing(5);
237 }
238
239 IconLabel *textLabel = new IconLabel(popup);
240 QFont font;
241 font.fromString( option.font[fPopup] );
242 textLabel->setFont(font);
243
244 textLabel->setText(QString("<qt>%1</qt>").arg(clipText(text)));
245 textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
246 dataBox->addWidget(textLabel);
247
248 return dataBox;
249}
250
251//----------------------------------------------------------------------------
252// PsiPopup
253//----------------------------------------------------------------------------
254
255PsiPopup::PsiPopup(const Icon *titleIcon, QString titleText, PsiAccount *acc)
256{
257 d = new Private(this);
258 d->init(titleIcon, titleText, acc, AlertNone);
259}
260
261PsiPopup::~PsiPopup()
262{
263 delete d;
264}
265
266PsiPopup::PsiPopup(PopupType type, PsiAccount *acc)
267{
268 d = new Private(this);
269
270 d->popupType = type;
271 Icon *icon = 0;
272 QString text = "Psi: ";
273 bool doAlertIcon = false;
274
275 switch(type) {
276 case AlertOnline:
277 text += PsiPopup::tr("Contact online");
278 icon = (Icon *)IconsetFactory::iconPtr("status/online");
279 break;
280 case AlertOffline:
281 text += PsiPopup::tr("Contact offline");
282 icon = (Icon *)IconsetFactory::iconPtr("status/offline");
283 break;
284 case AlertStatusChange:
285 text += PsiPopup::tr("Status change");
286 icon = (Icon *)IconsetFactory::iconPtr("status/online");
287 break;
288 case AlertMessage:
289 text += PsiPopup::tr("Incoming message");
290 icon = (Icon *)IconsetFactory::iconPtr("psi/message");
291 doAlertIcon = true;
292 break;
293 case AlertChat:
294 text += PsiPopup::tr("Incoming chat message");
295 icon= (Icon *)IconsetFactory::iconPtr("psi/chat");
296 doAlertIcon = true;
297 break;
298 case AlertHeadline:
299 text += PsiPopup::tr("Headline");
300 icon= (Icon *)IconsetFactory::iconPtr("psi/headline");
301 doAlertIcon = true;
302 break;
303 case AlertFile:
304 text += PsiPopup::tr("Incoming file");
305 icon= (Icon *)IconsetFactory::iconPtr("psi/file");
306 doAlertIcon = true;
307 break;
308 default:
309 break;
310 }
311
312 d->init(icon, text, acc, doAlertIcon ? type : AlertNone);
313}
314
315void PsiPopup::setData(const Icon *icon, QString text)
316{
317 if ( !d->popup ) {
318 deleteLater();
319 return;
320 }
321
322 d->popup->addLayout( d->createContactInfo(icon, text) );
323
324 // update id
325 if ( icon )
326 d->id += icon->name();
327 d->id += text;
328
329 show();
330}
331
332void PsiPopup::setData(const Jid &j, const Resource &r, const UserListItem *u, const PsiEvent *event)
333{
334 if ( !d->popup ) {
335 deleteLater();
336 return;
337 }
338
339 d->jid = j;
340 d->status = r.status();
341 d->event = (PsiEvent *)event;
342
343 if ( event )
344 connect(event, SIGNAL(destroyed()), d, SLOT(eventDestroyed()));
345
346 Icon *icon = is->statusPtr(j, r.status());
347 QString text;
348
349 QString jid = j.full();
350 if ( option.ppJidClip > 0 && ((int)jid.length()) > option.ppJidClip )
351 jid = jid.left( option.ppJidClip ) + "...";
352
353 QString status;
354 if ( option.ppStatusClip != 0 )
355 status = r.status().status();
356 if ( option.ppStatusClip > 0 )
357 if ( ((int)status.length()) > option.ppStatusClip )
358 status = status.left ( option.ppStatusClip ) + "...";
359
360 QString name;
361 if ( u && !u->name().isEmpty() ) {
362 if ( !option.ppJidClip )
363 name = "<nobr>" + u->name() + "</nobr>";
364 else
365 name = "<nobr>" + u->name() + " &lt;" + jid + "&gt;" + "</nobr>";
366 }
367 else
368 name = "<nobr>&lt;" + jid + "&gt;</nobr>";
369
370 QString statusString = plain2rich(status);
371 if ( option.useEmoticons )
372 statusString = emoticonify(statusString);
373
374 if ( !statusString.isEmpty() )
375 statusString = "<br>" + statusString;
376
377 QString contactText = "<font size=\"+1\">" + name + "</font>" + statusString;
378
379 // hack for duplicate "Contact Online"/"Status Change" popups
380 PsiPopup *pp = psiPopupList->first();
381 while ( pp ) {
382 if ( d->jid.full() == pp->d->jid.full() && d->status.show() == pp->d->status.show() && d->status.status() == d->status.status() ) {
383 if ( d->popupType == AlertStatusChange && pp->d->popupType == AlertOnline ) {
384 d->display = false;
385 deleteLater();
386 break;
387 }
388 }
389
390 pp = psiPopupList->next();
391 }
392
393 // show popup
394 if ( d->popupType != AlertHeadline && (d->popupType != AlertFile || !option.popupFiles) )
395 setData(icon, contactText);
396 else if ( d->popupType == AlertHeadline ) {
397 QVBoxLayout *vbox = new QVBoxLayout(0);
398 vbox->addLayout( d->createContactInfo(icon, contactText) );
399
400 vbox->addSpacing(5);
401
402 const Message *jmessage = &((MessageEvent *)event)->message();
403 QString message;
404 if ( !jmessage->subject().isEmpty() )
405 message += "<font color=\"red\"><b>" + tr("Subject:") + " " + jmessage->subject() + "</b></font><br>";
406 message += plain2rich( jmessage->body() );
407
408 QLabel *messageLabel = new QLabel(d->popup);
409 QFont font = messageLabel->font();
410 font.setPointSize(option.smallFontSize);
411 messageLabel->setFont(font);
412
413 messageLabel->setTextFormat(RichText);
414 messageLabel->setText( d->clipText(linkify( message )) );
415 messageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
416 vbox->addWidget(messageLabel);
417
418 // update id
419 if ( icon )
420 d->id += icon->name();
421 d->id += contactText;
422 d->id += message;
423
424 d->popup->addLayout( vbox );
425 show();
426 }
427}
428
429void PsiPopup::show()
430{
431 if ( !d->popup || !option.ppIsOn ) {
432 deleteLater();
433 return;
434 }
435
436 if ( !d->id.isEmpty() /*&& option.ppNoDupes*/ ) {
437 PsiPopup *pp = psiPopupList->first();
438 while ( pp ) {
439 if ( d->id == pp->id() && pp->popup() ) {
440 pp->popup()->restartHideTimer();
441
442 d->display = false;
443 break;
444 }
445
446 pp = psiPopupList->next();
447 }
448 }
449
450 if ( d->display ) {
451 psiPopupList->prepend( this );
452 d->popup->show();
453 }
454 else {
455 deleteLater();
456 }
457}
458
459QString PsiPopup::id() const
460{
461 return d->id;
462}
463
464FancyPopup *PsiPopup::popup()
465{
466 return d->popup;
467}
468
469void PsiPopup::deleteAll()
470{
471 if ( !psiPopupList )
472 return;
473
474 psiPopupList->clear();
475 delete psiPopupList;
476 psiPopupList = 0;
477}
478
479#include "psipopup.moc"
Note: See TracBrowser for help on using the repository browser.