~ubuntu-branches/ubuntu/edgy/psi/edgy

« back to all changes in this revision

Viewing changes to libpsi/psiwidgets/psitextview.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
 * 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"