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

Last change on this file since 1147 was 846, checked in by Dmitry A. Kuminov, 14 years ago

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

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