• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.0 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • kdeui
  • icons
kiconloader.cpp
Go to the documentation of this file.
1 /* vi: ts=8 sts=4 sw=4
2  *
3  * kiconloader.cpp: An icon loader for KDE with theming functionality.
4  *
5  * This file is part of the KDE project, module kdeui.
6  * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
7  * Antonio Larrosa <larrosa@kde.org>
8  * 2010 Michael Pyne <mpyne@kde.org>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License version 2 as published by the Free Software Foundation.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB. If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 #include "kiconloader.h"
26 
27 #include <sys/types.h>
28 #include <stdlib.h> //for abs
29 #include <unistd.h> //for readlink
30 #include <dirent.h>
31 #include <assert.h>
32 
33 #include <QtCore/QCache>
34 #include <QtCore/QFileInfo>
35 #include <QtCore/QDir>
36 #include <QtCore/QBuffer>
37 #include <QtCore/QDataStream>
38 #include <QtCore/QByteArray>
39 #include <QtCore/QStringBuilder> // % operator for QString
40 #include <QtGui/QIcon>
41 #include <QtGui/QImage>
42 #include <QtGui/QMovie>
43 #include <QtGui/QPainter>
44 #include <QtGui/QPixmap>
45 #include <QtGui/QPixmapCache>
46 #ifndef _WIN32_WCE
47 #include <QtSvg/QSvgRenderer>
48 #endif
49 
50 // kdecore
51 #include <kconfig.h>
52 #include <kconfiggroup.h>
53 #include <kdebug.h>
54 #include <kstandarddirs.h>
55 #include <kglobal.h>
56 #include <kglobalsettings.h>
57 #include <kcomponentdata.h>
58 #include <kde_file.h>
59 #include <kshareddatacache.h>
60 
61 // kdeui
62 #include "kicontheme.h"
63 #include "kiconeffect.h"
64 #include "k3icon_p.h"
65 
66 // Used to make cache keys for icons with no group. Result type is QString*
67 K_GLOBAL_STATIC_WITH_ARGS(QString, NULL_EFFECT_FINGERPRINT, (QString::fromLatin1("noeffect")))
68 
69 // Qt implements Tiny SVG specification. This specification does not cover important elements
70 // that are pretty globally used on our icons, like blurring (and other filters). TT seems to have
71 // no interest in supporting the full SVG specification (it would be slower, even with JS, CSS
72 // support...). So, we have no chance for now. Let's disable svg rendering unconditionally.
73 // (ereslibre)
74 #undef KDE_QT_SVG_RENDERER_FIXED
75 
79 static bool pathIsRelative(const QString &path)
80 {
81 #ifdef Q_OS_UNIX
82  return (!path.isEmpty() && path[0] != QChar('/'));
83 #else
84  return QDir::isRelativePath(path);
85 #endif
86 }
87 
91 struct PixmapWithPath
92 {
93  QPixmap pixmap;
94  QString path;
95 };
96 
97 /*** KIconThemeNode: A node in the icon theme dependancy tree. ***/
98 
99 class KIconThemeNode
100 {
101 public:
102 
103  KIconThemeNode(KIconTheme *_theme);
104  ~KIconThemeNode();
105 
106  void queryIcons(QStringList *lst, int size, KIconLoader::Context context) const;
107  void queryIconsByContext(QStringList *lst, int size, KIconLoader::Context context) const;
108  K3Icon findIcon(const QString& name, int size, KIconLoader::MatchType match) const;
109  void printTree(QString& dbgString) const;
110 
111  KIconTheme *theme;
112 };
113 
114 KIconThemeNode::KIconThemeNode(KIconTheme *_theme)
115 {
116  theme = _theme;
117 }
118 
119 KIconThemeNode::~KIconThemeNode()
120 {
121  delete theme;
122 }
123 
124 void KIconThemeNode::printTree(QString& dbgString) const
125 {
126  /* This method doesn't have much sense anymore, so maybe it should
127  be removed in the (near?) future */
128  dbgString += '(';
129  dbgString += theme->name();
130  dbgString += ')';
131 }
132 
133 void KIconThemeNode::queryIcons(QStringList *result,
134  int size, KIconLoader::Context context) const
135 {
136  // add the icons of this theme to it
137  *result += theme->queryIcons(size, context);
138 }
139 
140 void KIconThemeNode::queryIconsByContext(QStringList *result,
141  int size, KIconLoader::Context context) const
142 {
143  // add the icons of this theme to it
144  *result += theme->queryIconsByContext(size, context);
145 }
146 
147 K3Icon KIconThemeNode::findIcon(const QString& name, int size,
148  KIconLoader::MatchType match) const
149 {
150  return theme->iconPath(name, size, match);
151 }
152 
153 
154 /*** KIconGroup: Icon type description. ***/
155 
156 struct KIconGroup
157 {
158  int size;
159  bool alphaBlending;
160 };
161 
162 
163 /*** d pointer for KIconLoader. ***/
164 class KIconLoaderPrivate
165 {
166 public:
167  KIconLoaderPrivate(KIconLoader *q)
168  : q(q)
169  , mpGroups(0)
170  , mIconCache(0)
171  {
172  }
173 
174  ~KIconLoaderPrivate()
175  {
176  /* antlarr: There's no need to delete d->mpThemeRoot as it's already
177  deleted when the elements of d->links are deleted */
178  qDeleteAll(links);
179  delete[] mpGroups;
180  delete mIconCache;
181  }
182 
186  void init( const QString& _appname, KStandardDirs *_dirs );
187 
191  bool initIconThemes();
192 
198  K3Icon findMatchingIcon(const QString& name, int size) const;
199 
206  K3Icon findMatchingIconWithGenericFallbacks(const QString& name, int size) const;
207 
212  void addAppThemes(const QString& appname);
213 
219  void addBaseThemes(KIconThemeNode *node, const QString &appname);
220 
226  void addInheritedThemes(KIconThemeNode *node, const QString &appname);
227 
234  void addThemeByName(const QString &themename, const QString &appname);
235 
240  QString unknownIconPath( int size ) const;
241 
246  QString removeIconExtension(const QString &name) const;
247 
254  void normalizeIconMetadata(KIconLoader::Group &group, int &size, int &state) const;
255 
261  QString makeCacheKey(const QString &name, KIconLoader::Group group, const QStringList &overlays,
262  int size, int state) const;
263 
270  QImage createIconImage(const QString &path, int size = 0);
271 
276  void insertCachedPixmapWithPath(const QString &key, const QPixmap &data, const QString &path);
277 
283  bool findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path);
284 
285  KIconLoader *const q;
286 
287  QStringList mThemesInTree;
288  KIconGroup *mpGroups;
289  KIconThemeNode *mpThemeRoot;
290  KStandardDirs *mpDirs;
291  KIconEffect mpEffect;
292  QList<KIconThemeNode *> links;
293 
294  // This shares the icons across all processes
295  KSharedDataCache* mIconCache;
296 
297  // This caches rendered QPixmaps in just this process.
298  QCache<QString, PixmapWithPath> mPixmapCache;
299 
300  bool extraDesktopIconsLoaded :1;
301  // lazy loading: initIconThemes() is only needed when the "links" list is needed
302  // mIconThemeInited is used inside initIconThemes() to init only once
303  bool mIconThemeInited :1;
304  QString appname;
305 
306  void drawOverlays(const KIconLoader *loader, KIconLoader::Group group, int state, QPixmap& pix, const QStringList& overlays);
307 };
308 
309 class KIconLoaderGlobalData
310 {
311 public:
312  KIconLoaderGlobalData() {
313  const QStringList genericIconsFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "generic-icons");
314  //kDebug() << genericIconsFiles;
315  Q_FOREACH(const QString& file, genericIconsFiles) {
316  parseGenericIconsFiles(file);
317  }
318  }
319 
320  QString genericIconFor(const QString& icon) const {
321  return m_genericIcons.value(icon);
322  }
323 
324 private:
325  void parseGenericIconsFiles(const QString& fileName);
326  QHash<QString, QString> m_genericIcons;
327 };
328 
329 void KIconLoaderGlobalData::parseGenericIconsFiles(const QString& fileName)
330 {
331  QFile file(fileName);
332  if (file.open(QIODevice::ReadOnly)) {
333  QTextStream stream(&file);
334  stream.setCodec("ISO 8859-1");
335  while (!stream.atEnd()) {
336  const QString line = stream.readLine();
337  if (line.isEmpty() || line[0] == '#')
338  continue;
339  const int pos = line.indexOf(':');
340  if (pos == -1) // syntax error
341  continue;
342  QString mimeIcon = line.left(pos);
343  const int slashindex = mimeIcon.indexOf(QLatin1Char('/'));
344  if (slashindex != -1) {
345  mimeIcon[slashindex] = QLatin1Char('-');
346  }
347 
348  const QString genericIcon = line.mid(pos+1);
349  m_genericIcons.insert(mimeIcon, genericIcon);
350  //kDebug(264) << mimeIcon << "->" << genericIcon;
351  }
352  }
353 }
354 
355 K_GLOBAL_STATIC(KIconLoaderGlobalData, s_globalData)
356 
357 void KIconLoaderPrivate::drawOverlays(const KIconLoader *iconLoader, KIconLoader::Group group, int state, QPixmap& pix, const QStringList& overlays)
358 {
359  if (overlays.isEmpty()) {
360  return;
361  }
362 
363  const int width = pix.size().width();
364  const int height = pix.size().height();
365  const int iconSize = qMin(width, height);
366  int overlaySize;
367 
368  if (iconSize < 32) {
369  overlaySize = 8;
370  } else if (iconSize <= 48) {
371  overlaySize = 16;
372  } else if (iconSize <= 96) {
373  overlaySize = 22;
374  } else if (iconSize < 256) {
375  overlaySize = 32;
376  } else {
377  overlaySize = 64;
378  }
379 
380  QPainter painter(&pix);
381 
382  int count = 0;
383  foreach (const QString& overlay, overlays) {
384  // Ensure empty strings fill up a emblem spot
385  // Needed when you have several emblems to ensure they're always painted
386  // at the same place, even if one is not here
387  if (overlay.isEmpty()) {
388  ++count;
389  continue;
390  }
391 
392  //TODO: should we pass in the kstate? it results in a slower
393  // path, and perhaps emblems should remain in the default state
394  // anyways?
395  const QPixmap pixmap = iconLoader->loadIcon(overlay, group, overlaySize, state, QStringList(), 0, true);
396 
397  if (pixmap.isNull()) {
398  continue;
399  }
400 
401  QPoint startPoint;
402  switch (count) {
403  case 0:
404  // bottom left corner
405  startPoint = QPoint(2, height - overlaySize - 2);
406  break;
407  case 1:
408  // bottom right corner
409  startPoint = QPoint(width - overlaySize - 2,
410  height - overlaySize - 2);
411  break;
412  case 2:
413  // top right corner
414  startPoint = QPoint(width - overlaySize - 2, 2);
415  break;
416  case 3:
417  // top left corner
418  startPoint = QPoint(2, 2);
419  break;
420  }
421 
422  painter.drawPixmap(startPoint, pixmap);
423 
424  ++count;
425  if (count > 3) {
426  break;
427  }
428  }
429 }
430 
431 KIconLoader::KIconLoader(const QString& _appname, KStandardDirs *_dirs, QObject* parent)
432  : QObject(parent)
433 {
434  setObjectName(_appname);
435  d = new KIconLoaderPrivate(this);
436 
437  connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
438  this, SLOT(newIconLoader()));
439  d->init( _appname, _dirs );
440 }
441 
442 KIconLoader::KIconLoader(const KComponentData &componentData, QObject* parent)
443  : QObject(parent)
444 {
445  setObjectName(componentData.componentName());
446  d = new KIconLoaderPrivate(this);
447 
448  connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
449  this, SLOT(newIconLoader()));
450  d->init(componentData.componentName(), componentData.dirs());
451 }
452 
453 void KIconLoader::reconfigure( const QString& _appname, KStandardDirs *_dirs )
454 {
455  d->mIconCache->clear();
456  delete d;
457  d = new KIconLoaderPrivate(this);
458  d->init( _appname, _dirs );
459 }
460 
461 void KIconLoaderPrivate::init( const QString& _appname, KStandardDirs *_dirs )
462 {
463  extraDesktopIconsLoaded=false;
464  mIconThemeInited = false;
465  mpThemeRoot = 0;
466 
467  if (_dirs)
468  mpDirs = _dirs;
469  else
470  mpDirs = KGlobal::dirs();
471 
472  appname = _appname;
473  if (appname.isEmpty())
474  appname = KGlobal::mainComponent().componentName();
475 
476  // Initialize icon cache
477  mIconCache = new KSharedDataCache("icon-cache", 10 * 1024 * 1024);
478  // Cost here is number of pixels, not size. So this is actually a bit
479  // smaller.
480  mPixmapCache.setMaxCost(10 * 1024 * 1024);
481 
482  // These have to match the order in kicontheme.h
483  static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", "Dialog", 0L };
484  KSharedConfig::Ptr config = KGlobal::config();
485 
486  // loading config and default sizes
487  initIconThemes();
488  KIconTheme *defaultSizesTheme = links.empty() ? 0 : links.first()->theme;
489  mpGroups = new KIconGroup[(int) KIconLoader::LastGroup];
490  for (KIconLoader::Group i = KIconLoader::FirstGroup; i < KIconLoader::LastGroup; ++i) {
491  if (groups[i] == 0L) {
492  break;
493  }
494 
495  KConfigGroup cg(config, QLatin1String(groups[i]) + "Icons");
496  mpGroups[i].size = cg.readEntry("Size", 0);
497  if (QPixmap::defaultDepth() > 8) {
498  mpGroups[i].alphaBlending = cg.readEntry("AlphaBlending", true);
499  } else {
500  mpGroups[i].alphaBlending = false;
501  }
502 
503  if (!mpGroups[i].size && defaultSizesTheme) {
504  mpGroups[i].size = defaultSizesTheme->defaultSize(i);
505  }
506  }
507 }
508 
509 bool KIconLoaderPrivate::initIconThemes()
510 {
511  if (mIconThemeInited) {
512  // If mpThemeRoot isn't 0 then initing has succeeded
513  return (mpThemeRoot != 0);
514  }
515  //kDebug(264);
516  mIconThemeInited = true;
517 
518  // Add the default theme and its base themes to the theme tree
519  KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
520  if (!def->isValid())
521  {
522  delete def;
523  // warn, as this is actually a small penalty hit
524  kDebug(264) << "Couldn't find current icon theme, falling back to default.";
525  def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
526  if (!def->isValid())
527  {
528  kError(264) << "Error: standard icon theme" << KIconTheme::defaultThemeName() << "not found!" << endl;
529  delete def;
530  return false;
531  }
532  }
533  mpThemeRoot = new KIconThemeNode(def);
534  mThemesInTree.append(def->internalName());
535  links.append(mpThemeRoot);
536  addBaseThemes(mpThemeRoot, appname);
537 
538  // Insert application specific themes at the top.
539  mpDirs->addResourceType("appicon", "data", appname + "/pics/");
540  // ################## KDE5: consider removing the toolbar directory
541  mpDirs->addResourceType("appicon", "data", appname + "/toolbar/");
542 
543  // Add legacy icon dirs.
544  QStringList dirs;
545  dirs += mpDirs->resourceDirs("icon");
546  dirs += mpDirs->resourceDirs("pixmap");
547  dirs += mpDirs->resourceDirs("xdgdata-icon");
548  dirs += "/usr/share/pixmaps";
549  // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
550  dirs += mpDirs->resourceDirs("xdgdata-pixmap");
551  for (QStringList::ConstIterator it = dirs.constBegin(); it != dirs.constEnd(); ++it)
552  mpDirs->addResourceDir("appicon", *it);
553 
554 #ifndef NDEBUG
555  QString dbgString = "Theme tree: ";
556  mpThemeRoot->printTree(dbgString);
557  kDebug(264) << dbgString;
558 #endif
559 
560  return true;
561 }
562 
563 KIconLoader::~KIconLoader()
564 {
565  delete d;
566 }
567 
568 void KIconLoader::addAppDir(const QString& appname)
569 {
570  d->initIconThemes();
571 
572  d->mpDirs->addResourceType("appicon", "data", appname + "/pics/");
573  // ################## KDE5: consider removing the toolbar directory
574  d->mpDirs->addResourceType("appicon", "data", appname + "/toolbar/");
575  d->addAppThemes(appname);
576 }
577 
578 void KIconLoaderPrivate::addAppThemes(const QString& appname)
579 {
580  initIconThemes();
581 
582  KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
583  if (!def->isValid()) {
584  delete def;
585  def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
586  }
587  KIconThemeNode* node = new KIconThemeNode(def);
588  bool addedToLinks = false;
589 
590  if (!mThemesInTree.contains(node->theme->internalName())) {
591  mThemesInTree.append(node->theme->internalName());
592  links.append(node);
593  addedToLinks = true;
594  }
595  addBaseThemes(node, appname);
596 
597  if (!addedToLinks) {
598  // Nodes in links are being deleted later - this one needs manual care.
599  delete node;
600  }
601 }
602 
603 void KIconLoaderPrivate::addBaseThemes(KIconThemeNode *node, const QString &appname)
604 {
605  // Quote from the icon theme specification:
606  // The lookup is done first in the current theme, and then recursively
607  // in each of the current theme's parents, and finally in the
608  // default theme called "hicolor" (implementations may add more
609  // default themes before "hicolor", but "hicolor" must be last).
610  //
611  // So we first make sure that all inherited themes are added, then we
612  // add the KDE default theme as fallback for all icons that might not be
613  // present in an inherited theme, and hicolor goes last.
614 
615  addInheritedThemes(node, appname);
616  addThemeByName(KIconTheme::defaultThemeName(), appname);
617  addThemeByName("hicolor", appname);
618 }
619 
620 void KIconLoaderPrivate::addInheritedThemes(KIconThemeNode *node, const QString &appname)
621 {
622  const QStringList lst = node->theme->inherits();
623 
624  for (QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) {
625  if ((*it) == "hicolor") {
626  // The icon theme spec says that "hicolor" must be the very last
627  // of all inherited themes, so don't add it here but at the very end
628  // of addBaseThemes().
629  continue;
630  }
631  addThemeByName(*it, appname);
632  }
633 }
634 
635 void KIconLoaderPrivate::addThemeByName(const QString &themename, const QString &appname)
636 {
637  if (mThemesInTree.contains(themename + appname)) {
638  return;
639  }
640  KIconTheme *theme = new KIconTheme(themename, appname);
641  if (!theme->isValid()) {
642  delete theme;
643  return;
644  }
645  KIconThemeNode *n = new KIconThemeNode(theme);
646  mThemesInTree.append(themename + appname);
647  links.append(n);
648  addInheritedThemes(n, appname);
649 }
650 
651 void KIconLoader::addExtraDesktopThemes()
652 {
653  if ( d->extraDesktopIconsLoaded ) return;
654 
655  d->initIconThemes();
656 
657  QStringList list;
658  const QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
659  QStringList::ConstIterator it;
660  char buf[1000];
661  int r;
662  for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
663  {
664  QDir dir(*it);
665  if (!dir.exists())
666  continue;
667  const QStringList lst = dir.entryList(QStringList( "default.*" ), QDir::Dirs);
668  QStringList::ConstIterator it2;
669  for (it2=lst.begin(); it2!=lst.end(); ++it2)
670  {
671  if (!KStandardDirs::exists(*it + *it2 + "/index.desktop")
672  && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
673  continue;
674  r=readlink( QFile::encodeName(*it + *it2) , buf, sizeof(buf)-1);
675  if ( r>0 )
676  {
677  buf[r]=0;
678  const QDir dir2( buf );
679  QString themeName=dir2.dirName();
680 
681  if (!list.contains(themeName))
682  list.append(themeName);
683  }
684  }
685  }
686 
687  for (it = list.constBegin(); it != list.constEnd(); ++it)
688  {
689  // Don't add the KDE defaults once more, we have them anyways.
690  if (*it == QLatin1String("default.kde")
691  || *it == QLatin1String("default.kde4")) {
692  continue;
693  }
694  d->addThemeByName(*it, "");
695  }
696 
697  d->extraDesktopIconsLoaded=true;
698 
699 }
700 
701 bool KIconLoader::extraDesktopThemesAdded() const
702 {
703  return d->extraDesktopIconsLoaded;
704 }
705 
706 void KIconLoader::drawOverlays(const QStringList &overlays, QPixmap &pixmap, KIconLoader::Group group, int state) const
707 {
708  d->drawOverlays(this, group, state, pixmap, overlays);
709 }
710 
711 QString KIconLoaderPrivate::removeIconExtension(const QString &name) const
712 {
713  if (name.endsWith(QLatin1String(".png"))
714  || name.endsWith(QLatin1String(".xpm"))
715  || name.endsWith(QLatin1String(".svg"))) {
716  return name.left(name.length() - 4);
717  } else if (name.endsWith(QLatin1String(".svgz"))) {
718  return name.left(name.length() - 5);
719  }
720 
721  return name;
722 }
723 
724 void KIconLoaderPrivate::normalizeIconMetadata(KIconLoader::Group &group, int &size, int &state) const
725 {
726  if ((state < 0) || (state >= KIconLoader::LastState))
727  {
728  kWarning(264) << "Illegal icon state: " << state;
729  state = KIconLoader::DefaultState;
730  }
731 
732  if (size < 0) {
733  size = 0;
734  }
735 
736  // For "User" icons, bail early since the size should be based on the size on disk,
737  // which we've already checked.
738  if (group == KIconLoader::User) {
739  return;
740  }
741 
742  if ((group < -1) || (group >= KIconLoader::LastGroup))
743  {
744  kWarning(264) << "Illegal icon group: " << group;
745  group = KIconLoader::Desktop;
746  }
747 
748  // If size == 0, use default size for the specified group.
749  if (size == 0)
750  {
751  if (group < 0)
752  {
753  kWarning(264) << "Neither size nor group specified!";
754  group = KIconLoader::Desktop;
755  }
756  size = mpGroups[group].size;
757  }
758 }
759 
760 QString KIconLoaderPrivate::makeCacheKey(const QString &name, KIconLoader::Group group,
761  const QStringList &overlays, int size, int state) const
762 {
763  // The KSharedDataCache is shared so add some namespacing. The following code
764  // uses QStringBuilder (new in Qt 4.6)
765 
766  return (group == KIconLoader::User
767  ? QLatin1Literal("$kicou_")
768  : QLatin1Literal("$kico_"))
769  % name
770  % QLatin1Char('_')
771  % QString::number(size)
772  % QLatin1Char('_')
773  % overlays.join("_")
774  % ( group >= 0 ? mpEffect.fingerprint(group, state)
775  : *NULL_EFFECT_FINGERPRINT);
776 }
777 
778 QImage KIconLoaderPrivate::createIconImage(const QString &path, int size)
779 {
780  // Use the extension as the format. Works for XPM and PNG, but not for SVG. The
781  // "VGZ" is the last 3 characters of "SVGZ"
782  QString ext = path.right(3).toUpper();
783  QImage img;
784 
785  if (ext != "SVG" && ext != "VGZ")
786  {
787  // Not a SVG or SVGZ
788  img = QImage(path, ext.toLatin1());
789 
790  if (size != 0 && !img.isNull()) {
791  img = img.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
792  }
793  }
794  else
795  {
796 #ifndef _WIN32_WCE
797  QSvgRenderer renderer(path, q);
798 
799  if (renderer.isValid()) {
800  img = QImage(size, size, QImage::Format_ARGB32_Premultiplied);
801  img.fill(0);
802  QPainter p(&img);
803  renderer.render(&p);
804  }
805 #endif
806  }
807 
808  return img;
809 }
810 
811 void KIconLoaderPrivate::insertCachedPixmapWithPath(
812  const QString &key,
813  const QPixmap &data,
814  const QString &path = QString())
815 {
816  // Even if the pixmap is null, we add it to the caches so that we record
817  // the fact that whatever icon led to us getting a null pixmap doesn't
818  // exist.
819 
820  QBuffer output;
821  output.open(QIODevice::WriteOnly);
822 
823  QDataStream outputStream(&output);
824  outputStream.setVersion(QDataStream::Qt_4_6);
825 
826  outputStream << path;
827 
828  // Convert the QPixmap to PNG. This is actually done by Qt's own operator.
829  outputStream << data;
830 
831  output.close();
832 
833  // The byte array contained in the QBuffer is what we want in the cache.
834  mIconCache->insert(key, output.buffer());
835 
836  // Also insert the object into our process-local cache for even more
837  // speed.
838  PixmapWithPath *pixmapPath = new PixmapWithPath;
839  pixmapPath->pixmap = data;
840  pixmapPath->path = path;
841 
842  mPixmapCache.insert(key, pixmapPath, data.width() * data.height() + 1);
843 }
844 
845 bool KIconLoaderPrivate::findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path)
846 {
847  // If the pixmap is present in our local process cache, use that since we
848  // don't need to decompress and upload it to the X server/graphics card.
849  const PixmapWithPath *pixmapPath = mPixmapCache.object(key);
850  if (pixmapPath) {
851  path = pixmapPath->path;
852  data = pixmapPath->pixmap;
853 
854  return true;
855  }
856 
857  // Otherwise try to find it in our shared memory cache since that will
858  // be quicker than the disk, especially for SVGs.
859  QByteArray result;
860 
861  if (!mIconCache->find(key, &result) || result.isEmpty()) {
862  return false;
863  }
864 
865  QBuffer buffer;
866  buffer.setBuffer(&result);
867  buffer.open(QIODevice::ReadOnly);
868 
869  QDataStream inputStream(&buffer);
870  inputStream.setVersion(QDataStream::Qt_4_6);
871 
872  QString tempPath;
873  inputStream >> tempPath;
874 
875  if (inputStream.status() == QDataStream::Ok) {
876  QPixmap tempPixmap;
877  inputStream >> tempPixmap;
878 
879  if (inputStream.status() == QDataStream::Ok) {
880  data = tempPixmap;
881  path = tempPath;
882 
883  // Since we're here we didn't have a QPixmap cache entry, add one now.
884  PixmapWithPath *newPixmapWithPath = new PixmapWithPath;
885  newPixmapWithPath->pixmap = data;
886  newPixmapWithPath->path = path;
887 
888  mPixmapCache.insert(key, newPixmapWithPath, data.width() * data.height() + 1);
889 
890  return true;
891  }
892  }
893 
894  return false;
895 }
896 
897 K3Icon KIconLoaderPrivate::findMatchingIconWithGenericFallbacks(const QString& name, int size) const
898 {
899  K3Icon icon = findMatchingIcon(name, size);
900  if (icon.isValid())
901  return icon;
902 
903  const QString genericIcon = s_globalData->genericIconFor(name);
904  if (!genericIcon.isEmpty()) {
905  icon = findMatchingIcon(genericIcon, size);
906  }
907  return icon;
908 }
909 
910 K3Icon KIconLoaderPrivate::findMatchingIcon(const QString& name, int size) const
911 {
912  const_cast<KIconLoaderPrivate*>(this)->initIconThemes();
913 
914  K3Icon icon;
915 
916 // The following code has been commented out because the Qt SVG renderer needs
917 // to be improved. If you are going to change/remove some code from this part,
918 // please contact me before (ereslibre@kde.org), or kde-core-devel@kde.org. (ereslibre)
919 #ifdef KDE_QT_SVG_RENDERER_FIXED
920  const char * ext1[4] = { ".png", ".svgz", ".svg", ".xpm" };
921  const char * ext2[4] = { ".svgz", ".svg", ".png", ".xpm" };
922  const char ** ext;
923 
924  if (size == KIconLoader::SizeSmall ||
925  size == KIconLoader::SizeSmallMedium ||
926  size == KIconLoader::SizeMedium ||
927  size == KIconLoader::SizeLarge ||
928  size == KIconLoader::SizeHuge ||
929  size == KIconLoader::SizeEnormous)
930  {
931  ext = ext1; // size is standard, give preference to PNG over SVG when searching
932  }
933  else
934  {
935  ext = ext2; // size is non-standard, give preference to SVG over PNG when searching
936  }
937 
938  /* If size parameter is a standard one, that means:
939 
940  - KIconLoader::SizeSmall
941  - KIconLoader::SizeSmallMedium
942  - KIconLoader::SizeMedium
943  - KIconLoader::SizeLarge
944  - KIconLoader::SizeHuge
945  - KIconLoader::SizeEnormous
946 
947  To follow the XDG icon theme and icon naming specifications,
948  the order in which we look for an icon is:
949 
950  png, svgz, svg, xpm exact match
951  png, svgz, svg, xpm best match
952  less specific fallback in this theme: png, svgz, svg, xpm exact match
953  png, svgz, svg, xpm best match
954  even less specific fallback in this theme: [same order]
955  (...)
956 
957  next theme in inheritance tree: png, svgz, svg, xpm exact match
958  png, svgz, svg, xpm best match
959  less specific fallbacks in this next theme
960  (...)
961 
962  next theme in inheritance tree: png, svgz, svg, xpm exact match
963  png, svgz, svg, xpm best match
964  less specific fallbacks in this next theme
965  (...)
966 
967  and so on.
968 
969  If size parameter is a non-standard one, then we give more preference to
970  SVG format since drawing SVG's gives better quality and despite being
971  slower than resizing a PNG image, the cases where non-standard sizes are
972  asked are very rare. For non-standard sizes what we have is:
973 
974  svgz, svg, png, xpm exact match
975  svgz, svg, png, xpm best match
976  less specific fallback in this theme: svgz, svg, png, xpm exact match
977  svgz, svg, png, xpm best match
978  even less specific fallback in this theme: [same order]
979  (...)
980 
981  next theme in inheritance tree: svgz, svg, png, xpm exact match
982  svgz, svg, png, xpm best match
983  less specific fallbacks in this next theme
984  (...)
985 
986  next theme in inheritance tree: svgz, svg, png, xpm exact match
987  svgz, svg, png, xpm best match
988  less specific fallbacks in this next theme
989  (...)
990 
991  and so on.
992  */
993 #else
994  const char * const ext[4] = { ".png", ".svgz", ".svg", ".xpm" };
995 #endif
996 
997  bool genericFallback = name.endsWith(QLatin1String("-x-generic"));
998 
999  foreach(KIconThemeNode *themeNode, links)
1000  {
1001  QString currentName = name;
1002 
1003  while (!currentName.isEmpty())
1004  {
1005 
1006  //kDebug(264) << "Looking up" << currentName;
1007 
1008 // The following code has been commented out because the Qt SVG renderer needs
1009 // to be improved. If you are going to change/remove some code from this part,
1010 // please contact me before (ereslibre@kde.org), or kde-core-devel@kde.org. (ereslibre)
1011 #ifdef KDE_QT_SVG_RENDERER_FIXED
1012  for (int i = 0 ; i < 4 ; i++)
1013  {
1014  icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchExact);
1015  if (icon.isValid())
1016  return icon;
1017  }
1018 
1019  for (int i = 0 ; i < 4 ; i++)
1020  {
1021  icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchBest);
1022  if (icon.isValid())
1023  return icon;
1024  }
1025 #else
1026  for (int i = 0 ; i < 4 ; i++)
1027  {
1028  icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchExact);
1029  if (icon.isValid())
1030  return icon;
1031 
1032  icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchBest);
1033  if (icon.isValid())
1034  return icon;
1035  }
1036 #endif
1037  if (genericFallback)
1038  // we already tested the base name
1039  break;
1040 
1041  int rindex = currentName.lastIndexOf('-');
1042  if (rindex > 1) { // > 1 so that we don't split x-content or x-epoc
1043  currentName.truncate(rindex);
1044 
1045  if (currentName.endsWith(QLatin1String("-x")))
1046  currentName.chop(2);
1047  } else {
1048  // From update-mime-database.c
1049  static const QSet<QString> mediaTypes = QSet<QString>()
1050  << "text" << "application" << "image" << "audio"
1051  << "inode" << "video" << "message" << "model" << "multipart"
1052  << "x-content" << "x-epoc";
1053  // Shared-mime-info spec says:
1054  // "If [generic-icon] is not specified then the mimetype is used to generate the
1055  // generic icon by using the top-level media type (e.g. "video" in "video/ogg")
1056  // and appending "-x-generic" (i.e. "video-x-generic" in the previous example)."
1057  if (mediaTypes.contains(currentName)) {
1058  currentName += QLatin1String("-x-generic");
1059  genericFallback = true;
1060  } else {
1061  break;
1062  }
1063  }
1064  }
1065  }
1066  return icon;
1067 }
1068 
1069 inline QString KIconLoaderPrivate::unknownIconPath( int size ) const
1070 {
1071  static const QString &str_unknown = KGlobal::staticQString("unknown");
1072 
1073  K3Icon icon = findMatchingIcon(str_unknown, size);
1074  if (!icon.isValid())
1075  {
1076  kDebug(264) << "Warning: could not find \"Unknown\" icon for size = "
1077  << size << endl;
1078  return QString();
1079  }
1080  return icon.path;
1081 }
1082 
1083 // Finds the absolute path to an icon.
1084 
1085 QString KIconLoader::iconPath(const QString& _name, int group_or_size,
1086  bool canReturnNull) const
1087 {
1088  if (!d->initIconThemes()) {
1089  return QString();
1090  }
1091 
1092  if (_name.isEmpty() || !pathIsRelative(_name))
1093  {
1094  // we have either an absolute path or nothing to work with
1095  return _name;
1096  }
1097 
1098  QString name = d->removeIconExtension( _name );
1099 
1100  QString path;
1101  if (group_or_size == KIconLoader::User)
1102  {
1103  static const QString &png_ext = KGlobal::staticQString(".png");
1104  static const QString &xpm_ext = KGlobal::staticQString(".xpm");
1105  path = d->mpDirs->findResource("appicon", name + png_ext);
1106 
1107  static const QString &svgz_ext = KGlobal::staticQString(".svgz");
1108  static const QString &svg_ext = KGlobal::staticQString(".svg");
1109  if (path.isEmpty())
1110  path = d->mpDirs->findResource("appicon", name + svgz_ext);
1111  if (path.isEmpty())
1112  path = d->mpDirs->findResource("appicon", name + svg_ext);
1113  if (path.isEmpty())
1114  path = d->mpDirs->findResource("appicon", name + xpm_ext);
1115  return path;
1116  }
1117 
1118  if (group_or_size >= KIconLoader::LastGroup)
1119  {
1120  kDebug(264) << "Illegal icon group: " << group_or_size;
1121  return path;
1122  }
1123 
1124  int size;
1125  if (group_or_size >= 0)
1126  size = d->mpGroups[group_or_size].size;
1127  else
1128  size = -group_or_size;
1129 
1130  if (_name.isEmpty()) {
1131  if (canReturnNull)
1132  return QString();
1133  else
1134  return d->unknownIconPath(size);
1135  }
1136 
1137  K3Icon icon = d->findMatchingIconWithGenericFallbacks(name, size);
1138 
1139  if (!icon.isValid())
1140  {
1141  // Try "User" group too.
1142  path = iconPath(name, KIconLoader::User, true);
1143  if (!path.isEmpty() || canReturnNull)
1144  return path;
1145 
1146  return d->unknownIconPath(size);
1147  }
1148  return icon.path;
1149 }
1150 
1151 QPixmap KIconLoader::loadMimeTypeIcon( const QString& _iconName, KIconLoader::Group group, int size,
1152  int state, const QStringList& overlays, QString *path_store ) const
1153 {
1154  QString iconName = _iconName;
1155  const int slashindex = iconName.indexOf(QLatin1Char('/'));
1156  if (slashindex != -1) {
1157  iconName[slashindex] = QLatin1Char('-');
1158  }
1159 
1160  if ( !d->extraDesktopIconsLoaded )
1161  {
1162  const QPixmap pixmap = loadIcon( iconName, group, size, state, overlays, path_store, true );
1163  if (!pixmap.isNull() ) {
1164  return pixmap;
1165  }
1166  const_cast<KIconLoader *>(this)->addExtraDesktopThemes();
1167  }
1168  const QPixmap pixmap = loadIcon(iconName, group, size, state, overlays, path_store, true);
1169  if (pixmap.isNull()) {
1170  // Icon not found, fallback to application/octet-stream
1171  return loadIcon("application-octet-stream", group, size, state, overlays, path_store, false);
1172  }
1173  return pixmap;
1174 }
1175 
1176 QPixmap KIconLoader::loadIcon(const QString& _name, KIconLoader::Group group, int size,
1177  int state, const QStringList& overlays,
1178  QString *path_store, bool canReturnNull) const
1179 {
1180  QString name = _name;
1181  bool favIconOverlay = false;
1182 
1183  if (size < 0 || _name.isEmpty())
1184  return QPixmap();
1185 
1186  /*
1187  * This method works in a kind of pipeline, with the following steps:
1188  * 1. Sanity checks.
1189  * 2. Convert _name, group, size, etc. to a key name.
1190  * 3. Check if the key is already cached.
1191  * 4. If not, initialize the theme and find/load the icon.
1192  * 4a Apply overlays
1193  * 4b Re-add to cache.
1194  */
1195 
1196  // Special case for absolute path icons.
1197  if (name.startsWith(QLatin1String("favicons/")))
1198  {
1199  favIconOverlay = true;
1200  name = KStandardDirs::locateLocal("cache", name+".png");
1201  }
1202 
1203  bool absolutePath = !pathIsRelative(name);
1204  if (!absolutePath) {
1205  name = d->removeIconExtension(name);
1206  }
1207 
1208  // Don't bother looking for an icon with no name.
1209  if (name.isEmpty()) {
1210  return QPixmap();
1211  }
1212 
1213  // May modify group, size, or state. This function puts them into sane
1214  // states.
1215  d->normalizeIconMetadata(group, size, state);
1216 
1217  // See if the image is already cached.
1218  QString key = d->makeCacheKey(name, group, overlays, size, state);
1219  QPixmap pix;
1220  bool iconWasUnknown = false;
1221  K3Icon icon;
1222 
1223  // icon.path would be empty for "unknown" icons, which should be searched for
1224  // anew each time.
1225  if (d->findCachedPixmapWithPath(key, pix, icon.path) && !icon.path.isEmpty()) {
1226  if (path_store) {
1227  *path_store = icon.path;
1228  }
1229 
1230  return pix;
1231  }
1232 
1233  // Image is not cached... go find it and apply effects.
1234  if (!d->initIconThemes()) {
1235  return QPixmap();
1236  }
1237 
1238  favIconOverlay = favIconOverlay && size > 22;
1239 
1240  // First we look for non-User icons. If we don't find one we'd search in
1241  // the User space anyways...
1242  if (group != KIconLoader::User) {
1243  // K3Icon seems to hold some needed information.
1244 
1245  if (absolutePath && !favIconOverlay)
1246  {
1247  icon.context = KIconLoader::Any;
1248  icon.type = KIconLoader::Scalable;
1249  icon.path = name;
1250  }
1251  else
1252  {
1253  icon = d->findMatchingIconWithGenericFallbacks(favIconOverlay ? QString("text-html") : name, size);
1254  }
1255  }
1256 
1257  if (icon.path.isEmpty()) {
1258  // We do have a "User" icon, or we couldn't find the non-User one.
1259  icon.path = (absolutePath) ? name :
1260  iconPath(name, KIconLoader::User, canReturnNull);
1261  }
1262 
1263  // Still can't find it? Use "unknown" if we can't return null.
1264  // We keep going in the function so we can ensure this result gets cached.
1265  if (icon.path.isEmpty() && !canReturnNull) {
1266  icon.path = d->unknownIconPath(size);
1267  iconWasUnknown = true;
1268  }
1269 
1270  QImage img = d->createIconImage(icon.path, size);
1271 
1272  if (group >= 0)
1273  {
1274  img = d->mpEffect.apply(img, group, state);
1275  }
1276 
1277  if (favIconOverlay)
1278  {
1279  QImage favIcon(name, "PNG");
1280  if (!favIcon.isNull()) // if favIcon not there yet, don't try to blend it
1281  {
1282  QPainter p(&img);
1283 
1284  // Align the favicon overlay
1285  QRect r(favIcon.rect());
1286  r.moveBottomRight(img.rect().bottomRight());
1287  r.adjust(-1, -1, -1, -1); // Move off edge
1288 
1289  // Blend favIcon over img.
1290  p.drawImage(r, favIcon);
1291  }
1292  }
1293 
1294  pix = QPixmap::fromImage(img);
1295 
1296  // TODO: If we make a loadIcon that returns the image we can convert
1297  // drawOverlays to use the image instead of pixmaps as well so we don't
1298  // have to transfer so much to the graphics card.
1299  d->drawOverlays(this, group, state, pix, overlays);
1300 
1301  // Don't add the path to our unknown icon to the cache, only cache the
1302  // actual image.
1303  if (iconWasUnknown) {
1304  icon.path.clear();
1305  }
1306 
1307  d->insertCachedPixmapWithPath(key, pix, icon.path);
1308 
1309  if (path_store) {
1310  *path_store = icon.path;
1311  }
1312 
1313  return pix;
1314 }
1315 
1316 QMovie *KIconLoader::loadMovie(const QString& name, KIconLoader::Group group, int size, QObject *parent) const
1317 {
1318  QString file = moviePath( name, group, size );
1319  if (file.isEmpty())
1320  return 0;
1321  int dirLen = file.lastIndexOf('/');
1322  QString icon = iconPath(name, size ? -size : group, true);
1323  if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
1324  return 0;
1325  QMovie *movie = new QMovie(file, QByteArray(), parent);
1326  if (!movie->isValid())
1327  {
1328  delete movie;
1329  return 0;
1330  }
1331  return movie;
1332 }
1333 
1334 QString KIconLoader::moviePath(const QString& name, KIconLoader::Group group, int size) const
1335 {
1336  if (!d->mpGroups) return QString();
1337 
1338  d->initIconThemes();
1339 
1340  if ( (group < -1 || group >= KIconLoader::LastGroup) && group != KIconLoader::User )
1341  {
1342  kDebug(264) << "Illegal icon group: " << group;
1343  group = KIconLoader::Desktop;
1344  }
1345  if (size == 0 && group < 0)
1346  {
1347  kDebug(264) << "Neither size nor group specified!";
1348  group = KIconLoader::Desktop;
1349  }
1350 
1351  QString file = name + ".mng";
1352  if (group == KIconLoader::User)
1353  {
1354  file = d->mpDirs->findResource("appicon", file);
1355  }
1356  else
1357  {
1358  if (size == 0)
1359  size = d->mpGroups[group].size;
1360 
1361  K3Icon icon;
1362 
1363  foreach(KIconThemeNode *themeNode, d->links)
1364  {
1365  icon = themeNode->theme->iconPath(file, size, KIconLoader::MatchExact);
1366  if (icon.isValid())
1367  break;
1368  }
1369 
1370  if ( !icon.isValid() )
1371  {
1372  foreach(KIconThemeNode *themeNode, d->links)
1373  {
1374  icon = themeNode->theme->iconPath(file, size, KIconLoader::MatchBest);
1375  if (icon.isValid())
1376  break;
1377  }
1378  }
1379 
1380  file = icon.isValid() ? icon.path : QString();
1381  }
1382  return file;
1383 }
1384 
1385 
1386 QStringList KIconLoader::loadAnimated(const QString& name, KIconLoader::Group group, int size) const
1387 {
1388  QStringList lst;
1389 
1390  if (!d->mpGroups) return lst;
1391 
1392  d->initIconThemes();
1393 
1394  if ((group < -1) || (group >= KIconLoader::LastGroup))
1395  {
1396  kDebug(264) << "Illegal icon group: " << group;
1397  group = KIconLoader::Desktop;
1398  }
1399  if ((size == 0) && (group < 0))
1400  {
1401  kDebug(264) << "Neither size nor group specified!";
1402  group = KIconLoader::Desktop;
1403  }
1404 
1405  QString file = name + "/0001";
1406  if (group == KIconLoader::User)
1407  {
1408  file = d->mpDirs->findResource("appicon", file + ".png");
1409  } else
1410  {
1411  if (size == 0)
1412  size = d->mpGroups[group].size;
1413  K3Icon icon = d->findMatchingIcon(file, size);
1414  file = icon.isValid() ? icon.path : QString();
1415 
1416  }
1417  if (file.isEmpty())
1418  return lst;
1419 
1420  QString path = file.left(file.length()-8);
1421  DIR* dp = opendir( QFile::encodeName(path) );
1422  if(!dp)
1423  return lst;
1424 
1425  KDE_struct_dirent* ep;
1426  while( ( ep = KDE_readdir( dp ) ) != 0L )
1427  {
1428  QString fn(QFile::decodeName(ep->d_name));
1429  if(!(fn.left(4)).toUInt())
1430  continue;
1431 
1432  lst += path + fn;
1433  }
1434  closedir ( dp );
1435  lst.sort();
1436  return lst;
1437 }
1438 
1439 KIconTheme *KIconLoader::theme() const
1440 {
1441  d->initIconThemes();
1442  if (d->mpThemeRoot) return d->mpThemeRoot->theme;
1443  return 0L;
1444 }
1445 
1446 int KIconLoader::currentSize(KIconLoader::Group group) const
1447 {
1448  if (!d->mpGroups) return -1;
1449 
1450  if (group < 0 || group >= KIconLoader::LastGroup)
1451  {
1452  kDebug(264) << "Illegal icon group: " << group;
1453  return -1;
1454  }
1455  return d->mpGroups[group].size;
1456 }
1457 
1458 QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
1459 {
1460  const QDir dir(iconsDir);
1461  const QStringList formats = QStringList() << "*.png" << "*.xpm" << "*.svg" << "*.svgz";
1462  const QStringList lst = dir.entryList(formats, QDir::Files);
1463  QStringList result;
1464  QStringList::ConstIterator it;
1465  for (it=lst.begin(); it!=lst.end(); ++it)
1466  result += iconsDir + '/' + *it;
1467  return result;
1468 }
1469 
1470 QStringList KIconLoader::queryIconsByContext(int group_or_size,
1471  KIconLoader::Context context) const
1472 {
1473  d->initIconThemes();
1474 
1475  QStringList result;
1476  if (group_or_size >= KIconLoader::LastGroup)
1477  {
1478  kDebug(264) << "Illegal icon group: " << group_or_size;
1479  return result;
1480  }
1481  int size;
1482  if (group_or_size >= 0)
1483  size = d->mpGroups[group_or_size].size;
1484  else
1485  size = -group_or_size;
1486 
1487  foreach(KIconThemeNode *themeNode, d->links)
1488  themeNode->queryIconsByContext(&result, size, context);
1489 
1490  // Eliminate duplicate entries (same icon in different directories)
1491  QString name;
1492  QStringList res2, entries;
1493  QStringList::ConstIterator it;
1494  for (it=result.constBegin(); it!=result.constEnd(); ++it)
1495  {
1496  int n = (*it).lastIndexOf('/');
1497  if (n == -1)
1498  name = *it;
1499  else
1500  name = (*it).mid(n+1);
1501  name = d->removeIconExtension(name);
1502  if (!entries.contains(name))
1503  {
1504  entries += name;
1505  res2 += *it;
1506  }
1507  }
1508  return res2;
1509 
1510 }
1511 
1512 QStringList KIconLoader::queryIcons(int group_or_size, KIconLoader::Context context) const
1513 {
1514  d->initIconThemes();
1515 
1516  QStringList result;
1517  if (group_or_size >= KIconLoader::LastGroup)
1518  {
1519  kDebug(264) << "Illegal icon group: " << group_or_size;
1520  return result;
1521  }
1522  int size;
1523  if (group_or_size >= 0)
1524  size = d->mpGroups[group_or_size].size;
1525  else
1526  size = -group_or_size;
1527 
1528  foreach(KIconThemeNode *themeNode, d->links)
1529  themeNode->queryIcons(&result, size, context);
1530 
1531  // Eliminate duplicate entries (same icon in different directories)
1532  QString name;
1533  QStringList res2, entries;
1534  QStringList::ConstIterator it;
1535  for (it=result.constBegin(); it!=result.constEnd(); ++it)
1536  {
1537  int n = (*it).lastIndexOf('/');
1538  if (n == -1)
1539  name = *it;
1540  else
1541  name = (*it).mid(n+1);
1542  name = d->removeIconExtension(name);
1543  if (!entries.contains(name))
1544  {
1545  entries += name;
1546  res2 += *it;
1547  }
1548  }
1549  return res2;
1550 }
1551 
1552 // used by KIconDialog to find out which contexts to offer in a combobox
1553 bool KIconLoader::hasContext(KIconLoader::Context context) const
1554 {
1555  d->initIconThemes();
1556 
1557  foreach(KIconThemeNode *themeNode, d->links)
1558  if( themeNode->theme->hasContext( context ))
1559  return true;
1560  return false;
1561 }
1562 
1563 KIconEffect * KIconLoader::iconEffect() const
1564 {
1565  return &d->mpEffect;
1566 }
1567 
1568 bool KIconLoader::alphaBlending(KIconLoader::Group group) const
1569 {
1570  if (!d->mpGroups) return false;
1571 
1572  if (group < 0 || group >= KIconLoader::LastGroup)
1573  {
1574  kDebug(264) << "Illegal icon group: " << group;
1575  return false;
1576  }
1577  return d->mpGroups[group].alphaBlending;
1578 }
1579 
1580 // deprecated
1581 #ifndef KDE_NO_DEPRECATED
1582 QIcon KIconLoader::loadIconSet( const QString& name, KIconLoader::Group g, int s,
1583  bool canReturnNull )
1584 {
1585  QIcon iconset;
1586  QPixmap tmp = loadIcon(name, g, s, KIconLoader::ActiveState, QStringList(), NULL, canReturnNull);
1587  iconset.addPixmap( tmp, QIcon::Active, QIcon::On );
1588  // we don't use QIconSet's resizing anyway
1589  tmp = loadIcon(name, g, s, KIconLoader::DisabledState, QStringList(), NULL, canReturnNull);
1590  iconset.addPixmap( tmp, QIcon::Disabled, QIcon::On );
1591  tmp = loadIcon(name, g, s, KIconLoader::DefaultState, QStringList(), NULL, canReturnNull);
1592  iconset.addPixmap( tmp, QIcon::Normal, QIcon::On );
1593  return iconset;
1594 }
1595 #endif
1596 
1597 // Easy access functions
1598 
1599 QPixmap DesktopIcon(const QString& name, int force_size, int state, const QStringList &overlays)
1600 {
1601  KIconLoader *loader = KIconLoader::global();
1602  return loader->loadIcon(name, KIconLoader::Desktop, force_size, state, overlays);
1603 }
1604 
1605 // deprecated
1606 #ifndef KDE_NO_DEPRECATED
1607 QIcon DesktopIconSet(const QString& name, int force_size)
1608 {
1609  KIconLoader *loader = KIconLoader::global();
1610  return loader->loadIconSet(name, KIconLoader::Desktop, force_size);
1611 }
1612 #endif
1613 
1614 QPixmap BarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
1615 {
1616  KIconLoader *loader = KIconLoader::global();
1617  return loader->loadIcon(name, KIconLoader::Toolbar, force_size, state, overlays);
1618 }
1619 
1620 // deprecated
1621 #ifndef KDE_NO_DEPRECATED
1622 QIcon BarIconSet(const QString& name, int force_size)
1623 {
1624  KIconLoader *loader = KIconLoader::global();
1625  return loader->loadIconSet( name, KIconLoader::Toolbar, force_size );
1626 }
1627 #endif
1628 
1629 QPixmap SmallIcon(const QString& name, int force_size, int state, const QStringList &overlays)
1630 {
1631  KIconLoader *loader = KIconLoader::global();
1632  return loader->loadIcon(name, KIconLoader::Small, force_size, state, overlays);
1633 }
1634 
1635 // deprecated
1636 #ifndef KDE_NO_DEPRECATED
1637 QIcon SmallIconSet(const QString& name, int force_size)
1638 {
1639  KIconLoader *loader = KIconLoader::global();
1640  return loader->loadIconSet( name, KIconLoader::Small, force_size );
1641 }
1642 #endif
1643 
1644 QPixmap MainBarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
1645 {
1646  KIconLoader *loader = KIconLoader::global();
1647  return loader->loadIcon(name, KIconLoader::MainToolbar, force_size, state, overlays);
1648 }
1649 
1650 // deprecated
1651 #ifndef KDE_NO_DEPRECATED
1652 QIcon MainBarIconSet(const QString& name, int force_size)
1653 {
1654  KIconLoader *loader = KIconLoader::global();
1655  return loader->loadIconSet( name, KIconLoader::MainToolbar, force_size );
1656 }
1657 #endif
1658 
1659 QPixmap UserIcon(const QString& name, int state, const QStringList &overlays)
1660 {
1661  KIconLoader *loader = KIconLoader::global();
1662  return loader->loadIcon(name, KIconLoader::User, 0, state, overlays);
1663 }
1664 
1665 // deprecated
1666 #ifndef KDE_NO_DEPRECATED
1667 QIcon UserIconSet(const QString& name)
1668 {
1669  KIconLoader *loader = KIconLoader::global();
1670  return loader->loadIconSet( name, KIconLoader::User );
1671 }
1672 #endif
1673 
1674 int IconSize(KIconLoader::Group group)
1675 {
1676  KIconLoader *loader = KIconLoader::global();
1677  return loader->currentSize(group);
1678 }
1679 
1680 QPixmap KIconLoader::unknown()
1681 {
1682  QPixmap pix;
1683  if ( QPixmapCache::find("unknown", pix) ) //krazy:exclude=iconnames
1684  return pix;
1685 
1686  QString path = global()->iconPath("unknown", KIconLoader::Small, true); //krazy:exclude=iconnames
1687  if (path.isEmpty())
1688  {
1689  kDebug(264) << "Warning: Cannot find \"unknown\" icon.";
1690  pix = QPixmap(32,32);
1691  } else
1692  {
1693  pix.load(path);
1694  QPixmapCache::insert("unknown", pix); //krazy:exclude=iconnames
1695  }
1696 
1697  return pix;
1698 }
1699 
1700 /*** the global icon loader ***/
1701 K_GLOBAL_STATIC_WITH_ARGS(KIconLoader, globalIconLoader, (KGlobal::mainComponent(), 0))
1702 
1703 KIconLoader *KIconLoader::global()
1704 {
1705  return globalIconLoader;
1706 }
1707 
1708 void KIconLoader::newIconLoader()
1709 {
1710  if ( global() == this) {
1711  KIconTheme::reconfigure();
1712  }
1713 
1714  reconfigure( objectName(), d->mpDirs );
1715  emit iconLoaderSettingsChanged();
1716 }
1717 
1718 #include "kiconloader.moc"
1719 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Feb 9 2013 12:05:56 by doxygen 1.8.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.10.0 API Reference

Skip menu "kdelibs-4.10.0 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal