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

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

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 35.6 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
107static void qt_cleanup_icon_cache();
108typedef QCache<QString, QIcon> IconCache;
109Q_GLOBAL_STATIC_WITH_INITIALIZER(IconCache, qtIconCache, qAddPostRoutine(qt_cleanup_icon_cache))
110
111static void qt_cleanup_icon_cache()
112{
113 qtIconCache()->clear();
114}
115
116QIconPrivate::QIconPrivate()
117 : engine(0), ref(1),
118 serialNum(serialNumCounter.fetchAndAddRelaxed(1)),
119 detach_no(0),
120 engine_version(2),
121 v1RefCount(0)
122{
123}
124
125QPixmapIconEngine::QPixmapIconEngine()
126{
127}
128
129QPixmapIconEngine::QPixmapIconEngine(const QPixmapIconEngine &other)
130 : QIconEngineV2(other), pixmaps(other.pixmaps)
131{
132}
133
134QPixmapIconEngine::~QPixmapIconEngine()
135{
136}
137
138void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
139{
140 QSize pixmapSize = rect.size();
141#if defined(Q_WS_MAC)
142 pixmapSize *= qt_mac_get_scalefactor();
143#endif
144 painter->drawPixmap(rect, pixmap(pixmapSize, mode, state));
145}
146
147static 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.
150static 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
173QPixmapIconEngineEntry *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
187QPixmapIconEngineEntry *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
239QPixmap 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)
267 + QString::number(QApplication::palette().cacheKey())
268 + QLatin1Char('_')
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
302QSize 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
316void 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
329void 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
363QString QPixmapIconEngine::key() const
364{
365 return QLatin1String("QPixmapIconEngine");
366}
367
368QIconEngineV2 *QPixmapIconEngine::clone() const
369{
370 return new QPixmapIconEngine(*this);
371}
372
373bool 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;
393 if (pm.isNull()) {
394 addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
395 } else {
396 QPixmapIconEngineEntry pe(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
397 pe.pixmap = pm;
398 pixmaps += pe;
399 }
400 }
401 return true;
402}
403
404bool 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
421void 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)
445Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
446 (QIconEngineFactoryInterface_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive))
447Q_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
459 \ingroup painting
460 \ingroup shared
461
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*/
522QIcon::QIcon()
523 : d(0)
524{
525}
526
527/*!
528 Constructs an icon from a \a pixmap.
529 */
530QIcon::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*/
539QIcon::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*/
564QIcon::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*/
575QIcon::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*/
587QIcon::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*/
597QIcon::~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*/
607QIcon &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*/
620QIcon::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
642int 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*/
660qint64 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*/
674QPixmap 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*/
705QSize 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*/
719void 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*/
744bool QIcon::isNull() const
745{
746 return !d;
747}
748
749/*!\internal
750 */
751bool QIcon::isDetached() const
752{
753 return !d || d->ref == 1;
754}
755
756/*! \internal
757 */
758void 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*/
789void 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
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
825 \sa addPixmap()
826 */
827void 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*/
873QList<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
881/*!
882 \since 4.6
883
884 Sets the search paths for icon themes to \a paths.
885 \sa themeSearchPaths(), fromTheme(), setThemeName()
886*/
887void QIcon::setThemeSearchPaths(const QStringList &paths)
888{
889 QIconLoader::instance()->setThemeSearchPath(paths);
890}
891
892/*!
893 \since 4.6
894
895 Returns the search paths for icon themes.
896
897 The default value will depend on the platform:
898
899 On X11, the search path will use the XDG_DATA_DIRS environment
900 variable if available.
901
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.
905
906 \sa setThemeSearchPaths(), fromTheme(), setThemeName()
907*/
908QStringList QIcon::themeSearchPaths()
909{
910 return QIconLoader::instance()->themeSearchPaths();
911}
912
913/*!
914 \since 4.6
915
916 Sets the current icon theme to \a name.
917
918 The \a name should correspond to a directory name in the
919 themeSearchPath() containing an index.theme
920 file describing it's contents.
921
922 \sa themeSearchPaths(), themeName()
923*/
924void QIcon::setThemeName(const QString &name)
925{
926 QIconLoader::instance()->setThemeName(name);
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
937 \sa setThemeName(), themeSearchPaths(), fromTheme(),
938 hasThemeIcon()
939*/
940QString 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
971 \sa themeName(), setThemeName(), themeSearchPaths()
972*/
973QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback)
974{
975 QIcon icon;
976
977 if (qtIconCache()->contains(name)) {
978 icon = *qtIconCache()->object(name);
979 } else {
980 QIcon *cachedIcon = new QIcon(new QIconLoaderEngine(name));
981 qtIconCache()->insert(name, cachedIcon);
982 icon = *cachedIcon;
983 }
984
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())
988 return fallback;
989
990 return icon;
991}
992
993/*!
994 \since 4.6
995
996 Returns true if there is an icon available for \a name in the
997 current icon theme, otherwise returns false.
998
999 \sa themeSearchPaths(), fromTheme(), setThemeName()
1000*/
1001bool QIcon::hasThemeIcon(const QString &name)
1002{
1003 QIcon icon = fromTheme(name);
1004
1005 return !icon.isNull();
1006}
1007
1008
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
1018 Writes the given \a icon to the given \a stream as a PNG
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
1024QDataStream &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
1069QDataStream &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);
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);
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
1128static int widths[2] = { 22, 32 };
1129static int heights[2] = { 22, 32 };
1130
1131static 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*/
1154QPixmap 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*/
1165QPixmap 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*/
1171QPixmap 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*/
1178void 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*/
1192QSize 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
1229QT_END_NAMESPACE
1230#endif //QT_NO_ICON
Note: See TracBrowser for help on using the repository browser.