67ad051 by Lars Knoll at 2009-03-23 1
/****************************************************************************
2
**
fbc2c44 by Jason McDonald at 2011-01-10 3
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
04e3b30 by Jason McDonald at 2009-09-09 4
** All rights reserved.
858c70f by Jason McDonald at 2009-06-16 5
** Contact: Nokia Corporation (qt-info@nokia.com)
67ad051 by Lars Knoll at 2009-03-23 6
**
7
** This file is part of the QtGui module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** No Commercial Usage
11
** This file contains pre-release code and may not be distributed.
12
** You may use this file in accordance with the terms and conditions
309db73 by Jason McDonald at 2009-08-31 13
** contained in the Technology Preview License Agreement accompanying
14
** this package.
67ad051 by Lars Knoll at 2009-03-23 15
**
16
** GNU Lesser General Public License Usage
17
** Alternatively, this file may be used under the terms of the GNU Lesser
18
** General Public License version 2.1 as published by the Free Software
19
** Foundation and appearing in the file LICENSE.LGPL included in the
20
** packaging of this file.  Please review the following information to
21
** ensure the GNU Lesser General Public License version 2.1 requirements
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23
**
04e3b30 by Jason McDonald at 2009-09-09 24
** In addition, as a special exception, Nokia gives you certain additional
25
** rights.  These rights are described in the Nokia Qt LGPL Exception
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
67ad051 by Lars Knoll at 2009-03-23 27
**
309db73 by Jason McDonald at 2009-08-31 28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
30
**
31
**
32
**
33
**
34
**
35
**
36
**
67ad051 by Lars Knoll at 2009-03-23 37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
#include "qicon.h"
13a31fe by Jens Bache-Wiig at 2009-08-10 43
#include "qicon_p.h"
67ad051 by Lars Knoll at 2009-03-23 44
#include "qiconengine.h"
45
#include "qiconengineplugin.h"
46
#include "private/qfactoryloader_p.h"
13a31fe by Jens Bache-Wiig at 2009-08-10 47
#include "private/qiconloader_p.h"
67ad051 by Lars Knoll at 2009-03-23 48
#include "qapplication.h"
49
#include "qstyleoption.h"
50
#include "qpainter.h"
51
#include "qfileinfo.h"
52
#include "qstyle.h"
53
#include "qpixmapcache.h"
54
#include "qvariant.h"
13a31fe by Jens Bache-Wiig at 2009-08-10 55
#include "qcache.h"
67ad051 by Lars Knoll at 2009-03-23 56
#include "qdebug.h"
ee383b8 by Olivier Goffart at 2009-10-07 57
#include "private/qguiplatformplugin_p.h"
67ad051 by Lars Knoll at 2009-03-23 58
59
#ifdef Q_WS_MAC
60
#include <private/qt_mac_p.h>
48fe6df by Norwegian Rock Cat at 2009-06-23 61
#include <private/qt_cocoa_helpers_mac_p.h>
67ad051 by Lars Knoll at 2009-03-23 62
#endif
63
13a31fe by Jens Bache-Wiig at 2009-08-10 64
#ifdef Q_WS_X11
65
#include "private/qt_x11_p.h"
66
#include "private/qkde_p.h"
67
#endif
68
fccbc9b by Jørgen Lind at 2009-10-29 69
#ifndef QT_NO_ICON
67ad051 by Lars Knoll at 2009-03-23 70
QT_BEGIN_NAMESPACE
71
72
/*!
73
    \enum QIcon::Mode
74
75
    This enum type describes the mode for which a pixmap is intended
76
    to be used. The currently defined modes are:
77
78
    \value Normal
79
         Display the pixmap when the user is
80
        not interacting with the icon, but the
81
        functionality represented by the icon is available.
82
    \value Disabled
83
         Display the pixmap when the
84
        functionality represented by the icon is not available.
85
    \value Active
86
         Display the pixmap when the
87
        functionality represented by the icon is available and
88
        the user is interacting with the icon, for example, moving the
89
        mouse over it or clicking it.
90
   \value Selected
91
        Display the pixmap when the item represented by the icon is
92
        selected.
93
*/
94
95
/*!
96
  \enum QIcon::State
97
98
  This enum describes the state for which a pixmap is intended to be
99
  used. The \e state can be:
100
101
  \value Off  Display the pixmap when the widget is in an "off" state
102
  \value On  Display the pixmap when the widget is in an "on" state
103
*/
104
105
static QBasicAtomicInt serialNumCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
106
dadfdfa by Trond Kjernåsen at 2010-02-09 107
static void qt_cleanup_icon_cache();
108
typedef QCache<QString, QIcon> IconCache;
109
Q_GLOBAL_STATIC_WITH_INITIALIZER(IconCache, qtIconCache, qAddPostRoutine(qt_cleanup_icon_cache))
110
111
static void qt_cleanup_icon_cache()
112
{
113
    qtIconCache()->clear();
114
}
115
13a31fe by Jens Bache-Wiig at 2009-08-10 116
QIconPrivate::QIconPrivate()
117
    : engine(0), ref(1),
118
    serialNum(serialNumCounter.fetchAndAddRelaxed(1)),
119
    detach_no(0),
120
    engine_version(2),
121
    v1RefCount(0)
67ad051 by Lars Knoll at 2009-03-23 122
{
13a31fe by Jens Bache-Wiig at 2009-08-10 123
}
67ad051 by Lars Knoll at 2009-03-23 124
125
QPixmapIconEngine::QPixmapIconEngine()
126
{
127
}
128
129
QPixmapIconEngine::QPixmapIconEngine(const QPixmapIconEngine &other)
130
    : QIconEngineV2(other), pixmaps(other.pixmaps)
131
{
132
}
133
134
QPixmapIconEngine::~QPixmapIconEngine()
135
{
136
}
137
138
void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
139
{
140
    QSize pixmapSize = rect.size();
48fe6df by Norwegian Rock Cat at 2009-06-23 141
#if defined(Q_WS_MAC)
142
    pixmapSize *= qt_mac_get_scalefactor();
67ad051 by Lars Knoll at 2009-03-23 143
#endif
144
    painter->drawPixmap(rect, pixmap(pixmapSize, mode, state));
145
}
146
147
static inline int area(const QSize &s) { return s.width() * s.height(); }
148
149
// returns the smallest of the two that is still larger than or equal to size.
150
static QPixmapIconEngineEntry *bestSizeMatch( const QSize &size, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb)
151
{
152
    int s = area(size);
153
    if (pa->size == QSize() && pa->pixmap.isNull()) {
154
        pa->pixmap = QPixmap(pa->fileName);
155
        pa->size = pa->pixmap.size();
156
    }
157
    int a = area(pa->size);
158
    if (pb->size == QSize() && pb->pixmap.isNull()) {
159
        pb->pixmap = QPixmap(pb->fileName);
160
        pb->size = pb->pixmap.size();
161
    }
162
    int b = area(pb->size);
163
    int res = a;
164
    if (qMin(a,b) >= s)
165
        res = qMin(a,b);
166
    else
167
        res = qMax(a,b);
168
    if (res == a)
169
        return pa;
170
    return pb;
171
}
172
173
QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state)
174
{
175
    QPixmapIconEngineEntry *pe = 0;
176
    for (int i = 0; i < pixmaps.count(); ++i)
177
        if (pixmaps.at(i).mode == mode && pixmaps.at(i).state == state) {
178
            if (pe)
179
                pe = bestSizeMatch(size, &pixmaps[i], pe);
180
            else
181
                pe = &pixmaps[i];
182
        }
183
    return pe;
184
}
185
186
187
QPixmapIconEngineEntry *QPixmapIconEngine::bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly)
188
{
189
    QPixmapIconEngineEntry *pe = tryMatch(size, mode, state);
190
    while (!pe){
191
        QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On;
192
        if (mode == QIcon::Disabled || mode == QIcon::Selected) {
193
            QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled;
194
            if ((pe = tryMatch(size, QIcon::Normal, state)))
195
                break;
196
            if ((pe = tryMatch(size, QIcon::Active, state)))
197
                break;
198
            if ((pe = tryMatch(size, mode, oppositeState)))
199
                break;
200
            if ((pe = tryMatch(size, QIcon::Normal, oppositeState)))
201
                break;
202
            if ((pe = tryMatch(size, QIcon::Active, oppositeState)))
203
                break;
204
            if ((pe = tryMatch(size, oppositeMode, state)))
205
                break;
206
            if ((pe = tryMatch(size, oppositeMode, oppositeState)))
207
                break;
208
        } else {
209
            QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal;
210
            if ((pe = tryMatch(size, oppositeMode, state)))
211
                break;
212
            if ((pe = tryMatch(size, mode, oppositeState)))
213
                break;
214
            if ((pe = tryMatch(size, oppositeMode, oppositeState)))
215
                break;
216
            if ((pe = tryMatch(size, QIcon::Disabled, state)))
217
                break;
218
            if ((pe = tryMatch(size, QIcon::Selected, state)))
219
                break;
220
            if ((pe = tryMatch(size, QIcon::Disabled, oppositeState)))
221
                break;
222
            if ((pe = tryMatch(size, QIcon::Selected, oppositeState)))
223
                break;
224
        }
225
226
        if (!pe)
227
            return pe;
228
    }
229
230
    if (sizeOnly ? (pe->size.isNull() || !pe->size.isValid()) : pe->pixmap.isNull()) {
231
        pe->pixmap = QPixmap(pe->fileName);
232
        if (!pe->pixmap.isNull())
233
            pe->size = pe->pixmap.size();
234
    }
235
236
    return pe;
237
}
238
239
QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
240
{
241
    QPixmap pm;
242
    QPixmapIconEngineEntry *pe = bestMatch(size, mode, state, false);
243
    if (pe)
244
        pm = pe->pixmap;
245
246
    if (pm.isNull()) {
247
        int idx = pixmaps.count();
248
        while (--idx >= 0) {
249
            if (pe == &pixmaps[idx]) {
250
                pixmaps.remove(idx);
251
                break;
252
            }
253
        }
254
        if (pixmaps.isEmpty())
255
            return pm;
256
        else
257
            return pixmap(size, mode, state);
258
    }
259
260
    QSize actualSize = pm.size();
261
    if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
262
        actualSize.scale(size, Qt::KeepAspectRatio);
263
264
    QString key = QLatin1String("$qt_icon_")
265
                  + QString::number(pm.cacheKey())
266
                  + QString::number(pe->mode)
35e2a29 by Thierry Bastian at 2009-06-11 267
                  + QString::number(QApplication::palette().cacheKey())
8ec0109 by Jens Bache-Wiig at 2009-04-15 268
                  + QLatin1Char('_')
67ad051 by Lars Knoll at 2009-03-23 269
                  + QString::number(actualSize.width())
270
                  + QLatin1Char('_')
271
                  + QString::number(actualSize.height())
272
                  + QLatin1Char('_');
273
274
275
    if (mode == QIcon::Active) {
276
        if (QPixmapCache::find(key + QString::number(mode), pm))
277
            return pm; // horray
278
        if (QPixmapCache::find(key + QString::number(QIcon::Normal), pm)) {
279
            QStyleOption opt(0);
280
            opt.palette = QApplication::palette();
281
            QPixmap active = QApplication::style()->generatedIconPixmap(QIcon::Active, pm, &opt);
282
            if (pm.cacheKey() == active.cacheKey())
283
                return pm;
284
        }
285
    }
286
287
    if (!QPixmapCache::find(key + QString::number(mode), pm)) {
288
        if (pm.size() != actualSize)
289
            pm = pm.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
290
        if (pe->mode != mode && mode != QIcon::Normal) {
291
            QStyleOption opt(0);
292
            opt.palette = QApplication::palette();
293
            QPixmap generated = QApplication::style()->generatedIconPixmap(mode, pm, &opt);
294
            if (!generated.isNull())
295
                pm = generated;
296
        }
297
        QPixmapCache::insert(key + QString::number(mode), pm);
298
    }
299
    return pm;
300
}
301
302
QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
303
{
304
    QSize actualSize;
305
    if (QPixmapIconEngineEntry *pe = bestMatch(size, mode, state, true))
306
        actualSize = pe->size;
307
308
    if (actualSize.isNull())
309
        return actualSize;
310
311
    if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
312
        actualSize.scale(size, Qt::KeepAspectRatio);
313
    return actualSize;
314
}
315
316
void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
317
{
318
    if (!pixmap.isNull()) {
319
        QPixmapIconEngineEntry *pe = tryMatch(pixmap.size(), mode, state);
320
        if(pe && pe->size == pixmap.size()) {
321
            pe->pixmap = pixmap;
322
            pe->fileName.clear();
323
        } else {
324
            pixmaps += QPixmapIconEngineEntry(pixmap, mode, state);
325
        }
326
    }
327
}
328
329
void QPixmapIconEngine::addFile(const QString &fileName, const QSize &_size, QIcon::Mode mode, QIcon::State state)
330
{
331
    if (!fileName.isEmpty()) {
332
        QSize size = _size;
333
        QPixmap pixmap;
334
335
        QString abs = fileName;
336
        if (fileName.at(0) != QLatin1Char(':'))
337
            abs = QFileInfo(fileName).absoluteFilePath();
338
339
        for (int i = 0; i < pixmaps.count(); ++i) {
340
            if (pixmaps.at(i).mode == mode && pixmaps.at(i).state == state) {
341
                QPixmapIconEngineEntry *pe = &pixmaps[i];
342
                if(size == QSize()) {
343
                    pixmap = QPixmap(abs);
344
                    size = pixmap.size();
345
                }
346
                if (pe->size == QSize() && pe->pixmap.isNull()) {
347
                    pe->pixmap = QPixmap(pe->fileName);
348
                    pe->size = pe->pixmap.size();
349
                }
350
                if(pe->size == size) {
351
                    pe->pixmap = pixmap;
352
                    pe->fileName = abs;
353
                    return;
354
                }
355
            }
356
        }
357
        QPixmapIconEngineEntry e(abs, size, mode, state);
358
        e.pixmap = pixmap;
359
        pixmaps += e;
360
    }
361
}
362
363
QString QPixmapIconEngine::key() const
364
{
365
    return QLatin1String("QPixmapIconEngine");
366
}
367
368
QIconEngineV2 *QPixmapIconEngine::clone() const
369
{
370
    return new QPixmapIconEngine(*this);
371
}
372
373
bool QPixmapIconEngine::read(QDataStream &in)
374
{
375
    int num_entries;
376
    QPixmap pm;
377
    QString fileName;
378
    QSize sz;
379
    uint mode;
380
    uint state;
381
382
    in >> num_entries;
383
    for (int i=0; i < num_entries; ++i) {
384
        if (in.atEnd()) {
385
            pixmaps.clear();
386
            return false;
387
        }
388
        in >> pm;
389
        in >> fileName;
390
        in >> sz;
391
        in >> mode;
392
        in >> state;
408ca46 by Trond Kjernåsen at 2009-05-28 393
        if (pm.isNull()) {
67ad051 by Lars Knoll at 2009-03-23 394
            addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
408ca46 by Trond Kjernåsen at 2009-05-28 395
        } else {
396
            QPixmapIconEngineEntry pe(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
397
            pe.pixmap = pm;
398
            pixmaps += pe;
399
        }
67ad051 by Lars Knoll at 2009-03-23 400
    }
401
    return true;
402
}
403
404
bool QPixmapIconEngine::write(QDataStream &out) const
405
{
406
    int num_entries = pixmaps.size();
407
    out << num_entries;
408
    for (int i=0; i < num_entries; ++i) {
409
        if (pixmaps.at(i).pixmap.isNull())
410
            out << QPixmap(pixmaps.at(i).fileName);
411
        else
412
            out << pixmaps.at(i).pixmap;
413
        out << pixmaps.at(i).fileName;
414
        out << pixmaps.at(i).size;
415
        out << (uint) pixmaps.at(i).mode;
416
        out << (uint) pixmaps.at(i).state;
417
    }
418
    return true;
419
}
420
421
void QPixmapIconEngine::virtual_hook(int id, void *data)
422
{
423
    switch (id) {
424
    case QIconEngineV2::AvailableSizesHook: {
425
        QIconEngineV2::AvailableSizesArgument &arg =
426
            *reinterpret_cast<QIconEngineV2::AvailableSizesArgument*>(data);
427
        arg.sizes.clear();
428
        for (int i = 0; i < pixmaps.size(); ++i) {
429
            QPixmapIconEngineEntry &pe = pixmaps[i];
430
            if (pe.size == QSize() && pe.pixmap.isNull()) {
431
                pe.pixmap = QPixmap(pe.fileName);
432
                pe.size = pe.pixmap.size();
433
            }
434
            if (pe.mode == arg.mode && pe.state == arg.state && !pe.size.isEmpty())
435
                arg.sizes.push_back(pe.size);
436
        }
437
        break;
438
    }
439
    default:
440
        QIconEngineV2::virtual_hook(id, data);
441
    }
442
}
443
444
#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
445
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
446
    (QIconEngineFactoryInterface_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive))
447
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loaderV2,
448
    (QIconEngineFactoryInterfaceV2_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive))
449
#endif
450
451
452
453
/*!
454
  \class QIcon
455
456
  \brief The QIcon class provides scalable icons in different modes
457
  and states.
458
911557f by Volker Hilsheimer at 2009-08-17 459
  \ingroup painting
67ad051 by Lars Knoll at 2009-03-23 460
  \ingroup shared
911557f by Volker Hilsheimer at 2009-08-17 461
67ad051 by Lars Knoll at 2009-03-23 462
463
  A QIcon can generate smaller, larger, active, and disabled pixmaps
464
  from the set of pixmaps it is given. Such pixmaps are used by Qt
465
  widgets to show an icon representing a particular action.
466
467
  The simplest use of QIcon is to create one from a QPixmap file or
468
  resource, and then use it, allowing Qt to work out all the required
469
  icon styles and sizes. For example:
470
471
  \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 0
472
473
  To undo a QIcon, simply set a null icon in its place:
474
475
  \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 1
476
477
  Use the QImageReader::supportedImageFormats() and
478
  QImageWriter::supportedImageFormats() functions to retrieve a
479
  complete list of the supported file formats.
480
481
  When you retrieve a pixmap using pixmap(QSize, Mode, State), and no
482
  pixmap for this given size, mode and state has been added with
483
  addFile() or addPixmap(), then QIcon will generate one on the
484
  fly. This pixmap generation happens in a QIconEngineV2. The default
485
  engine scales pixmaps down if required, but never up, and it uses
486
  the current style to calculate a disabled appearance. By using
487
  custom icon engines, you can customize every aspect of generated
488
  icons. With QIconEnginePluginV2 it is possible to register different
489
  icon engines for different file suffixes, making it possible for
490
  third parties to provide additional icon engines to those included
491
  with Qt.
492
493
  \note Since Qt 4.2, an icon engine that supports SVG is included.
494
495
  \section1 Making Classes that Use QIcon
496
497
  If you write your own widgets that have an option to set a small
498
  pixmap, consider allowing a QIcon to be set for that pixmap.  The
499
  Qt class QToolButton is an example of such a widget.
500
501
  Provide a method to set a QIcon, and when you draw the icon, choose
502
  whichever pixmap is appropriate for the current state of your widget.
503
  For example:
504
  \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 2
505
506
  You might also make use of the \c Active mode, perhaps making your
507
  widget \c Active when the mouse is over the widget (see \l
508
  QWidget::enterEvent()), while the mouse is pressed pending the
509
  release that will activate the function, or when it is the currently
510
  selected item. If the widget can be toggled, the "On" mode might be
511
  used to draw a different icon.
512
513
  \img icon.png QIcon
514
515
  \sa {fowler}{GUI Design Handbook: Iconic Label}, {Icons Example}
516
*/
517
518
519
/*!
520
  Constructs a null icon.
521
*/
522
QIcon::QIcon()
523
    : d(0)
524
{
525
}
526
527
/*!
528
  Constructs an icon from a \a pixmap.
529
 */
530
QIcon::QIcon(const QPixmap &pixmap)
531
    :d(0)
532
{
533
    addPixmap(pixmap);
534
}
535
536
/*!
537
  Constructs a copy of \a other. This is very fast.
538
*/
539
QIcon::QIcon(const QIcon &other)
540
    :d(other.d)
541
{
542
    if (d)
543
        d->ref.ref();
544
}
545
546
/*!
547
    Constructs an icon from the file with the given \a fileName. The
548
    file will be loaded on demand.
549
550
    If \a fileName contains a relative path (e.g. the filename only)
551
    the relevant file must be found relative to the runtime working
552
    directory.
553
554
    The file name can be either refer to an actual file on disk or to
555
    one of the application's embedded resources.  See the
556
    \l{resources.html}{Resource System} overview for details on how to
557
    embed images and other resource files in the application's
558
    executable.
559
560
    Use the QImageReader::supportedImageFormats() and
561
    QImageWriter::supportedImageFormats() functions to retrieve a
562
    complete list of the supported file formats.
563
*/
564
QIcon::QIcon(const QString &fileName)
565
    : d(0)
566
{
567
    addFile(fileName);
568
}
569
570
571
/*!
572
    Creates an icon with a specific icon \a engine. The icon takes
573
    ownership of the engine.
574
*/
575
QIcon::QIcon(QIconEngine *engine)
576
    :d(new QIconPrivate)
577
{
578
    d->engine_version = 1;
579
    d->engine = engine;
580
    d->v1RefCount = new QAtomicInt(1);
581
}
582
583
/*!
584
    Creates an icon with a specific icon \a engine. The icon takes
585
    ownership of the engine.
586
*/
587
QIcon::QIcon(QIconEngineV2 *engine)
588
    :d(new QIconPrivate)
589
{
590
    d->engine_version = 2;
591
    d->engine = engine;
592
}
593
594
/*!
595
    Destroys the icon.
596
*/
597
QIcon::~QIcon()
598
{
599
    if (d && !d->ref.deref())
600
        delete d;
601
}
602
603
/*!
604
    Assigns the \a other icon to this icon and returns a reference to
605
    this icon.
606
*/
607
QIcon &QIcon::operator=(const QIcon &other)
608
{
609
    if (other.d)
610
        other.d->ref.ref();
611
    if (d && !d->ref.deref())
612
        delete d;
613
    d = other.d;
614
    return *this;
615
}
616
617
/*!
618
   Returns the icon as a QVariant.
619
*/
620
QIcon::operator QVariant() const
621
{
622
    return QVariant(QVariant::Icon, this);
623
}
624
625
/*! \obsolete
626
627
    Returns a number that identifies the contents of this
628
    QIcon object. Distinct QIcon objects can have
629
    the same serial number if they refer to the same contents
630
    (but they don't have to). Also, the serial number of
631
    a QIcon object may change during its lifetime.
632
633
    Use cacheKey() instead.
634
635
    A null icon always has a serial number of 0.
636
637
    Serial numbers are mostly useful in conjunction with caching.
638
639
    \sa QPixmap::serialNumber()
640
*/
641
642
int QIcon::serialNumber() const
643
{
644
    return d ? d->serialNum : 0;
645
}
646
647
/*!
648
    Returns a number that identifies the contents of this QIcon
649
    object. Distinct QIcon objects can have the same key if
650
    they refer to the same contents.
651
    \since 4.3
652
653
    The cacheKey() will change when the icon is altered via
654
    addPixmap() or addFile().
655
656
    Cache keys are mostly useful in conjunction with caching.
657
658
    \sa QPixmap::cacheKey()
659
*/
660
qint64 QIcon::cacheKey() const
661
{
662
    if (!d)
663
        return 0;
664
    return (((qint64) d->serialNum) << 32) | ((qint64) (d->detach_no));
665
}
666
667
/*!
668
  Returns a pixmap with the requested \a size, \a mode, and \a
669
  state, generating one if necessary. The pixmap might be smaller than
670
  requested, but never larger.
671
672
  \sa actualSize(), paint()
673
*/
674
QPixmap QIcon::pixmap(const QSize &size, Mode mode, State state) const
675
{
676
    if (!d)
677
        return QPixmap();
678
    return d->engine->pixmap(size, mode, state);
679
}
680
681
/*!
682
    \fn QPixmap QIcon::pixmap(int w, int h, Mode mode = Normal, State state = Off) const
683
684
    \overload
685
686
    Returns a pixmap of size QSize(\a w, \a h). The pixmap might be smaller than
687
    requested, but never larger.
688
*/
689
690
/*!
691
    \fn QPixmap QIcon::pixmap(int extent, Mode mode = Normal, State state = Off) const
692
693
    \overload
694
695
    Returns a pixmap of size QSize(\a extent, \a extent). The pixmap might be smaller
696
    than requested, but never larger.
697
*/
698
699
/*!  Returns the actual size of the icon for the requested \a size, \a
700
  mode, and \a state. The result might be smaller than requested, but
701
  never larger.
702
703
  \sa pixmap(), paint()
704
*/
705
QSize QIcon::actualSize(const QSize &size, Mode mode, State state) const
706
{
707
    if (!d)
708
        return QSize();
709
    return d->engine->actualSize(size, mode, state);
710
}
711
712
713
/*!
714
    Uses the \a painter to paint the icon with specified \a alignment,
715
    required \a mode, and \a state into the rectangle \a rect.
716
717
    \sa actualSize(), pixmap()
718
*/
719
void QIcon::paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, Mode mode, State state) const
720
{
721
    if (!d || !painter)
722
        return;
723
    QRect alignedRect = QStyle::alignedRect(painter->layoutDirection(), alignment, d->engine->actualSize(rect.size(), mode, state), rect);
724
    d->engine->paint(painter, alignedRect, mode, state);
725
}
726
727
/*!
728
    \fn void QIcon::paint(QPainter *painter, int x, int y, int w, int h, Qt::Alignment alignment,
729
                          Mode mode, State state) const
730
731
    \overload
732
733
    Paints the icon into the rectangle QRect(\a x, \a y, \a w, \a h).
734
*/
735
736
/*!
737
    Returns true if the icon is empty; otherwise returns false.
738
739
    An icon is empty if it has neither a pixmap nor a filename.
740
741
    Note: Even a non-null icon might not be able to create valid
742
    pixmaps, eg. if the file does not exist or cannot be read.
743
*/
744
bool QIcon::isNull() const
745
{
746
    return !d;
747
}
748
749
/*!\internal
750
 */
751
bool QIcon::isDetached() const
752
{
753
    return !d || d->ref == 1;
754
}
755
756
/*! \internal
757
 */
758
void QIcon::detach()
759
{
760
    if (d) {
761
        if (d->ref != 1) {
762
            QIconPrivate *x = new QIconPrivate;
763
            if (d->engine_version > 1) {
764
                QIconEngineV2 *engine = static_cast<QIconEngineV2 *>(d->engine);
765
                x->engine = engine->clone();
766
            } else {
767
                x->engine = d->engine;
768
                x->v1RefCount = d->v1RefCount;
769
                x->v1RefCount->ref();
770
            }
771
            x->engine_version = d->engine_version;
772
            if (!d->ref.deref())
773
                delete d;
774
            d = x;
775
        }
776
        ++d->detach_no;
777
    }
778
}
779
780
/*!
781
    Adds \a pixmap to the icon, as a specialization for \a mode and
782
    \a state.
783
784
    Custom icon engines are free to ignore additionally added
785
    pixmaps.
786
787
    \sa addFile()
788
*/
789
void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
790
{
791
    if (pixmap.isNull())
792
        return;
793
    if (!d) {
794
        d = new QIconPrivate;
795
        d->engine = new QPixmapIconEngine;
796
    } else {
797
        detach();
798
    }
799
    d->engine->addPixmap(pixmap, mode, state);
800
}
801
802
803
/*!  Adds an image from the file with the given \a fileName to the
804
     icon, as a specialization for \a size, \a mode and \a state. The
805
     file will be loaded on demand. Note: custom icon engines are free
806
     to ignore additionally added pixmaps.
807
808
     If \a fileName contains a relative path (e.g. the filename only)
809
     the relevant file must be found relative to the runtime working
810
     directory.
811
812
    The file name can be either refer to an actual file on disk or to
813
    one of the application's embedded resources. See the
814
    \l{resources.html}{Resource System} overview for details on how to
815
    embed images and other resource files in the application's
816
    executable.
817
818
    Use the QImageReader::supportedImageFormats() and
819
    QImageWriter::supportedImageFormats() functions to retrieve a
820
    complete list of the supported file formats.
821
8a4934d by Norwegian Rock Cat at 2009-05-12 822
    Note: When you add a non-empty filename to a QIcon, the icon becomes
823
    non-null, even if the file doesn't exist or points to a corrupt file.
824
67ad051 by Lars Knoll at 2009-03-23 825
    \sa addPixmap()
826
 */
827
void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state)
828
{
829
    if (fileName.isEmpty())
830
        return;
831
    if (!d) {
832
#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
833
        QFileInfo info(fileName);
834
        QString suffix = info.suffix();
835
        if (!suffix.isEmpty()) {
836
            // first try version 2 engines..
837
            if (QIconEngineFactoryInterfaceV2 *factory = qobject_cast<QIconEngineFactoryInterfaceV2*>(loaderV2()->instance(suffix))) {
838
                if (QIconEngine *engine = factory->create(fileName)) {
839
                    d = new QIconPrivate;
840
                    d->engine = engine;
841
                }
842
            }
843
            // ..then fall back and try to load version 1 engines
844
            if (!d) {
845
                if (QIconEngineFactoryInterface *factory = qobject_cast<QIconEngineFactoryInterface*>(loader()->instance(suffix))) {
846
                    if (QIconEngine *engine = factory->create(fileName)) {
847
                        d = new QIconPrivate;
848
                        d->engine = engine;
849
                        d->engine_version = 1;
850
                        d->v1RefCount = new QAtomicInt(1);
851
                    }
852
                }
853
            }
854
        }
855
#endif
856
        // ...then fall back to the default engine
857
        if (!d) {
858
            d = new QIconPrivate;
859
            d->engine = new QPixmapIconEngine;
860
        }
861
    } else {
862
        detach();
863
    }
864
    d->engine->addFile(fileName, size, mode, state);
865
}
866
867
/*!
868
    \since 4.5
869
870
    Returns a list of available icon sizes for the specified \a mode and
871
    \a state.
872
*/
873
QList<QSize> QIcon::availableSizes(Mode mode, State state) const
874
{
875
    if (!d || !d->engine || d->engine_version < 2)
876
        return QList<QSize>();
877
    QIconEngineV2 *engine = static_cast<QIconEngineV2*>(d->engine);
878
    return engine->availableSizes(mode, state);
879
}
880
13a31fe by Jens Bache-Wiig at 2009-08-10 881
/*!
882
    \since 4.6
883
a675f83 by Volker Hilsheimer at 2009-08-10 884
    Sets the search paths for icon themes to \a paths.
72c1cb2 by Volker Hilsheimer at 2009-08-16 885
    \sa themeSearchPaths(), fromTheme(), setThemeName()
13a31fe by Jens Bache-Wiig at 2009-08-10 886
*/
887
void QIcon::setThemeSearchPaths(const QStringList &paths)
888
{
889
    QIconLoader::instance()->setThemeSearchPath(paths);
890
}
891
892
/*!
66fc433 by Martin Smith at 2009-09-02 893
  \since 4.6
13a31fe by Jens Bache-Wiig at 2009-08-10 894
66fc433 by Martin Smith at 2009-09-02 895
  Returns the search paths for icon themes.
13a31fe by Jens Bache-Wiig at 2009-08-10 896
66fc433 by Martin Smith at 2009-09-02 897
  The default value will depend on the platform:
13a31fe by Jens Bache-Wiig at 2009-08-10 898
66fc433 by Martin Smith at 2009-09-02 899
  On X11, the search path will use the XDG_DATA_DIRS environment
900
  variable if available.
13a31fe by Jens Bache-Wiig at 2009-08-10 901
66fc433 by Martin Smith at 2009-09-02 902
  By default all platforms will have the resource directory
903
  \c{:\icons} as a fallback. You can use "rcc -project" to generate a
904
  resource file from your icon theme.
13a31fe by Jens Bache-Wiig at 2009-08-10 905
66fc433 by Martin Smith at 2009-09-02 906
  \sa setThemeSearchPaths(), fromTheme(), setThemeName()
13a31fe by Jens Bache-Wiig at 2009-08-10 907
*/
908
QStringList QIcon::themeSearchPaths()
909
{
910
    return QIconLoader::instance()->themeSearchPaths();
911
}
912
913
/*!
914
    \since 4.6
915
72c1cb2 by Volker Hilsheimer at 2009-08-16 916
    Sets the current icon theme to \a name.
13a31fe by Jens Bache-Wiig at 2009-08-10 917
72c1cb2 by Volker Hilsheimer at 2009-08-16 918
    The \a name should correspond to a directory name in the
d82ab07 by Jens Bache-Wiig at 2009-08-11 919
    themeSearchPath() containing an index.theme
72c1cb2 by Volker Hilsheimer at 2009-08-16 920
    file describing it's contents.
13a31fe by Jens Bache-Wiig at 2009-08-10 921
72c1cb2 by Volker Hilsheimer at 2009-08-16 922
    \sa themeSearchPaths(), themeName()
13a31fe by Jens Bache-Wiig at 2009-08-10 923
*/
72c1cb2 by Volker Hilsheimer at 2009-08-16 924
void QIcon::setThemeName(const QString &name)
13a31fe by Jens Bache-Wiig at 2009-08-10 925
{
72c1cb2 by Volker Hilsheimer at 2009-08-16 926
    QIconLoader::instance()->setThemeName(name);
13a31fe by Jens Bache-Wiig at 2009-08-10 927
}
928
929
/*!
930
    \since 4.6
931
932
    Returns the name of the current icon theme.
933
934
    On X11, the current icon theme depends on your desktop
935
    settings. On other platforms it is not set by default.
936
72c1cb2 by Volker Hilsheimer at 2009-08-16 937
    \sa setThemeName(), themeSearchPaths(), fromTheme(),
938
    hasThemeIcon()
13a31fe by Jens Bache-Wiig at 2009-08-10 939
*/
940
QString QIcon::themeName()
941
{
942
    return QIconLoader::instance()->themeName();
943
}
944
945
/*!
946
    \since 4.6
947
948
    Returns the QIcon corresponding to \a name in the current
949
    icon theme. If no such icon is found in the current theme
950
    \a fallback is return instead.
951
952
    The lastest version of the freedesktop icon specification and naming
953
    spesification can be obtained here:
954
    http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
955
    http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
956
957
    To fetch an icon from the current icon theme:
958
959
    \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 3
960
961
    Or if you want to provide a guaranteed fallback for platforms that
962
    do not support theme icons, you can use the second argument:
963
964
    \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 4
965
966
    \note By default, only X11 will support themed icons. In order to
967
    use themed icons on Mac and Windows, you will have to bundle a
968
    compliant theme in one of your themeSearchPaths() and set the
969
    appropriate themeName().
970
72c1cb2 by Volker Hilsheimer at 2009-08-16 971
    \sa themeName(), setThemeName(), themeSearchPaths()
13a31fe by Jens Bache-Wiig at 2009-08-10 972
*/
973
QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback)
974
{
975
    QIcon icon;
976
dadfdfa by Trond Kjernåsen at 2010-02-09 977
    if (qtIconCache()->contains(name)) {
978
        icon = *qtIconCache()->object(name);
13a31fe by Jens Bache-Wiig at 2009-08-10 979
    } else {
980
        QIcon *cachedIcon  = new QIcon(new QIconLoaderEngine(name));
dadfdfa by Trond Kjernåsen at 2010-02-09 981
        qtIconCache()->insert(name, cachedIcon);
13a31fe by Jens Bache-Wiig at 2009-08-10 982
        icon = *cachedIcon;
983
    }
984
7727a43 by Jens Bache-Wiig at 2010-03-04 985
    // Note the qapp check is to allow lazy loading of static icons
986
    // Supporting fallbacks will not work for this case.
987
    if (qApp && icon.availableSizes().isEmpty())
13a31fe by Jens Bache-Wiig at 2009-08-10 988
        return fallback;
989
990
    return icon;
991
}
992
993
/*!
994
    \since 4.6
995
72c1cb2 by Volker Hilsheimer at 2009-08-16 996
    Returns true if there is an icon available for \a name in the
997
    current icon theme, otherwise returns false.
13a31fe by Jens Bache-Wiig at 2009-08-10 998
72c1cb2 by Volker Hilsheimer at 2009-08-16 999
    \sa themeSearchPaths(), fromTheme(), setThemeName()
13a31fe by Jens Bache-Wiig at 2009-08-10 1000
*/
1001
bool QIcon::hasThemeIcon(const QString &name)
1002
{
1003
    QIcon icon = fromTheme(name);
1004
1005
    return !icon.isNull();
1006
}
1007
1008
67ad051 by Lars Knoll at 2009-03-23 1009
/*****************************************************************************
1010
  QIcon stream functions
1011
 *****************************************************************************/
1012
#if !defined(QT_NO_DATASTREAM)
1013
/*!
1014
    \fn QDataStream &operator<<(QDataStream &stream, const QIcon &icon)
1015
    \relates QIcon
1016
    \since 4.2
1017
d13162d by Frederik Schwarzer at 2009-05-18 1018
    Writes the given \a icon to the given \a stream as a PNG
67ad051 by Lars Knoll at 2009-03-23 1019
    image. If the icon contains more than one image, all images will
1020
    be written to the stream. Note that writing the stream to a file
1021
    will not produce a valid image file.
1022
*/
1023
1024
QDataStream &operator<<(QDataStream &s, const QIcon &icon)
1025
{
1026
    if (s.version() >= QDataStream::Qt_4_3) {
1027
        if (icon.isNull()) {
1028
            s << QString();
1029
        } else {
1030
            if (icon.d->engine_version > 1) {
1031
                QIconEngineV2 *engine = static_cast<QIconEngineV2 *>(icon.d->engine);
1032
                s << engine->key();
1033
                engine->write(s);
1034
            } else {
1035
                // not really supported
1036
                qWarning("QIcon: Cannot stream QIconEngine. Use QIconEngineV2 instead.");
1037
            }
1038
        }
1039
    } else if (s.version() == QDataStream::Qt_4_2) {
1040
        if (icon.isNull()) {
1041
            s << 0;
1042
        } else {
1043
            QPixmapIconEngine *engine = static_cast<QPixmapIconEngine *>(icon.d->engine);
1044
            int num_entries = engine->pixmaps.size();
1045
            s << num_entries;
1046
            for (int i=0; i < num_entries; ++i) {
1047
                s << engine->pixmaps.at(i).pixmap;
1048
                s << engine->pixmaps.at(i).fileName;
1049
                s << engine->pixmaps.at(i).size;
1050
                s << (uint) engine->pixmaps.at(i).mode;
1051
                s << (uint) engine->pixmaps.at(i).state;
1052
            }
1053
        }
1054
    } else {
1055
        s << QPixmap(icon.pixmap(22,22));
1056
    }
1057
    return s;
1058
}
1059
1060
/*!
1061
    \fn QDataStream &operator>>(QDataStream &stream, QIcon &icon)
1062
    \relates QIcon
1063
    \since 4.2
1064
1065
    Reads an image, or a set of images, from the given \a stream into
1066
    the given \a icon.
1067
*/
1068
1069
QDataStream &operator>>(QDataStream &s, QIcon &icon)
1070
{
1071
    if (s.version() >= QDataStream::Qt_4_3) {
1072
        icon = QIcon();
1073
        QString key;
1074
        s >> key;
1075
        if (key == QLatin1String("QPixmapIconEngine")) {
1076
            icon.d = new QIconPrivate;
1077
            QIconEngineV2 *engine = new QPixmapIconEngine;
1078
            icon.d->engine = engine;
1079
            engine->read(s);
13a31fe by Jens Bache-Wiig at 2009-08-10 1080
        } else if (key == QLatin1String("QIconLoaderEngine")) {
1081
            icon.d = new QIconPrivate;
1082
            QIconEngineV2 *engine = new QIconLoaderEngine();
1083
            icon.d->engine = engine;
1084
            engine->read(s);
67ad051 by Lars Knoll at 2009-03-23 1085
#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
1086
        } else if (QIconEngineFactoryInterfaceV2 *factory = qobject_cast<QIconEngineFactoryInterfaceV2*>(loaderV2()->instance(key))) {
1087
            if (QIconEngineV2 *engine= factory->create()) {
1088
                icon.d = new QIconPrivate;
1089
                icon.d->engine = engine;
1090
                engine->read(s);
1091
            }
1092
#endif
1093
        }
1094
    } else if (s.version() == QDataStream::Qt_4_2) {
1095
        icon = QIcon();
1096
        int num_entries;
1097
        QPixmap pm;
1098
        QString fileName;
1099
        QSize sz;
1100
        uint mode;
1101
        uint state;
1102
1103
        s >> num_entries;
1104
        for (int i=0; i < num_entries; ++i) {
1105
            s >> pm;
1106
            s >> fileName;
1107
            s >> sz;
1108
            s >> mode;
1109
            s >> state;
1110
            if (pm.isNull())
1111
                icon.addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
1112
            else
1113
                icon.addPixmap(pm, QIcon::Mode(mode), QIcon::State(state));
1114
        }
1115
    } else {
1116
        QPixmap pm;
1117
        s >> pm;
1118
        icon.addPixmap(pm);
1119
    }
1120
    return s;
1121
}
1122
1123
#endif //QT_NO_DATASTREAM
1124
1125
1126
#ifdef QT3_SUPPORT
1127
1128
static int widths[2] = { 22, 32 };
1129
static int heights[2] = { 22, 32 };
1130
1131
static QSize pixmapSizeHelper(QIcon::Size which)
1132
{
1133
    int i = 0;
1134
    if (which == QIcon::Large)
1135
        i = 1;
1136
    return QSize(widths[i], heights[i]);
1137
}
1138
1139
/*!
1140
    \enum QIcon::Size
1141
    \compat
1142
1143
    \value Small  Use QStyle::pixelMetric(QStyle::PM_SmallIconSize) instead.
1144
    \value Large  Use QStyle::pixelMetric(QStyle::PM_LargeIconSize) instead.
1145
    \value Automatic  N/A.
1146
*/
1147
1148
/*!
1149
    Use pixmap(QSize(...), \a mode, \a state), where the first
1150
    argument is an appropriate QSize instead of a \l Size value.
1151
1152
    \sa pixmapSize()
1153
*/
1154
QPixmap QIcon::pixmap(Size size, Mode mode, State state) const
1155
{ return pixmap(pixmapSizeHelper(size), mode, state); }
1156
1157
/*!
1158
    Use pixmap(QSize(...), mode, \a state), where the first argument
1159
    is an appropriate QSize instead of a \l Size value, and the
1160
    second argument is QIcon::Normal or QIcon::Disabled, depending on
1161
    the value of \a enabled.
1162
1163
    \sa pixmapSize()
1164
*/
1165
QPixmap QIcon::pixmap(Size size, bool enabled, State state) const
1166
{ return pixmap(pixmapSizeHelper(size), enabled ? Normal : Disabled, state); }
1167
1168
/*!
1169
    Use one of the other pixmap() overloads.
1170
*/
1171
QPixmap QIcon::pixmap() const
1172
{ return pixmap(pixmapSizeHelper(Small), Normal, Off); }
1173
1174
/*!
1175
    The pixmap() function now takes a QSize instead of a QIcon::Size,
1176
    so there is no need for this function in new code.
1177
*/
1178
void QIcon::setPixmapSize(Size which, const QSize &size)
1179
{
1180
    int i = 0;
1181
    if (which == Large)
1182
        i = 1;
1183
    widths[i] = size.width();
1184
    heights[i] = size.height();
1185
}
1186
1187
/*!
1188
    Use QStyle::pixelMetric() with QStyle::PM_SmallIconSize or
1189
    QStyle::PM_LargeIconSize as the first argument, depending on \a
1190
    which.
1191
*/
1192
QSize QIcon::pixmapSize(Size which)
1193
{
1194
    return pixmapSizeHelper(which);
1195
}
1196
1197
/*!
1198
    \fn void QIcon::reset(const QPixmap &pixmap, Size size)
1199
1200
    Use the constructor that takes a QPixmap and operator=().
1201
*/
1202
1203
/*!
1204
    \fn void QIcon::setPixmap(const QPixmap &pixmap, Size size, Mode mode, State state)
1205
1206
    Use addPixmap(\a pixmap, \a mode, \a state) instead. The \a size
1207
    parameter is ignored.
1208
*/
1209
1210
/*!
1211
    \fn void QIcon::setPixmap(const QString &fileName, Size size, Mode mode, State state)
1212
1213
    Use addFile(\a fileName, \a mode, \a state) instead. The \a size
1214
    parameter is ignored.
1215
*/
1216
1217
#endif // QT3_SUPPORT
1218
1219
/*!
1220
    \fn DataPtr &QIcon::data_ptr()
1221
    \internal
1222
*/
1223
1224
/*!
1225
    \typedef QIcon::DataPtr
1226
    \internal
1227
*/
1228
1229
QT_END_NAMESPACE
fccbc9b by Jørgen Lind at 2009-10-29 1230
#endif //QT_NO_ICON