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

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

trunk: Merged in qt 4.6.2 sources.

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