~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to libpsi/psiwidgets/psitextview.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * psitextview.cpp - Icon-aware QTextView subclass widget
3
 
 * Copyright (C) 2003  Michail Pishchagin
4
 
 *
5
 
 * This library is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation; either
8
 
 * version 2.1 of the License, or (at your option) any later version.
9
 
 *
10
 
 * This library 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 GNU
13
 
 * Lesser General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Lesser General Public
16
 
 * License 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 "psitextview.h"
22
 
 
23
 
#include <qpopupmenu.h>
24
 
#include <qapplication.h>
25
 
#include <qclipboard.h>
26
 
#include <qtooltip.h>
27
 
 
28
 
#include <qstylesheet.h>
29
 
#include <private/qrichtext_p.h>
30
 
 
31
 
#ifndef WIDGET_PLUGIN
32
 
#include "iconset.h"
33
 
#else
34
 
class Icon;
35
 
class Iconset;
36
 
#endif
37
 
 
38
 
//----------------------------------------------------------------------------
39
 
// URLObject - helper class for handling links
40
 
//----------------------------------------------------------------------------
41
 
 
42
 
class URLObject : public QObject
43
 
{
44
 
        Q_OBJECT
45
 
 
46
 
public:
47
 
        URLObject(QObject *parent = 0)
48
 
        : QObject(qApp) { Q_UNUSED(parent); }
49
 
 
50
 
        QPopupMenu *createPopupMenu(const QString &lnk);
51
 
 
52
 
private:
53
 
        QString link;
54
 
 
55
 
        QString copyString(QString from)
56
 
        {
57
 
                QString l = from;
58
 
 
59
 
                int colon = l.find(':');
60
 
                if ( colon == -1 )
61
 
                        colon = 0;
62
 
                QString service = l.left( colon );
63
 
 
64
 
                if ( service == "mailto" || service == "jabber" || service == "jid" || service == "xmpp" ) {
65
 
                        if ( colon > -1 )
66
 
                                l = l.mid( colon + 1 );
67
 
 
68
 
                        while ( l[0] == '/' )
69
 
                                l = l.mid( 1 );
70
 
                }
71
 
 
72
 
                return l;
73
 
        }
74
 
 
75
 
signals:
76
 
        void openURL(QString);
77
 
 
78
 
public slots:
79
 
        void popupAction(QString lnk) {
80
 
                emit openURL(lnk);
81
 
        }
82
 
 
83
 
        void popupAction() {
84
 
                popupAction(link);
85
 
        }
86
 
 
87
 
        void popupCopy(QString lnk) {
88
 
                QApplication::clipboard()->setText( copyString(lnk), QClipboard::Clipboard );
89
 
                if(QApplication::clipboard()->supportsSelection())
90
 
                        QApplication::clipboard()->setText( copyString(lnk), QClipboard::Selection );
91
 
        }
92
 
 
93
 
        void popupCopy() {
94
 
                popupCopy(link);
95
 
        }
96
 
};
97
 
 
98
 
static URLObject *urlObject = 0;
99
 
 
100
 
QPopupMenu *URLObject::createPopupMenu(const QString &lnk)
101
 
{
102
 
        link = lnk;
103
 
        if ( link.isEmpty() )
104
 
                return 0;
105
 
 
106
 
        int colon = link.find(':');
107
 
        if ( colon == -1 )
108
 
                colon = 0;
109
 
        QString service = link.left( colon );
110
 
 
111
 
        QString action = "ERROR";
112
 
        QString iconName;
113
 
 
114
 
        if ( service == "mailto" ) {
115
 
                action = URLLabel::tr("Open mail composer");
116
 
                iconName = "psi/email";
117
 
        }
118
 
        else if ( service == "jabber" || service == "jid" || service == "xmpp" ) {
119
 
                // TODO: need more actions to jabber item. Ex: "add to roster", "send message"
120
 
                action = URLLabel::tr("Add to Roster");
121
 
                iconName = "psi/add";
122
 
        }
123
 
        else { //if ( service == "http" || service == "https" || service.isEmpty() ) {
124
 
                action = URLLabel::tr("Open web browser");
125
 
                iconName = "psi/www";
126
 
        }
127
 
 
128
 
#ifndef WIDGET_PLUGIN
129
 
        const Icon *icon = 0;
130
 
        if ( !iconName.isEmpty() )
131
 
                icon = IconsetFactory::iconPtr( iconName );
132
 
#endif
133
 
 
134
 
        QPopupMenu *m = new QPopupMenu;
135
 
 
136
 
#ifndef WIDGET_PLUGIN
137
 
        if ( icon )
138
 
                m->insertItem(/*QIconSet(*/ *icon /*)*/, action, this, SLOT(popupAction()));
139
 
        else
140
 
#endif
141
 
                m->insertItem(action, this, SLOT(popupAction()));
142
 
        m->insertItem(URLLabel::tr("Copy location"), this, SLOT(popupCopy()));
143
 
 
144
 
        return m;
145
 
}
146
 
 
147
 
//----------------------------------------------------------------------------
148
 
// TextIcon - helper class for PsiTextView
149
 
//----------------------------------------------------------------------------
150
 
 
151
 
class TextIcon : public QObject, public QTextCustomItem
152
 
{
153
 
        Q_OBJECT
154
 
 
155
 
public:
156
 
        TextIcon(QTextDocument *p, const QMap<QString, QString> &attr, const QString &context, QMimeSourceFactory &factory);
157
 
        ~TextIcon();
158
 
 
159
 
        void adjustToPainter(QPainter *);
160
 
        void draw(QPainter *p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup &cg, bool selected);
161
 
        QString richText() const;
162
 
 
163
 
        Placement placement() const { return place; }
164
 
        int minimumWidth() const { return width; }
165
 
 
166
 
private slots:
167
 
        void iconUpdated(const QPixmap &);
168
 
 
169
 
private:
170
 
        Placement place;
171
 
        int tmpwidth, tmpheight;
172
 
        QMap<QString, QString> attributes;
173
 
        QString imgId;
174
 
        Icon *icon;
175
 
};
176
 
 
177
 
TextIcon::TextIcon(QTextDocument *p, const QMap<QString, QString> &attr, const QString &context, QMimeSourceFactory &factory)
178
 
: QObject(0, 0), QTextCustomItem (p)
179
 
{
180
 
        Q_UNUSED(context);
181
 
        Q_UNUSED(factory);
182
 
 
183
 
        width = height = 0;
184
 
 
185
 
        icon = 0;
186
 
        QString iconName = attr["name"];
187
 
 
188
 
        if ( iconName.isEmpty() )
189
 
                iconName = attr["src"];
190
 
 
191
 
        if ( iconName.isEmpty() )
192
 
                iconName = attr["source"];
193
 
 
194
 
#ifndef WIDGET_PLUGIN
195
 
        if ( !iconName.isEmpty() ) {
196
 
                icon = (Icon *)IconsetFactory::iconPtr( iconName );
197
 
                if ( icon )
198
 
                        icon = new Icon(*icon);
199
 
 
200
 
                if ( icon ) {
201
 
                        icon->activated();
202
 
                        connect(icon, SIGNAL(pixmapChanged(const QPixmap &)), SLOT(iconUpdated(const QPixmap &)));
203
 
 
204
 
                        width = icon->pixmap().width();
205
 
                        height = icon->pixmap().height();
206
 
                }
207
 
        }
208
 
#endif
209
 
 
210
 
        if ( !icon && (width*height)==0 )
211
 
                width = height = 50;
212
 
 
213
 
        place = PlaceInline;
214
 
        if ( attr["align"] == "left" )
215
 
                place = PlaceLeft;
216
 
        else if ( attr["align"] == "right" )
217
 
                place = PlaceRight;
218
 
 
219
 
        tmpwidth = width;
220
 
        tmpheight = height;
221
 
 
222
 
        attributes = attr;
223
 
}
224
 
 
225
 
TextIcon::~TextIcon()
226
 
{
227
 
#ifndef WIDGET_PLUGIN
228
 
        if ( icon ) {
229
 
                icon->stop();
230
 
                delete icon;
231
 
        }
232
 
#endif
233
 
}
234
 
 
235
 
void TextIcon::adjustToPainter(QPainter *)
236
 
{
237
 
        // FIXME: This class can be incorrectly printed. Check this sometime later.
238
 
}
239
 
 
240
 
void TextIcon::draw(QPainter *p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup &cg, bool /*selected*/)
241
 
{
242
 
        if ( placement() != PlaceInline ) {
243
 
                x = xpos;
244
 
                y = ypos;
245
 
        }
246
 
 
247
 
        if ( !icon ) {
248
 
                p->fillRect( x, y, width, height, cg.dark() );
249
 
                return;
250
 
        }
251
 
 
252
 
        if ( placement() != PlaceInline && !QRect( xpos, ypos, width, height ).intersects( QRect( cx, cy, cw, ch ) ) )
253
 
                return;
254
 
 
255
 
#ifndef WIDGET_PLUGIN
256
 
        if ( placement() == PlaceInline )
257
 
                p->drawPixmap( x , y, icon->pixmap() );
258
 
        else
259
 
                p->drawPixmap( cx , cy, icon->pixmap(), cx - x, cy - y, cw, ch );
260
 
#endif
261
 
}
262
 
 
263
 
void TextIcon::iconUpdated(const QPixmap &)
264
 
{
265
 
        // TODO: any ideas what it should do? ;-)
266
 
}
267
 
 
268
 
QString TextIcon::richText() const
269
 
{
270
 
        QString s;
271
 
        s += "<icon ";
272
 
        QMap<QString, QString>::ConstIterator it = attributes.begin();
273
 
        for ( ; it != attributes.end(); ++it ) {
274
 
                s += it.key() + "=";
275
 
                if ( (*it).find( ' ' ) != -1 )
276
 
                        s += "\"" + *it + "\"" + " ";
277
 
                else
278
 
                        s += *it + " ";
279
 
        }
280
 
        s += ">";
281
 
        return s;
282
 
}
283
 
 
284
 
//----------------------------------------------------------------------------
285
 
// PsiStyleSheet - helper class for PsiTextView
286
 
//----------------------------------------------------------------------------
287
 
 
288
 
class PsiStyleSheet : public QStyleSheet
289
 
{
290
 
        Q_OBJECT
291
 
private:
292
 
        PsiStyleSheet(QObject *parent = 0, const char *name = 0)
293
 
        : QStyleSheet(parent, name)
294
 
        {
295
 
                new QStyleSheetItem(this, QString::fromLatin1("icon"));
296
 
        }
297
 
 
298
 
public:
299
 
        QTextCustomItem *tag(const QString &name, const QMap<QString, QString> &attr,
300
 
                        const QString &context,
301
 
                        const QMimeSourceFactory &factory,
302
 
                        bool emptyTag, QTextDocument *doc ) const
303
 
        {
304
 
                const QStyleSheetItem *style = item( name );
305
 
                if ( style && style->name() == "icon" )
306
 
                        return new TextIcon( doc, attr, context, (QMimeSourceFactory&)factory );
307
 
                return QStyleSheet::tag(name, attr, context, factory, emptyTag, doc);
308
 
        }
309
 
 
310
 
        static PsiStyleSheet *self();
311
 
 
312
 
private:
313
 
        static PsiStyleSheet *psiStyleSheet;
314
 
};
315
 
 
316
 
PsiStyleSheet *PsiStyleSheet::psiStyleSheet = 0;
317
 
 
318
 
PsiStyleSheet *PsiStyleSheet::self()
319
 
{
320
 
        if ( !psiStyleSheet ) {
321
 
                psiStyleSheet = new PsiStyleSheet();
322
 
        }
323
 
 
324
 
        return psiStyleSheet;
325
 
}
326
 
 
327
 
//----------------------------------------------------------------------------
328
 
// PsiTextView
329
 
//----------------------------------------------------------------------------
330
 
 
331
 
class PsiTextView::Private : public QObject
332
 
{
333
 
        Q_OBJECT
334
 
 
335
 
public:
336
 
        Private(QObject *parent)
337
 
        : QObject(parent, "PsiTextView::Private") { }
338
 
};
339
 
 
340
 
PsiTextView::PsiTextView(QWidget *parent, const char *name)
341
 
: QTextEdit(parent, name)
342
 
{
343
 
        d = new Private(this);
344
 
 
345
 
        setReadOnly(true);
346
 
        setTextFormat(RichText);
347
 
 
348
 
        setStyleSheet( styleSheet() );
349
 
}
350
 
 
351
 
QStyleSheet *PsiTextView::styleSheet()
352
 
{
353
 
        return PsiStyleSheet::self();
354
 
}
355
 
 
356
 
QPopupMenu *PsiTextView::createPopupMenu(const QPoint &pos)
357
 
{
358
 
        QString link = anchorAt(pos);
359
 
        if ( link.isEmpty() )
360
 
                return QTextEdit::createPopupMenu(pos);
361
 
 
362
 
        if ( !urlObject )
363
 
                urlObject = new URLObject();
364
 
        return urlObject->createPopupMenu( link );
365
 
}
366
 
 
367
 
void PsiTextView::emitHighlighted(const QString &)
368
 
{
369
 
}
370
 
 
371
 
void PsiTextView::emitLinkClicked(const QString &s)
372
 
{
373
 
        if ( !urlObject )
374
 
                urlObject = new URLObject();
375
 
        urlObject->popupAction( s );
376
 
}
377
 
 
378
 
//----------------------------------------------------------------------------
379
 
// URLLabel
380
 
//----------------------------------------------------------------------------
381
 
 
382
 
class URLLabel::Private
383
 
{
384
 
public:
385
 
        QString url;
386
 
        QString title;
387
 
};
388
 
 
389
 
URLLabel::URLLabel(QWidget *parent, const char *name)
390
 
: QLabel(parent, name)
391
 
{
392
 
        d = new Private;
393
 
        setCursor( pointingHandCursor );
394
 
}
395
 
 
396
 
URLLabel::~URLLabel()
397
 
{
398
 
        delete d;
399
 
}
400
 
 
401
 
const QString &URLLabel::url() const
402
 
{
403
 
        return d->url;
404
 
}
405
 
 
406
 
void URLLabel::setUrl(const QString &url)
407
 
{
408
 
        d->url = url;
409
 
        updateText();
410
 
}
411
 
 
412
 
const QString &URLLabel::title() const
413
 
{
414
 
        return d->title;
415
 
}
416
 
 
417
 
void URLLabel::setTitle(const QString &t)
418
 
{
419
 
        d->title = t;
420
 
        updateText();
421
 
}
422
 
 
423
 
void URLLabel::updateText()
424
 
{
425
 
        setText( QString("<a href=\"%1\">%2</a>").arg(d->url).arg(d->title) );
426
 
 
427
 
        if ( d->url != d->title )
428
 
                QToolTip::add(this, d->url);
429
 
        else
430
 
                QToolTip::remove(this);
431
 
}
432
 
 
433
 
void URLLabel::mouseReleaseEvent (QMouseEvent *e)
434
 
{
435
 
        QLabel::mouseReleaseEvent (e);
436
 
 
437
 
        switch ( e->button() ) {
438
 
        case LeftButton:
439
 
                if ( !urlObject )
440
 
                        urlObject = new URLObject();
441
 
                urlObject->popupAction( url() );
442
 
                break;
443
 
 
444
 
        case MidButton:
445
 
                break;
446
 
 
447
 
        case RightButton:
448
 
                {
449
 
                        if ( !urlObject )
450
 
                                urlObject = new URLObject();
451
 
                        QPopupMenu *m = urlObject->createPopupMenu( d->url );
452
 
 
453
 
                        if ( m ) {
454
 
                                m->exec( e->globalPos() );
455
 
                                delete m;
456
 
                        }
457
 
                        break;
458
 
                }
459
 
 
460
 
        default:
461
 
                ; // to supress warnings
462
 
        }
463
 
}
464
 
 
465
 
void URLLabel::enterEvent (QEvent *e)
466
 
{
467
 
        QLabel::enterEvent (e);
468
 
}
469
 
 
470
 
void URLLabel::leaveEvent (QEvent *e)
471
 
{
472
 
        QLabel::leaveEvent (e);
473
 
}
474
 
 
475
 
void URLLabel::connectOpenURL(QObject *receiver, const char *slot)
476
 
{
477
 
        if ( !urlObject )
478
 
                urlObject = new URLObject();
479
 
 
480
 
        connect(urlObject, SIGNAL(openURL(QString)), receiver, slot);
481
 
}
482
 
 
483
 
#include "psitextview.moc"