~ubuntu-branches/ubuntu/dapper/psi/dapper

« back to all changes in this revision

Viewing changes to src/psipopup.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2004-06-15 00:10:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040615001041-enywb6pcpe4sjsw6
Tags: 0.9.2-1
* New upstream release
* Set KDEDIR for ./configure so kde specific files get installed
* Don't install libpsiwidgets.so. It got installed in /usr/share
  where it doesn't belong. May be included (at a better location)
  later.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
39
class PsiPopupList : public QObject, public QPtrList<PsiPopup>
 
40
{
 
41
        Q_OBJECT
 
42
private:
 
43
        int numPopups;
 
44
 
 
45
public:
 
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
 
 
68
signals:
 
69
        void started();
 
70
        void finished();
 
71
 
 
72
private 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
 
 
84
static PsiPopupList *psiPopupList = 0;
 
85
 
 
86
//----------------------------------------------------------------------------
 
87
// PsiPopup::Private
 
88
//----------------------------------------------------------------------------
 
89
 
 
90
class PsiPopup::Private : public QObject
 
91
{
 
92
        Q_OBJECT
 
93
public:
 
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
 
 
101
private slots:
 
102
        void popupDestroyed();
 
103
        void popupClicked(int);
 
104
        void eventDestroyed();
 
105
 
 
106
public:
 
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
 
 
120
PsiPopup::Private::Private(PsiPopup *p)
 
121
{
 
122
        psiPopup = p;
 
123
        popup = 0;
 
124
        popupType = AlertNone;
 
125
        event = 0;
 
126
        titleIcon = 0;
 
127
}
 
128
 
 
129
PsiPopup::Private::~Private()
 
130
{
 
131
        if ( popup )
 
132
                delete popup;
 
133
        if ( titleIcon )
 
134
                delete titleIcon;
 
135
        popup = 0;
 
136
}
 
137
 
 
138
void 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
 
 
169
void PsiPopup::Private::popupDestroyed()
 
170
{
 
171
        popup = 0;
 
172
        psiPopup->deleteLater();
 
173
}
 
174
 
 
175
void 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
 
 
192
void 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
 
 
201
        event = 0;
 
202
}
 
203
 
 
204
QString PsiPopup::Private::clipText(QString text)
 
205
{
 
206
        if ( option.ppTextClip > 0 ) {
 
207
                // richtext will give us trouble here
 
208
                if ( ((int)text.length()) > option.ppTextClip ) {
 
209
                        text = text.left( option.ppTextClip );
 
210
 
 
211
                        // delete last unclosed tag
 
212
                        /*if ( text.find("</") > text.find(">") ) {
 
213
 
 
214
                                text = text.left( text.find("</") );
 
215
                        }*/
 
216
 
 
217
                        text += "...";
 
218
                }
 
219
        }
 
220
 
 
221
        return text;
 
222
}
 
223
 
 
224
QBoxLayout *PsiPopup::Private::createContactInfo(const Icon *icon, QString text)
 
225
{
 
226
        QHBoxLayout *dataBox = new QHBoxLayout(0);
 
227
 
 
228
        if ( icon ) {
 
229
                IconLabel *iconLabel = new IconLabel(popup);
 
230
                iconLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
 
231
                iconLabel->setIcon(icon);
 
232
                dataBox->addWidget(iconLabel);
 
233
 
 
234
                dataBox->addSpacing(5);
 
235
        }
 
236
 
 
237
        IconLabel *textLabel = new IconLabel(popup);
 
238
        QFont font;
 
239
        font.fromString( option.font[fPopup] );
 
240
        textLabel->setFont(font);
 
241
 
 
242
        textLabel->setText(QString("<qt>%1</qt>").arg(clipText(text)));
 
243
        textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
 
244
        dataBox->addWidget(textLabel);
 
245
 
 
246
        return dataBox;
 
247
}
 
248
 
 
249
//----------------------------------------------------------------------------
 
250
// PsiPopup
 
251
//----------------------------------------------------------------------------
 
252
 
 
253
PsiPopup::PsiPopup(const Icon *titleIcon, QString titleText, PsiAccount *acc)
 
254
{
 
255
        d = new Private(this);
 
256
        d->init(titleIcon, titleText, acc, AlertNone);
 
257
}
 
258
 
 
259
PsiPopup::~PsiPopup()
 
260
{
 
261
        delete d;
 
262
}
 
263
 
 
264
PsiPopup::PsiPopup(PopupType type, PsiAccount *acc)
 
265
{
 
266
        d = new Private(this);
 
267
 
 
268
        d->popupType = type;
 
269
        Icon *icon = 0;
 
270
        QString text = "Psi: ";
 
271
        bool doAlertIcon = false;
 
272
 
 
273
        switch(type) {
 
274
        case AlertOnline:
 
275
                text += PsiPopup::tr("Contact online");
 
276
                icon = (Icon *)IconsetFactory::iconPtr("status/online");
 
277
                break;
 
278
        case AlertOffline:
 
279
                text += PsiPopup::tr("Contact offline");
 
280
                icon = (Icon *)IconsetFactory::iconPtr("status/offline");
 
281
                break;
 
282
        case AlertStatusChange:
 
283
                text += PsiPopup::tr("Status change");
 
284
                icon = (Icon *)IconsetFactory::iconPtr("status/online");
 
285
                break;
 
286
        case AlertMessage:
 
287
                text += PsiPopup::tr("Incoming message");
 
288
                icon = (Icon *)IconsetFactory::iconPtr("psi/message");
 
289
                doAlertIcon = true;
 
290
                break;
 
291
        case AlertChat:
 
292
                text += PsiPopup::tr("Incoming chat message");
 
293
                icon= (Icon *)IconsetFactory::iconPtr("psi/chat");
 
294
                doAlertIcon = true;
 
295
                break;
 
296
        case AlertHeadline:
 
297
                text += PsiPopup::tr("Headline");
 
298
                icon= (Icon *)IconsetFactory::iconPtr("psi/headline");
 
299
                doAlertIcon = true;
 
300
                break;
 
301
        default:
 
302
                break;
 
303
        }
 
304
 
 
305
        d->init(icon, text, acc, doAlertIcon ? type : AlertNone);
 
306
}
 
307
 
 
308
void PsiPopup::setData(const Icon *icon, QString text)
 
309
{
 
310
        if ( !d->popup ) {
 
311
                deleteLater();
 
312
                return;
 
313
        }
 
314
 
 
315
        d->popup->addLayout( d->createContactInfo(icon, text) );
 
316
 
 
317
        // update id
 
318
        if ( icon )
 
319
                d->id += icon->name();
 
320
        d->id += text;
 
321
 
 
322
        show();
 
323
}
 
324
 
 
325
void PsiPopup::setData(const Jid &j, const Resource &r, const UserListItem *u, const PsiEvent *event)
 
326
{
 
327
        if ( !d->popup ) {
 
328
                deleteLater();
 
329
                return;
 
330
        }
 
331
 
 
332
        d->jid    = j;
 
333
        d->status = r.status();
 
334
        d->event  = (PsiEvent *)event;
 
335
 
 
336
        if ( event )
 
337
                connect(event, SIGNAL(destroyed()), d, SLOT(eventDestroyed()));
 
338
 
 
339
        Icon *icon = is->statusPtr(j, r.status());
 
340
        QString text;
 
341
 
 
342
        QString jid = j.full();
 
343
        if ( option.ppJidClip > 0 && ((int)jid.length()) > option.ppJidClip )
 
344
                jid = jid.left( option.ppJidClip ) + "...";
 
345
 
 
346
        QString status;
 
347
        if ( option.ppStatusClip != 0 )
 
348
                status = r.status().status();
 
349
        if ( option.ppStatusClip > 0 )
 
350
                if ( ((int)status.length()) > option.ppStatusClip )
 
351
                        status = status.left ( option.ppStatusClip ) + "...";
 
352
 
 
353
        QString name;
 
354
        if ( u && !u->name().isEmpty() ) {
 
355
                if ( !option.ppJidClip )
 
356
                        name = "<nobr>" + u->name() + "</nobr>";
 
357
                else
 
358
                        name = "<nobr>" + u->name() + " &lt;" + jid + "&gt;" + "</nobr>";
 
359
        }
 
360
        else
 
361
                name = "<nobr>&lt;" + jid + "&gt;</nobr>";
 
362
 
 
363
        QString statusString = plain2rich(status);
 
364
        if ( option.useEmoticons )
 
365
                statusString = emoticonify(statusString);
 
366
 
 
367
        if ( !statusString.isEmpty() )
 
368
                statusString = "<br>" + statusString;
 
369
 
 
370
        QString contactText = "<font size=\"+1\">" + name + "</font>" + statusString;
 
371
 
 
372
        // hack for duplicate "Contact Online"/"Status Change" popups
 
373
        PsiPopup *pp = psiPopupList->first();
 
374
        while ( pp ) {
 
375
                if ( d->jid.full() == pp->d->jid.full() && d->status.show() == pp->d->status.show() && d->status.status() == d->status.status() ) {
 
376
                        if ( d->popupType == AlertStatusChange && pp->d->popupType == AlertOnline ) {
 
377
                                d->display = false;
 
378
                                deleteLater();
 
379
                                break;
 
380
                        }
 
381
                }
 
382
 
 
383
                pp = psiPopupList->next();
 
384
        }
 
385
 
 
386
        // show popup
 
387
        if ( d->popupType != AlertHeadline )
 
388
                setData(icon, contactText);
 
389
        else if ( d->popupType == AlertHeadline ) {
 
390
                QVBoxLayout *vbox = new QVBoxLayout(0);
 
391
                vbox->addLayout( d->createContactInfo(icon, contactText) );
 
392
 
 
393
                vbox->addSpacing(5);
 
394
 
 
395
                const Message *jmessage = &((MessageEvent *)event)->message();
 
396
                QString message;
 
397
                if ( !jmessage->subject().isEmpty() )
 
398
                        message += "<font color=\"red\"><b>" + tr("Subject:") + " " + jmessage->subject() + "</b></font><br>";
 
399
                message += plain2rich( jmessage->body() );
 
400
 
 
401
                QLabel *messageLabel = new QLabel(d->popup);
 
402
                QFont font = messageLabel->font();
 
403
                font.setPointSize(option.smallFontSize);
 
404
                messageLabel->setFont(font);
 
405
 
 
406
                messageLabel->setTextFormat(RichText);
 
407
                messageLabel->setText( d->clipText(linkify( message )) );
 
408
                messageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 
409
                vbox->addWidget(messageLabel);
 
410
 
 
411
                // update id
 
412
                if ( icon )
 
413
                        d->id += icon->name();
 
414
                d->id += contactText;
 
415
                d->id += message;
 
416
 
 
417
                d->popup->addLayout( vbox );
 
418
                show();
 
419
        }
 
420
}
 
421
 
 
422
void PsiPopup::show()
 
423
{
 
424
        if ( !d->popup || !option.ppIsOn ) {
 
425
                deleteLater();
 
426
                return;
 
427
        }
 
428
 
 
429
        if ( !d->id.isEmpty() /*&& option.ppNoDupes*/ ) {
 
430
                PsiPopup *pp = psiPopupList->first();
 
431
                while ( pp ) {
 
432
                        if ( d->id == pp->id() ) {
 
433
                                pp->popup()->restartHideTimer();
 
434
 
 
435
                                d->display = false;
 
436
                                break;
 
437
                        }
 
438
 
 
439
                        pp = psiPopupList->next();
 
440
                }
 
441
        }
 
442
 
 
443
        // do not show popups when DND
 
444
        if ( d->account->status().show() == "dnd" )
 
445
                d->display = false;
 
446
 
 
447
        if ( d->display ) {
 
448
                psiPopupList->prepend( this );
 
449
                d->popup->show();
 
450
        }
 
451
        else {
 
452
                deleteLater();
 
453
        }
 
454
}
 
455
 
 
456
QString PsiPopup::id() const
 
457
{
 
458
        return d->id;
 
459
}
 
460
 
 
461
FancyPopup *PsiPopup::popup()
 
462
{
 
463
        return d->popup;
 
464
}
 
465
 
 
466
void PsiPopup::deleteAll()
 
467
{
 
468
        if ( !psiPopupList )
 
469
                return;
 
470
 
 
471
        psiPopupList->clear();
 
472
        delete psiPopupList;
 
473
        psiPopupList = 0;
 
474
}
 
475
 
 
476
#include "psipopup.moc"