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

Last change on this file since 763 was 763, checked in by Dmitry A. Kuminov, 15 years ago

gui: Reverter r261 as it breaks cross-platform compatibility with applications not providing consistent icon sizes.

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