source: trunk/src/gui/image/qicon.cpp@ 106

Last change on this file since 106 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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