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

KDEUI

kiconloader.cpp
Go to the documentation of this file.
00001 /* vi: ts=8 sts=4 sw=4
00002  *
00003  * kiconloader.cpp: An icon loader for KDE with theming functionality.
00004  *
00005  * This file is part of the KDE project, module kdeui.
00006  * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
00007  *                    Antonio Larrosa <larrosa@kde.org>
00008  *               2010 Michael Pyne <mpyne@kde.org>
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Library General Public
00012  * License version 2 as published by the Free Software Foundation.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Library General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Library General Public License
00020  * along with this library; see the file COPYING.LIB.  If not, write to
00021  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022  * Boston, MA 02110-1301, USA.
00023  */
00024 
00025 #include "kiconloader.h"
00026 
00027 #include <sys/types.h>
00028 #include <stdlib.h>     //for abs
00029 #include <unistd.h>     //for readlink
00030 #include <dirent.h>
00031 #include <assert.h>
00032 
00033 #include <QtCore/QCache>
00034 #include <QtCore/QFileInfo>
00035 #include <QtCore/QDir>
00036 #include <QtCore/QBuffer>
00037 #include <QtCore/QDataStream>
00038 #include <QtCore/QByteArray>
00039 #include <QtCore/QStringBuilder> // % operator for QString
00040 #include <QtGui/QIcon>
00041 #include <QtGui/QImage>
00042 #include <QtGui/QMovie>
00043 #include <QtGui/QPainter>
00044 #include <QtGui/QPixmap>
00045 #include <QtGui/QPixmapCache>
00046 #ifndef _WIN32_WCE
00047 #include <QtSvg/QSvgRenderer>
00048 #endif
00049 
00050 // kdecore
00051 #include <kconfig.h>
00052 #include <kconfiggroup.h>
00053 #include <kdebug.h>
00054 #include <kstandarddirs.h>
00055 #include <kglobal.h>
00056 #include <kglobalsettings.h>
00057 #include <kcomponentdata.h>
00058 #include <kde_file.h>
00059 #include <kshareddatacache.h>
00060 
00061 // kdeui
00062 #include "kicontheme.h"
00063 #include "kiconeffect.h"
00064 #include "k3icon_p.h"
00065 
00066 // Used to make cache keys for icons with no group. Result type is QString*
00067 K_GLOBAL_STATIC_WITH_ARGS(QString, NULL_EFFECT_FINGERPRINT, (QString::fromLatin1("noeffect")))
00068 
00069 // Qt implements Tiny SVG specification. This specification does not cover important elements
00070 // that are pretty globally used on our icons, like blurring (and other filters). TT seems to have
00071 // no interest in supporting the full SVG specification (it would be slower, even with JS, CSS
00072 // support...). So, we have no chance for now. Let's disable svg rendering unconditionally.
00073 // (ereslibre)
00074 #undef KDE_QT_SVG_RENDERER_FIXED
00075 
00079 static bool pathIsRelative(const QString &path)
00080 {
00081 #ifdef Q_OS_UNIX
00082     return (!path.isEmpty() && path[0] != QChar('/'));
00083 #else
00084     return QDir::isRelativePath(path);
00085 #endif
00086 }
00087 
00091 struct PixmapWithPath
00092 {
00093     QPixmap pixmap;
00094     QString path;
00095 };
00096 
00097 /*** KIconThemeNode: A node in the icon theme dependancy tree. ***/
00098 
00099 class KIconThemeNode
00100 {
00101 public:
00102 
00103     KIconThemeNode(KIconTheme *_theme);
00104     ~KIconThemeNode();
00105 
00106     void queryIcons(QStringList *lst, int size, KIconLoader::Context context) const;
00107     void queryIconsByContext(QStringList *lst, int size, KIconLoader::Context context) const;
00108     K3Icon findIcon(const QString& name, int size, KIconLoader::MatchType match) const;
00109     void printTree(QString& dbgString) const;
00110 
00111     KIconTheme *theme;
00112 };
00113 
00114 KIconThemeNode::KIconThemeNode(KIconTheme *_theme)
00115 {
00116     theme = _theme;
00117 }
00118 
00119 KIconThemeNode::~KIconThemeNode()
00120 {
00121     delete theme;
00122 }
00123 
00124 void KIconThemeNode::printTree(QString& dbgString) const
00125 {
00126     /* This method doesn't have much sense anymore, so maybe it should
00127        be removed in the (near?) future */
00128     dbgString += '(';
00129     dbgString += theme->name();
00130     dbgString += ')';
00131 }
00132 
00133 void KIconThemeNode::queryIcons(QStringList *result,
00134                                 int size, KIconLoader::Context context) const
00135 {
00136     // add the icons of this theme to it
00137     *result += theme->queryIcons(size, context);
00138 }
00139 
00140 void KIconThemeNode::queryIconsByContext(QStringList *result,
00141                                 int size, KIconLoader::Context context) const
00142 {
00143     // add the icons of this theme to it
00144     *result += theme->queryIconsByContext(size, context);
00145 }
00146 
00147 K3Icon KIconThemeNode::findIcon(const QString& name, int size,
00148                                KIconLoader::MatchType match) const
00149 {
00150     return theme->iconPath(name, size, match);
00151 }
00152 
00153 
00154 /*** KIconGroup: Icon type description. ***/
00155 
00156 struct KIconGroup
00157 {
00158     int size;
00159     bool alphaBlending;
00160 };
00161 
00162 
00163 /*** d pointer for KIconLoader. ***/
00164 class KIconLoaderPrivate
00165 {
00166 public:
00167     KIconLoaderPrivate(KIconLoader *q)
00168         : q(q)
00169         , mpGroups(0)
00170         , mIconCache(0)
00171     {
00172     }
00173 
00174     ~KIconLoaderPrivate()
00175     {
00176         /* antlarr: There's no need to delete d->mpThemeRoot as it's already
00177         deleted when the elements of d->links are deleted */
00178         qDeleteAll(links);
00179         delete[] mpGroups;
00180         delete mIconCache;
00181     }
00182 
00186     void init( const QString& _appname, KStandardDirs *_dirs );
00187 
00191     bool initIconThemes();
00192 
00198     K3Icon findMatchingIcon(const QString& name, int size) const;
00199 
00206     K3Icon findMatchingIconWithGenericFallbacks(const QString& name, int size) const;
00207 
00212     void addAppThemes(const QString& appname);
00213 
00219     void addBaseThemes(KIconThemeNode *node, const QString &appname);
00220 
00226     void addInheritedThemes(KIconThemeNode *node, const QString &appname);
00227 
00234     void addThemeByName(const QString &themename, const QString &appname);
00235 
00240     QString unknownIconPath( int size ) const;
00241 
00246     QString removeIconExtension(const QString &name) const;
00247 
00254     void normalizeIconMetadata(KIconLoader::Group &group, int &size, int &state) const;
00255 
00261     QString makeCacheKey(const QString &name, KIconLoader::Group group, const QStringList &overlays,
00262                          int size, int state) const;
00263 
00270     QImage createIconImage(const QString &path, int size = 0);
00271 
00276     void insertCachedPixmapWithPath(const QString &key, const QPixmap &data, const QString &path);
00277 
00283     bool findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path);
00284 
00285     KIconLoader *const q;
00286 
00287     QStringList mThemesInTree;
00288     KIconGroup *mpGroups;
00289     KIconThemeNode *mpThemeRoot;
00290     KStandardDirs *mpDirs;
00291     KIconEffect mpEffect;
00292     QList<KIconThemeNode *> links;
00293 
00294     // This shares the icons across all processes
00295     KSharedDataCache* mIconCache;
00296 
00297     // This caches rendered QPixmaps in just this process.
00298     QCache<QString, PixmapWithPath> mPixmapCache;
00299 
00300     bool extraDesktopIconsLoaded :1;
00301     // lazy loading: initIconThemes() is only needed when the "links" list is needed
00302     // mIconThemeInited is used inside initIconThemes() to init only once
00303     bool mIconThemeInited :1;
00304     QString appname;
00305 
00306     void drawOverlays(const KIconLoader *loader, KIconLoader::Group group, int state, QPixmap& pix, const QStringList& overlays);
00307 };
00308 
00309 class KIconLoaderGlobalData
00310 {
00311 public:
00312     KIconLoaderGlobalData() {
00313         const QStringList genericIconsFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "generic-icons");
00314         //kDebug() << genericIconsFiles;
00315         Q_FOREACH(const QString& file, genericIconsFiles) {
00316             parseGenericIconsFiles(file);
00317         }
00318     }
00319 
00320     QString genericIconFor(const QString& icon) const {
00321         return m_genericIcons.value(icon);
00322     }
00323 
00324 private:
00325     void parseGenericIconsFiles(const QString& fileName);
00326     QHash<QString, QString> m_genericIcons;
00327 };
00328 
00329 void KIconLoaderGlobalData::parseGenericIconsFiles(const QString& fileName)
00330 {
00331     QFile file(fileName);
00332     if (file.open(QIODevice::ReadOnly)) {
00333         QTextStream stream(&file);
00334         stream.setCodec("ISO 8859-1");
00335         while (!stream.atEnd()) {
00336             const QString line = stream.readLine();
00337             if (line.isEmpty() || line[0] == '#')
00338                 continue;
00339             const int pos = line.indexOf(':');
00340             if (pos == -1) // syntax error
00341                 continue;
00342             QString mimeIcon = line.left(pos);
00343             const int slashindex = mimeIcon.indexOf(QLatin1Char('/'));
00344             if (slashindex != -1) {
00345                 mimeIcon[slashindex] = QLatin1Char('-');
00346             }
00347 
00348             const QString genericIcon = line.mid(pos+1);
00349             m_genericIcons.insert(mimeIcon, genericIcon);
00350             //kDebug(264) << mimeIcon << "->" << genericIcon;
00351         }
00352     }
00353 }
00354 
00355 K_GLOBAL_STATIC(KIconLoaderGlobalData, s_globalData)
00356 
00357 void KIconLoaderPrivate::drawOverlays(const KIconLoader *iconLoader, KIconLoader::Group group, int state, QPixmap& pix, const QStringList& overlays)
00358 {
00359     if (overlays.isEmpty()) {
00360         return;
00361     }
00362 
00363     const int width = pix.size().width();
00364     const int height = pix.size().height();
00365     const int iconSize = qMin(width, height);
00366     int overlaySize;
00367 
00368     if (iconSize < 32) {
00369         overlaySize = 8;
00370     } else if (iconSize <= 48) {
00371         overlaySize = 16;
00372     } else if (iconSize <= 96) {
00373         overlaySize = 22;
00374     } else if (iconSize < 256) {
00375         overlaySize = 32;
00376     } else {
00377         overlaySize = 64;
00378     }
00379 
00380     QPainter painter(&pix);
00381 
00382     int count = 0;
00383     foreach (const QString& overlay, overlays) {
00384         // Ensure empty strings fill up a emblem spot
00385         // Needed when you have several emblems to ensure they're always painted
00386         // at the same place, even if one is not here
00387         if (overlay.isEmpty()) {
00388             ++count;
00389             continue;
00390         }
00391 
00392         //TODO: should we pass in the kstate? it results in a slower
00393         //      path, and perhaps emblems should remain in the default state
00394         //      anyways?
00395         const QPixmap pixmap = iconLoader->loadIcon(overlay, group, overlaySize, state, QStringList(), 0, true);
00396 
00397         if (pixmap.isNull()) {
00398             continue;
00399         }
00400 
00401         QPoint startPoint;
00402         switch (count) {
00403         case 0:
00404             // bottom left corner
00405             startPoint = QPoint(2, height - overlaySize - 2);
00406             break;
00407         case 1:
00408             // bottom right corner
00409             startPoint = QPoint(width - overlaySize - 2,
00410                                 height - overlaySize - 2);
00411             break;
00412         case 2:
00413             // top right corner
00414             startPoint = QPoint(width - overlaySize - 2, 2);
00415             break;
00416         case 3:
00417             // top left corner
00418             startPoint = QPoint(2, 2);
00419             break;
00420         }
00421 
00422         painter.drawPixmap(startPoint, pixmap);
00423 
00424         ++count;
00425         if (count > 3) {
00426             break;
00427         }
00428     }
00429 }
00430 
00431 KIconLoader::KIconLoader(const QString& _appname, KStandardDirs *_dirs, QObject* parent)
00432     : QObject(parent)
00433 {
00434     setObjectName(_appname);
00435     d = new KIconLoaderPrivate(this);
00436 
00437     connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
00438             this, SLOT(newIconLoader()));
00439     d->init( _appname, _dirs );
00440 }
00441 
00442 KIconLoader::KIconLoader(const KComponentData &componentData, QObject* parent)
00443     : QObject(parent)
00444 {
00445     setObjectName(componentData.componentName());
00446     d = new KIconLoaderPrivate(this);
00447 
00448     connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
00449             this, SLOT(newIconLoader()));
00450     d->init(componentData.componentName(), componentData.dirs());
00451 }
00452 
00453 void KIconLoader::reconfigure( const QString& _appname, KStandardDirs *_dirs )
00454 {
00455     d->mIconCache->clear();
00456     delete d;
00457     d = new KIconLoaderPrivate(this);
00458     d->init( _appname, _dirs );
00459 }
00460 
00461 void KIconLoaderPrivate::init( const QString& _appname, KStandardDirs *_dirs )
00462 {
00463     extraDesktopIconsLoaded=false;
00464     mIconThemeInited = false;
00465     mpThemeRoot = 0;
00466 
00467     if (_dirs)
00468         mpDirs = _dirs;
00469     else
00470         mpDirs = KGlobal::dirs();
00471 
00472     appname = _appname;
00473     if (appname.isEmpty())
00474         appname = KGlobal::mainComponent().componentName();
00475 
00476     // Initialize icon cache
00477     mIconCache = new KSharedDataCache("icon-cache", 10 * 1024 * 1024);
00478     // Cost here is number of pixels, not size. So this is actually a bit
00479     // smaller.
00480     mPixmapCache.setMaxCost(10 * 1024 * 1024);
00481 
00482     // These have to match the order in kicontheme.h
00483     static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", "Dialog", 0L };
00484     KSharedConfig::Ptr config = KGlobal::config();
00485 
00486     // loading config and default sizes
00487     initIconThemes();
00488     KIconTheme *defaultSizesTheme = links.empty() ? 0 : links.first()->theme;
00489     mpGroups = new KIconGroup[(int) KIconLoader::LastGroup];
00490     for (KIconLoader::Group i = KIconLoader::FirstGroup; i < KIconLoader::LastGroup; ++i) {
00491         if (groups[i] == 0L) {
00492             break;
00493         }
00494 
00495         KConfigGroup cg(config, QLatin1String(groups[i]) + "Icons");
00496         mpGroups[i].size = cg.readEntry("Size", 0);
00497         if (QPixmap::defaultDepth() > 8) {
00498             mpGroups[i].alphaBlending = cg.readEntry("AlphaBlending", true);
00499         } else {
00500             mpGroups[i].alphaBlending = false;
00501         }
00502 
00503         if (!mpGroups[i].size && defaultSizesTheme) {
00504             mpGroups[i].size = defaultSizesTheme->defaultSize(i);
00505         }
00506     }
00507 }
00508 
00509 bool KIconLoaderPrivate::initIconThemes()
00510 {
00511     if (mIconThemeInited) {
00512         // If mpThemeRoot isn't 0 then initing has succeeded
00513         return (mpThemeRoot != 0);
00514     }
00515     //kDebug(264);
00516     mIconThemeInited = true;
00517 
00518     // Add the default theme and its base themes to the theme tree
00519     KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00520     if (!def->isValid())
00521     {
00522         delete def;
00523         // warn, as this is actually a small penalty hit
00524         kDebug(264) << "Couldn't find current icon theme, falling back to default.";
00525         def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00526         if (!def->isValid())
00527         {
00528             kError(264) << "Error: standard icon theme" << KIconTheme::defaultThemeName() << "not found!" << endl;
00529             delete def;
00530             return false;
00531         }
00532     }
00533     mpThemeRoot = new KIconThemeNode(def);
00534     mThemesInTree.append(def->internalName());
00535     links.append(mpThemeRoot);
00536     addBaseThemes(mpThemeRoot, appname);
00537 
00538     // Insert application specific themes at the top.
00539     mpDirs->addResourceType("appicon", "data", appname + "/pics/");
00540     // ################## KDE5: consider removing the toolbar directory
00541     mpDirs->addResourceType("appicon", "data", appname + "/toolbar/");
00542 
00543     // Add legacy icon dirs.
00544     QStringList dirs;
00545     dirs += mpDirs->resourceDirs("icon");
00546     dirs += mpDirs->resourceDirs("pixmap");
00547     dirs += mpDirs->resourceDirs("xdgdata-icon");
00548     dirs += "/usr/share/pixmaps";
00549     // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
00550     dirs += mpDirs->resourceDirs("xdgdata-pixmap");
00551     for (QStringList::ConstIterator it = dirs.constBegin(); it != dirs.constEnd(); ++it)
00552         mpDirs->addResourceDir("appicon", *it);
00553 
00554 #ifndef NDEBUG
00555     QString dbgString = "Theme tree: ";
00556     mpThemeRoot->printTree(dbgString);
00557     kDebug(264) << dbgString;
00558 #endif
00559 
00560     return true;
00561 }
00562 
00563 KIconLoader::~KIconLoader()
00564 {
00565     delete d;
00566 }
00567 
00568 void KIconLoader::addAppDir(const QString& appname)
00569 {
00570     d->initIconThemes();
00571 
00572     d->mpDirs->addResourceType("appicon", "data", appname + "/pics/");
00573     // ################## KDE5: consider removing the toolbar directory
00574     d->mpDirs->addResourceType("appicon", "data", appname + "/toolbar/");
00575     d->addAppThemes(appname);
00576 }
00577 
00578 void KIconLoaderPrivate::addAppThemes(const QString& appname)
00579 {
00580     initIconThemes();
00581 
00582     KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00583     if (!def->isValid()) {
00584         delete def;
00585         def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00586     }
00587     KIconThemeNode* node = new KIconThemeNode(def);
00588     bool addedToLinks = false;
00589 
00590     if (!mThemesInTree.contains(node->theme->internalName())) {
00591         mThemesInTree.append(node->theme->internalName());
00592         links.append(node);
00593         addedToLinks = true;
00594     }
00595     addBaseThemes(node, appname);
00596 
00597     if (!addedToLinks) {
00598         // Nodes in links are being deleted later - this one needs manual care.
00599         delete node;
00600     }
00601 }
00602 
00603 void KIconLoaderPrivate::addBaseThemes(KIconThemeNode *node, const QString &appname)
00604 {
00605     // Quote from the icon theme specification:
00606     //   The lookup is done first in the current theme, and then recursively
00607     //   in each of the current theme's parents, and finally in the
00608     //   default theme called "hicolor" (implementations may add more
00609     //   default themes before "hicolor", but "hicolor" must be last).
00610     //
00611     // So we first make sure that all inherited themes are added, then we
00612     // add the KDE default theme as fallback for all icons that might not be
00613     // present in an inherited theme, and hicolor goes last.
00614 
00615     addInheritedThemes(node, appname);
00616     addThemeByName(KIconTheme::defaultThemeName(), appname);
00617     addThemeByName("hicolor", appname);
00618 }
00619 
00620 void KIconLoaderPrivate::addInheritedThemes(KIconThemeNode *node, const QString &appname)
00621 {
00622     const QStringList lst = node->theme->inherits();
00623 
00624     for (QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) {
00625         if ((*it) == "hicolor") {
00626           // The icon theme spec says that "hicolor" must be the very last
00627           // of all inherited themes, so don't add it here but at the very end
00628           // of addBaseThemes().
00629           continue;
00630         }
00631         addThemeByName(*it, appname);
00632     }
00633 }
00634 
00635 void KIconLoaderPrivate::addThemeByName(const QString &themename, const QString &appname)
00636 {
00637     if (mThemesInTree.contains(themename + appname)) {
00638         return;
00639     }
00640     KIconTheme *theme = new KIconTheme(themename, appname);
00641     if (!theme->isValid()) {
00642         delete theme;
00643         return;
00644     }
00645     KIconThemeNode *n = new KIconThemeNode(theme);
00646     mThemesInTree.append(themename + appname);
00647     links.append(n);
00648     addInheritedThemes(n, appname);
00649 }
00650 
00651 void KIconLoader::addExtraDesktopThemes()
00652 {
00653     if ( d->extraDesktopIconsLoaded ) return;
00654 
00655     d->initIconThemes();
00656 
00657     QStringList list;
00658     const QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
00659     QStringList::ConstIterator it;
00660     char buf[1000];
00661     int r;
00662     for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00663     {
00664         QDir dir(*it);
00665         if (!dir.exists())
00666             continue;
00667         const QStringList lst = dir.entryList(QStringList( "default.*" ), QDir::Dirs);
00668         QStringList::ConstIterator it2;
00669         for (it2=lst.begin(); it2!=lst.end(); ++it2)
00670         {
00671             if (!KStandardDirs::exists(*it + *it2 + "/index.desktop")
00672                 && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
00673                 continue;
00674             r=readlink( QFile::encodeName(*it + *it2) , buf, sizeof(buf)-1);
00675             if ( r>0 )
00676             {
00677                 buf[r]=0;
00678                 const QDir dir2( buf );
00679                 QString themeName=dir2.dirName();
00680 
00681                 if (!list.contains(themeName))
00682                     list.append(themeName);
00683             }
00684         }
00685     }
00686 
00687     for (it = list.constBegin(); it != list.constEnd(); ++it)
00688     {
00689         // Don't add the KDE defaults once more, we have them anyways.
00690         if (*it == QLatin1String("default.kde")
00691             || *it == QLatin1String("default.kde4")) {
00692             continue;
00693         }
00694         d->addThemeByName(*it, "");
00695     }
00696 
00697     d->extraDesktopIconsLoaded=true;
00698 
00699 }
00700 
00701 bool KIconLoader::extraDesktopThemesAdded() const
00702 {
00703     return d->extraDesktopIconsLoaded;
00704 }
00705 
00706 void KIconLoader::drawOverlays(const QStringList &overlays, QPixmap &pixmap, KIconLoader::Group group, int state) const
00707 {
00708     d->drawOverlays(this, group, state, pixmap, overlays);
00709 }
00710 
00711 QString KIconLoaderPrivate::removeIconExtension(const QString &name) const
00712 {
00713     if (name.endsWith(QLatin1String(".png"))
00714         || name.endsWith(QLatin1String(".xpm"))
00715         || name.endsWith(QLatin1String(".svg"))) {
00716         return name.left(name.length() - 4);
00717     } else if (name.endsWith(QLatin1String(".svgz"))) {
00718         return name.left(name.length() - 5);
00719     }
00720 
00721     return name;
00722 }
00723 
00724 void KIconLoaderPrivate::normalizeIconMetadata(KIconLoader::Group &group, int &size, int &state) const
00725 {
00726     if ((state < 0) || (state >= KIconLoader::LastState))
00727     {
00728         kWarning(264) << "Illegal icon state: " << state;
00729         state = KIconLoader::DefaultState;
00730     }
00731 
00732     if (size < 0) {
00733         size = 0;
00734     }
00735 
00736     // For "User" icons, bail early since the size should be based on the size on disk,
00737     // which we've already checked.
00738     if (group == KIconLoader::User) {
00739         return;
00740     }
00741 
00742     if ((group < -1) || (group >= KIconLoader::LastGroup))
00743     {
00744         kWarning(264) << "Illegal icon group: " << group;
00745         group = KIconLoader::Desktop;
00746     }
00747 
00748     // If size == 0, use default size for the specified group.
00749     if (size == 0)
00750     {
00751         if (group < 0)
00752         {
00753             kWarning(264) << "Neither size nor group specified!";
00754             group = KIconLoader::Desktop;
00755         }
00756         size = mpGroups[group].size;
00757     }
00758 }
00759 
00760 QString KIconLoaderPrivate::makeCacheKey(const QString &name, KIconLoader::Group group,
00761                                          const QStringList &overlays, int size, int state) const
00762 {
00763     // The KSharedDataCache is shared so add some namespacing. The following code
00764     // uses QStringBuilder (new in Qt 4.6)
00765 
00766     return (group == KIconLoader::User
00767                   ? QLatin1Literal("$kicou_")
00768                   : QLatin1Literal("$kico_"))
00769            % name
00770            % QLatin1Char('_')
00771            % QString::number(size)
00772            % QLatin1Char('_')
00773            % overlays.join("_")
00774            % ( group >= 0 ? mpEffect.fingerprint(group, state)
00775                           : *NULL_EFFECT_FINGERPRINT);
00776 }
00777 
00778 QImage KIconLoaderPrivate::createIconImage(const QString &path, int size)
00779 {
00780     // Use the extension as the format. Works for XPM and PNG, but not for SVG. The
00781     // "VGZ" is the last 3 characters of "SVGZ"
00782     QString ext = path.right(3).toUpper();
00783     QImage img;
00784 
00785     if (ext != "SVG" && ext != "VGZ")
00786     {
00787         // Not a SVG or SVGZ
00788         img = QImage(path, ext.toLatin1());
00789 
00790         if (size != 0 && !img.isNull()) {
00791             img = img.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
00792         }
00793     }
00794     else
00795     {
00796 #ifndef _WIN32_WCE
00797         QSvgRenderer renderer(path, q);
00798 
00799         if (renderer.isValid()) {
00800             img = QImage(size, size, QImage::Format_ARGB32_Premultiplied);
00801             img.fill(0);
00802             QPainter p(&img);
00803             renderer.render(&p);
00804         }
00805 #endif
00806     }
00807 
00808     return img;
00809 }
00810 
00811 void KIconLoaderPrivate::insertCachedPixmapWithPath(
00812     const QString &key,
00813     const QPixmap &data,
00814     const QString &path = QString())
00815 {
00816     // Even if the pixmap is null, we add it to the caches so that we record
00817     // the fact that whatever icon led to us getting a null pixmap doesn't
00818     // exist.
00819 
00820     QBuffer output;
00821     output.open(QIODevice::WriteOnly);
00822 
00823     QDataStream outputStream(&output);
00824     outputStream.setVersion(QDataStream::Qt_4_6);
00825 
00826     outputStream << path;
00827 
00828     // Convert the QPixmap to PNG. This is actually done by Qt's own operator.
00829     outputStream << data;
00830 
00831     output.close();
00832 
00833     // The byte array contained in the QBuffer is what we want in the cache.
00834     mIconCache->insert(key, output.buffer());
00835 
00836     // Also insert the object into our process-local cache for even more
00837     // speed.
00838     PixmapWithPath *pixmapPath = new PixmapWithPath;
00839     pixmapPath->pixmap = data;
00840     pixmapPath->path = path;
00841 
00842     mPixmapCache.insert(key, pixmapPath, data.width() * data.height() + 1);
00843 }
00844 
00845 bool KIconLoaderPrivate::findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path)
00846 {
00847     // If the pixmap is present in our local process cache, use that since we
00848     // don't need to decompress and upload it to the X server/graphics card.
00849     const PixmapWithPath *pixmapPath = mPixmapCache.object(key);
00850     if (pixmapPath) {
00851         path = pixmapPath->path;
00852         data = pixmapPath->pixmap;
00853 
00854         return true;
00855     }
00856 
00857     // Otherwise try to find it in our shared memory cache since that will
00858     // be quicker than the disk, especially for SVGs.
00859     QByteArray result;
00860 
00861     if (!mIconCache->find(key, &result) || result.isEmpty()) {
00862         return false;
00863     }
00864 
00865     QBuffer buffer;
00866     buffer.setBuffer(&result);
00867     buffer.open(QIODevice::ReadOnly);
00868 
00869     QDataStream inputStream(&buffer);
00870     inputStream.setVersion(QDataStream::Qt_4_6);
00871 
00872     QString tempPath;
00873     inputStream >> tempPath;
00874 
00875     if (inputStream.status() == QDataStream::Ok) {
00876         QPixmap tempPixmap;
00877         inputStream >> tempPixmap;
00878 
00879         if (inputStream.status() == QDataStream::Ok) {
00880             data = tempPixmap;
00881             path = tempPath;
00882 
00883             // Since we're here we didn't have a QPixmap cache entry, add one now.
00884             PixmapWithPath *newPixmapWithPath = new PixmapWithPath;
00885             newPixmapWithPath->pixmap = data;
00886             newPixmapWithPath->path = path;
00887 
00888             mPixmapCache.insert(key, newPixmapWithPath, data.width() * data.height() + 1);
00889 
00890             return true;
00891         }
00892     }
00893 
00894     return false;
00895 }
00896 
00897 K3Icon KIconLoaderPrivate::findMatchingIconWithGenericFallbacks(const QString& name, int size) const
00898 {
00899     K3Icon icon = findMatchingIcon(name, size);
00900     if (icon.isValid())
00901         return icon;
00902 
00903     const QString genericIcon = s_globalData->genericIconFor(name);
00904     if (!genericIcon.isEmpty()) {
00905         icon = findMatchingIcon(genericIcon, size);
00906     }
00907     return icon;
00908 }
00909 
00910 K3Icon KIconLoaderPrivate::findMatchingIcon(const QString& name, int size) const
00911 {
00912     const_cast<KIconLoaderPrivate*>(this)->initIconThemes();
00913 
00914     K3Icon icon;
00915 
00916 // The following code has been commented out because the Qt SVG renderer needs
00917 // to be improved. If you are going to change/remove some code from this part,
00918 // please contact me before (ereslibre@kde.org), or kde-core-devel@kde.org. (ereslibre)
00919 #ifdef KDE_QT_SVG_RENDERER_FIXED
00920     const char * ext1[4] = { ".png", ".svgz", ".svg", ".xpm" };
00921     const char * ext2[4] = { ".svgz", ".svg", ".png", ".xpm" };
00922     const char ** ext;
00923 
00924     if (size == KIconLoader::SizeSmall ||
00925         size == KIconLoader::SizeSmallMedium ||
00926         size == KIconLoader::SizeMedium ||
00927         size == KIconLoader::SizeLarge ||
00928         size == KIconLoader::SizeHuge ||
00929         size == KIconLoader::SizeEnormous)
00930     {
00931         ext = ext1; // size is standard, give preference to PNG over SVG when searching
00932     }
00933     else
00934     {
00935         ext = ext2; // size is non-standard, give preference to SVG over PNG when searching
00936     }
00937 
00938     /* If size parameter is a standard one, that means:
00939 
00940            - KIconLoader::SizeSmall
00941            - KIconLoader::SizeSmallMedium
00942            - KIconLoader::SizeMedium
00943            - KIconLoader::SizeLarge
00944            - KIconLoader::SizeHuge
00945            - KIconLoader::SizeEnormous
00946 
00947        To follow the XDG icon theme and icon naming specifications,
00948        the order in which we look for an icon is:
00949 
00950        png, svgz, svg, xpm exact match
00951        png, svgz, svg, xpm best match
00952        less specific fallback in this theme: png, svgz, svg, xpm exact match
00953                                              png, svgz, svg, xpm best match
00954        even less specific fallback in this theme: [same order]
00955        (...)
00956 
00957        next theme in inheritance tree: png, svgz, svg, xpm exact match
00958                                        png, svgz, svg, xpm best match
00959        less specific fallbacks in this next theme
00960        (...)
00961 
00962        next theme in inheritance tree: png, svgz, svg, xpm exact match
00963                                        png, svgz, svg, xpm best match
00964        less specific fallbacks in this next theme
00965        (...)
00966 
00967        and so on.
00968 
00969        If size parameter is a non-standard one, then we give more preference to
00970        SVG format since drawing SVG's gives better quality and despite being
00971        slower than resizing a PNG image, the cases where non-standard sizes are
00972        asked are very rare. For non-standard sizes what we have is:
00973 
00974        svgz, svg, png, xpm exact match
00975        svgz, svg, png, xpm best match
00976        less specific fallback in this theme: svgz, svg, png, xpm exact match
00977                                              svgz, svg, png, xpm best match
00978        even less specific fallback in this theme: [same order]
00979        (...)
00980 
00981        next theme in inheritance tree: svgz, svg, png, xpm exact match
00982                                        svgz, svg, png, xpm best match
00983        less specific fallbacks in this next theme
00984        (...)
00985 
00986        next theme in inheritance tree: svgz, svg, png, xpm exact match
00987                                        svgz, svg, png, xpm best match
00988        less specific fallbacks in this next theme
00989        (...)
00990 
00991        and so on.
00992        */
00993 #else
00994     const char * const ext[4] = { ".png", ".svgz", ".svg", ".xpm" };
00995 #endif
00996 
00997     bool genericFallback = name.endsWith(QLatin1String("-x-generic"));
00998 
00999     foreach(KIconThemeNode *themeNode, links)
01000     {
01001         QString currentName = name;
01002 
01003         while (!currentName.isEmpty())
01004         {
01005 
01006             //kDebug(264) << "Looking up" << currentName;
01007 
01008 // The following code has been commented out because the Qt SVG renderer needs
01009 // to be improved. If you are going to change/remove some code from this part,
01010 // please contact me before (ereslibre@kde.org), or kde-core-devel@kde.org. (ereslibre)
01011 #ifdef KDE_QT_SVG_RENDERER_FIXED
01012             for (int i = 0 ; i < 4 ; i++)
01013             {
01014                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchExact);
01015                 if (icon.isValid())
01016                     return icon;
01017             }
01018 
01019             for (int i = 0 ; i < 4 ; i++)
01020             {
01021                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchBest);
01022                 if (icon.isValid())
01023                     return icon;
01024             }
01025 #else
01026             for (int i = 0 ; i < 4 ; i++)
01027             {
01028                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchExact);
01029                 if (icon.isValid())
01030                     return icon;
01031 
01032                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchBest);
01033                 if (icon.isValid())
01034                     return icon;
01035             }
01036 #endif
01037             if (genericFallback)
01038                 // we already tested the base name
01039                 break;
01040 
01041             int rindex = currentName.lastIndexOf('-');
01042             if (rindex > 1) { // > 1 so that we don't split x-content or x-epoc
01043                 currentName.truncate(rindex);
01044 
01045                 if (currentName.endsWith(QLatin1String("-x")))
01046                     currentName.chop(2);
01047             } else {
01048                 // From update-mime-database.c
01049                 static const QSet<QString> mediaTypes = QSet<QString>()
01050                     << "text" << "application" << "image" << "audio"
01051                     << "inode" << "video" << "message" << "model" << "multipart"
01052                     << "x-content" << "x-epoc";
01053                 // Shared-mime-info spec says:
01054                 // "If [generic-icon] is not specified then the mimetype is used to generate the
01055                 // generic icon by using the top-level media type (e.g. "video" in "video/ogg")
01056                 // and appending "-x-generic" (i.e. "video-x-generic" in the previous example)."
01057                 if (mediaTypes.contains(currentName)) {
01058                     currentName += QLatin1String("-x-generic");
01059                     genericFallback = true;
01060                 } else {
01061                     break;
01062                 }
01063             }
01064         }
01065     }
01066     return icon;
01067 }
01068 
01069 inline QString KIconLoaderPrivate::unknownIconPath( int size ) const
01070 {
01071     static const QString &str_unknown = KGlobal::staticQString("unknown");
01072 
01073     K3Icon icon = findMatchingIcon(str_unknown, size);
01074     if (!icon.isValid())
01075     {
01076         kDebug(264) << "Warning: could not find \"Unknown\" icon for size = "
01077                      << size << endl;
01078         return QString();
01079     }
01080     return icon.path;
01081 }
01082 
01083 // Finds the absolute path to an icon.
01084 
01085 QString KIconLoader::iconPath(const QString& _name, int group_or_size,
01086                               bool canReturnNull) const
01087 {
01088     if (!d->initIconThemes()) {
01089         return QString();
01090     }
01091 
01092     if (_name.isEmpty() || !pathIsRelative(_name))
01093     {
01094         // we have either an absolute path or nothing to work with
01095         return _name;
01096     }
01097 
01098     QString name = d->removeIconExtension( _name );
01099 
01100     QString path;
01101     if (group_or_size == KIconLoader::User)
01102     {
01103         static const QString &png_ext = KGlobal::staticQString(".png");
01104         static const QString &xpm_ext = KGlobal::staticQString(".xpm");
01105         path = d->mpDirs->findResource("appicon", name + png_ext);
01106 
01107         static const QString &svgz_ext = KGlobal::staticQString(".svgz");
01108         static const QString &svg_ext = KGlobal::staticQString(".svg");
01109         if (path.isEmpty())
01110             path = d->mpDirs->findResource("appicon", name + svgz_ext);
01111         if (path.isEmpty())
01112             path = d->mpDirs->findResource("appicon", name + svg_ext);
01113         if (path.isEmpty())
01114             path = d->mpDirs->findResource("appicon", name + xpm_ext);
01115         return path;
01116     }
01117 
01118     if (group_or_size >= KIconLoader::LastGroup)
01119     {
01120         kDebug(264) << "Illegal icon group: " << group_or_size;
01121         return path;
01122     }
01123 
01124     int size;
01125     if (group_or_size >= 0)
01126         size = d->mpGroups[group_or_size].size;
01127     else
01128         size = -group_or_size;
01129 
01130     if (_name.isEmpty()) {
01131         if (canReturnNull)
01132             return QString();
01133         else
01134             return d->unknownIconPath(size);
01135     }
01136 
01137     K3Icon icon = d->findMatchingIconWithGenericFallbacks(name, size);
01138 
01139     if (!icon.isValid())
01140     {
01141         // Try "User" group too.
01142         path = iconPath(name, KIconLoader::User, true);
01143         if (!path.isEmpty() || canReturnNull)
01144             return path;
01145 
01146         return d->unknownIconPath(size);
01147     }
01148     return icon.path;
01149 }
01150 
01151 QPixmap KIconLoader::loadMimeTypeIcon( const QString& _iconName, KIconLoader::Group group, int size,
01152                                        int state, const QStringList& overlays, QString *path_store ) const
01153 {
01154     QString iconName = _iconName;
01155     const int slashindex = iconName.indexOf(QLatin1Char('/'));
01156     if (slashindex != -1) {
01157         iconName[slashindex] = QLatin1Char('-');
01158     }
01159 
01160     if ( !d->extraDesktopIconsLoaded )
01161     {
01162         const QPixmap pixmap = loadIcon( iconName, group, size, state, overlays, path_store, true );
01163         if (!pixmap.isNull() ) {
01164             return pixmap;
01165         }
01166         const_cast<KIconLoader *>(this)->addExtraDesktopThemes();
01167     }
01168     const QPixmap pixmap = loadIcon(iconName, group, size, state, overlays, path_store, true);
01169     if (pixmap.isNull()) {
01170         // Icon not found, fallback to application/octet-stream
01171         return loadIcon("application-octet-stream", group, size, state, overlays, path_store, false);
01172     }
01173     return pixmap;
01174 }
01175 
01176 QPixmap KIconLoader::loadIcon(const QString& _name, KIconLoader::Group group, int size,
01177                               int state, const QStringList& overlays,
01178                               QString *path_store, bool canReturnNull) const
01179 {
01180     QString name = _name;
01181     bool favIconOverlay = false;
01182 
01183     if (size < 0 || _name.isEmpty())
01184         return QPixmap();
01185 
01186     /*
01187      * This method works in a kind of pipeline, with the following steps:
01188      * 1. Sanity checks.
01189      * 2. Convert _name, group, size, etc. to a key name.
01190      * 3. Check if the key is already cached.
01191      * 4. If not, initialize the theme and find/load the icon.
01192      * 4a Apply overlays
01193      * 4b Re-add to cache.
01194      */
01195 
01196     // Special case for absolute path icons.
01197     if (name.startsWith(QLatin1String("favicons/")))
01198     {
01199        favIconOverlay = true;
01200        name = KStandardDirs::locateLocal("cache", name+".png");
01201     }
01202 
01203     bool absolutePath = !pathIsRelative(name);
01204     if (!absolutePath) {
01205         name = d->removeIconExtension(name);
01206     }
01207 
01208     // Don't bother looking for an icon with no name.
01209     if (name.isEmpty()) {
01210         return QPixmap();
01211     }
01212 
01213     // May modify group, size, or state. This function puts them into sane
01214     // states.
01215     d->normalizeIconMetadata(group, size, state);
01216 
01217     // See if the image is already cached.
01218     QString key = d->makeCacheKey(name, group, overlays, size, state);
01219     QPixmap pix;
01220     bool iconWasUnknown = false;
01221     K3Icon icon;
01222 
01223     // icon.path would be empty for "unknown" icons, which should be searched for
01224     // anew each time.
01225     if (d->findCachedPixmapWithPath(key, pix, icon.path) && !icon.path.isEmpty()) {
01226         if (path_store) {
01227             *path_store = icon.path;
01228         }
01229 
01230         return pix;
01231     }
01232 
01233     // Image is not cached... go find it and apply effects.
01234     if (!d->initIconThemes()) {
01235         return QPixmap();
01236     }
01237 
01238     favIconOverlay = favIconOverlay && size > 22;
01239 
01240     // First we look for non-User icons. If we don't find one we'd search in
01241     // the User space anyways...
01242     if (group != KIconLoader::User) {
01243         // K3Icon seems to hold some needed information.
01244 
01245         if (absolutePath && !favIconOverlay)
01246         {
01247             icon.context = KIconLoader::Any;
01248             icon.type = KIconLoader::Scalable;
01249             icon.path = name;
01250         }
01251         else
01252         {
01253             icon = d->findMatchingIconWithGenericFallbacks(favIconOverlay ? QString("text-html") : name, size);
01254         }
01255     }
01256 
01257     if (icon.path.isEmpty()) {
01258         // We do have a "User" icon, or we couldn't find the non-User one.
01259         icon.path = (absolutePath) ? name :
01260                         iconPath(name, KIconLoader::User, canReturnNull);
01261     }
01262 
01263     // Still can't find it? Use "unknown" if we can't return null.
01264     // We keep going in the function so we can ensure this result gets cached.
01265     if (icon.path.isEmpty() && !canReturnNull) {
01266         icon.path = d->unknownIconPath(size);
01267         iconWasUnknown = true;
01268     }
01269 
01270     QImage img = d->createIconImage(icon.path, size);
01271 
01272     if (group >= 0)
01273     {
01274         img = d->mpEffect.apply(img, group, state);
01275     }
01276 
01277     if (favIconOverlay)
01278     {
01279         QImage favIcon(name, "PNG");
01280         if (!favIcon.isNull()) // if favIcon not there yet, don't try to blend it
01281         {
01282             QPainter p(&img);
01283 
01284             // Align the favicon overlay
01285             QRect r(favIcon.rect());
01286             r.moveBottomRight(img.rect().bottomRight());
01287             r.adjust(-1, -1, -1, -1); // Move off edge
01288 
01289             // Blend favIcon over img.
01290             p.drawImage(r, favIcon);
01291         }
01292     }
01293 
01294     pix = QPixmap::fromImage(img);
01295 
01296     // TODO: If we make a loadIcon that returns the image we can convert
01297     // drawOverlays to use the image instead of pixmaps as well so we don't
01298     // have to transfer so much to the graphics card.
01299     d->drawOverlays(this, group, state, pix, overlays);
01300 
01301     // Don't add the path to our unknown icon to the cache, only cache the
01302     // actual image.
01303     if (iconWasUnknown) {
01304         icon.path.clear();
01305     }
01306 
01307     d->insertCachedPixmapWithPath(key, pix, icon.path);
01308 
01309     if (path_store) {
01310         *path_store = icon.path;
01311     }
01312 
01313     return pix;
01314 }
01315 
01316 QMovie *KIconLoader::loadMovie(const QString& name, KIconLoader::Group group, int size, QObject *parent) const
01317 {
01318     QString file = moviePath( name, group, size );
01319     if (file.isEmpty())
01320         return 0;
01321     int dirLen = file.lastIndexOf('/');
01322     QString icon = iconPath(name, size ? -size : group, true);
01323     if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
01324         return 0;
01325     QMovie *movie = new QMovie(file, QByteArray(), parent);
01326     if (!movie->isValid())
01327     {
01328         delete movie;
01329         return 0;
01330     }
01331     return movie;
01332 }
01333 
01334 QString KIconLoader::moviePath(const QString& name, KIconLoader::Group group, int size) const
01335 {
01336     if (!d->mpGroups) return QString();
01337 
01338     d->initIconThemes();
01339 
01340     if ( (group < -1 || group >= KIconLoader::LastGroup) && group != KIconLoader::User )
01341     {
01342         kDebug(264) << "Illegal icon group: " << group;
01343         group = KIconLoader::Desktop;
01344     }
01345     if (size == 0 && group < 0)
01346     {
01347         kDebug(264) << "Neither size nor group specified!";
01348         group = KIconLoader::Desktop;
01349     }
01350 
01351     QString file = name + ".mng";
01352     if (group == KIconLoader::User)
01353     {
01354         file = d->mpDirs->findResource("appicon", file);
01355     }
01356     else
01357     {
01358         if (size == 0)
01359             size = d->mpGroups[group].size;
01360 
01361         K3Icon icon;
01362 
01363         foreach(KIconThemeNode *themeNode, d->links)
01364         {
01365             icon = themeNode->theme->iconPath(file, size, KIconLoader::MatchExact);
01366             if (icon.isValid())
01367                 break;
01368         }
01369 
01370         if ( !icon.isValid() )
01371         {
01372             foreach(KIconThemeNode *themeNode, d->links)
01373             {
01374                 icon = themeNode->theme->iconPath(file, size, KIconLoader::MatchBest);
01375                 if (icon.isValid())
01376                     break;
01377             }
01378         }
01379 
01380         file = icon.isValid() ? icon.path : QString();
01381     }
01382     return file;
01383 }
01384 
01385 
01386 QStringList KIconLoader::loadAnimated(const QString& name, KIconLoader::Group group, int size) const
01387 {
01388     QStringList lst;
01389 
01390     if (!d->mpGroups) return lst;
01391 
01392     d->initIconThemes();
01393 
01394     if ((group < -1) || (group >= KIconLoader::LastGroup))
01395     {
01396         kDebug(264) << "Illegal icon group: " << group;
01397         group = KIconLoader::Desktop;
01398     }
01399     if ((size == 0) && (group < 0))
01400     {
01401         kDebug(264) << "Neither size nor group specified!";
01402         group = KIconLoader::Desktop;
01403     }
01404 
01405     QString file = name + "/0001";
01406     if (group == KIconLoader::User)
01407     {
01408         file = d->mpDirs->findResource("appicon", file + ".png");
01409     } else
01410     {
01411         if (size == 0)
01412             size = d->mpGroups[group].size;
01413         K3Icon icon = d->findMatchingIcon(file, size);
01414         file = icon.isValid() ? icon.path : QString();
01415 
01416     }
01417     if (file.isEmpty())
01418         return lst;
01419 
01420     QString path = file.left(file.length()-8);
01421     DIR* dp = opendir( QFile::encodeName(path) );
01422     if(!dp)
01423         return lst;
01424 
01425     KDE_struct_dirent* ep;
01426     while( ( ep = KDE_readdir( dp ) ) != 0L )
01427     {
01428         QString fn(QFile::decodeName(ep->d_name));
01429         if(!(fn.left(4)).toUInt())
01430             continue;
01431 
01432         lst += path + fn;
01433     }
01434     closedir ( dp );
01435     lst.sort();
01436     return lst;
01437 }
01438 
01439 KIconTheme *KIconLoader::theme() const
01440 {
01441     d->initIconThemes();
01442     if (d->mpThemeRoot) return d->mpThemeRoot->theme;
01443     return 0L;
01444 }
01445 
01446 int KIconLoader::currentSize(KIconLoader::Group group) const
01447 {
01448     if (!d->mpGroups) return -1;
01449 
01450     if (group < 0 || group >= KIconLoader::LastGroup)
01451     {
01452         kDebug(264) << "Illegal icon group: " << group;
01453         return -1;
01454     }
01455     return d->mpGroups[group].size;
01456 }
01457 
01458 QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
01459 {
01460     const QDir dir(iconsDir);
01461     const QStringList formats = QStringList() << "*.png" << "*.xpm" << "*.svg" << "*.svgz";
01462     const QStringList lst = dir.entryList(formats, QDir::Files);
01463     QStringList result;
01464     QStringList::ConstIterator it;
01465     for (it=lst.begin(); it!=lst.end(); ++it)
01466         result += iconsDir + '/' + *it;
01467     return result;
01468 }
01469 
01470 QStringList KIconLoader::queryIconsByContext(int group_or_size,
01471                                              KIconLoader::Context context) const
01472 {
01473     d->initIconThemes();
01474 
01475     QStringList result;
01476     if (group_or_size >= KIconLoader::LastGroup)
01477     {
01478         kDebug(264) << "Illegal icon group: " << group_or_size;
01479         return result;
01480     }
01481     int size;
01482     if (group_or_size >= 0)
01483         size = d->mpGroups[group_or_size].size;
01484     else
01485         size = -group_or_size;
01486 
01487     foreach(KIconThemeNode *themeNode, d->links)
01488        themeNode->queryIconsByContext(&result, size, context);
01489 
01490     // Eliminate duplicate entries (same icon in different directories)
01491     QString name;
01492     QStringList res2, entries;
01493     QStringList::ConstIterator it;
01494     for (it=result.constBegin(); it!=result.constEnd(); ++it)
01495     {
01496         int n = (*it).lastIndexOf('/');
01497         if (n == -1)
01498             name = *it;
01499         else
01500             name = (*it).mid(n+1);
01501         name = d->removeIconExtension(name);
01502         if (!entries.contains(name))
01503         {
01504             entries += name;
01505             res2 += *it;
01506         }
01507     }
01508     return res2;
01509 
01510 }
01511 
01512 QStringList KIconLoader::queryIcons(int group_or_size, KIconLoader::Context context) const
01513 {
01514     d->initIconThemes();
01515 
01516     QStringList result;
01517     if (group_or_size >= KIconLoader::LastGroup)
01518     {
01519         kDebug(264) << "Illegal icon group: " << group_or_size;
01520         return result;
01521     }
01522     int size;
01523     if (group_or_size >= 0)
01524         size = d->mpGroups[group_or_size].size;
01525     else
01526         size = -group_or_size;
01527 
01528     foreach(KIconThemeNode *themeNode, d->links)
01529        themeNode->queryIcons(&result, size, context);
01530 
01531     // Eliminate duplicate entries (same icon in different directories)
01532     QString name;
01533     QStringList res2, entries;
01534     QStringList::ConstIterator it;
01535     for (it=result.constBegin(); it!=result.constEnd(); ++it)
01536     {
01537         int n = (*it).lastIndexOf('/');
01538         if (n == -1)
01539             name = *it;
01540         else
01541             name = (*it).mid(n+1);
01542         name = d->removeIconExtension(name);
01543         if (!entries.contains(name))
01544         {
01545             entries += name;
01546             res2 += *it;
01547         }
01548     }
01549     return res2;
01550 }
01551 
01552 // used by KIconDialog to find out which contexts to offer in a combobox
01553 bool KIconLoader::hasContext(KIconLoader::Context context) const
01554 {
01555     d->initIconThemes();
01556 
01557     foreach(KIconThemeNode *themeNode, d->links)
01558        if( themeNode->theme->hasContext( context ))
01559            return true;
01560     return false;
01561 }
01562 
01563 KIconEffect * KIconLoader::iconEffect() const
01564 {
01565     return &d->mpEffect;
01566 }
01567 
01568 bool KIconLoader::alphaBlending(KIconLoader::Group group) const
01569 {
01570     if (!d->mpGroups) return false;
01571 
01572     if (group < 0 || group >= KIconLoader::LastGroup)
01573     {
01574         kDebug(264) << "Illegal icon group: " << group;
01575         return false;
01576     }
01577     return d->mpGroups[group].alphaBlending;
01578 }
01579 
01580 // deprecated
01581 #ifndef KDE_NO_DEPRECATED
01582 QIcon KIconLoader::loadIconSet( const QString& name, KIconLoader::Group g, int s,
01583                                 bool canReturnNull )
01584 {
01585     QIcon iconset;
01586     QPixmap tmp = loadIcon(name, g, s, KIconLoader::ActiveState, QStringList(), NULL, canReturnNull);
01587     iconset.addPixmap( tmp, QIcon::Active, QIcon::On );
01588     // we don't use QIconSet's resizing anyway
01589     tmp = loadIcon(name, g, s, KIconLoader::DisabledState, QStringList(), NULL, canReturnNull);
01590     iconset.addPixmap( tmp, QIcon::Disabled, QIcon::On );
01591     tmp = loadIcon(name, g, s, KIconLoader::DefaultState, QStringList(), NULL, canReturnNull);
01592     iconset.addPixmap( tmp, QIcon::Normal, QIcon::On );
01593     return iconset;
01594 }
01595 #endif
01596 
01597 // Easy access functions
01598 
01599 QPixmap DesktopIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01600 {
01601     KIconLoader *loader = KIconLoader::global();
01602     return loader->loadIcon(name, KIconLoader::Desktop, force_size, state, overlays);
01603 }
01604 
01605 // deprecated
01606 #ifndef KDE_NO_DEPRECATED
01607 QIcon DesktopIconSet(const QString& name, int force_size)
01608 {
01609     KIconLoader *loader = KIconLoader::global();
01610     return loader->loadIconSet(name, KIconLoader::Desktop, force_size);
01611 }
01612 #endif
01613 
01614 QPixmap BarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01615 {
01616     KIconLoader *loader = KIconLoader::global();
01617     return loader->loadIcon(name, KIconLoader::Toolbar, force_size, state, overlays);
01618 }
01619 
01620 // deprecated
01621 #ifndef KDE_NO_DEPRECATED
01622 QIcon BarIconSet(const QString& name, int force_size)
01623 {
01624     KIconLoader *loader = KIconLoader::global();
01625     return loader->loadIconSet( name, KIconLoader::Toolbar, force_size );
01626 }
01627 #endif
01628 
01629 QPixmap SmallIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01630 {
01631     KIconLoader *loader = KIconLoader::global();
01632     return loader->loadIcon(name, KIconLoader::Small, force_size, state, overlays);
01633 }
01634 
01635 // deprecated
01636 #ifndef KDE_NO_DEPRECATED
01637 QIcon SmallIconSet(const QString& name, int force_size)
01638 {
01639     KIconLoader *loader = KIconLoader::global();
01640     return loader->loadIconSet( name, KIconLoader::Small, force_size );
01641 }
01642 #endif
01643 
01644 QPixmap MainBarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01645 {
01646     KIconLoader *loader = KIconLoader::global();
01647     return loader->loadIcon(name, KIconLoader::MainToolbar, force_size, state, overlays);
01648 }
01649 
01650 // deprecated
01651 #ifndef KDE_NO_DEPRECATED
01652 QIcon MainBarIconSet(const QString& name, int force_size)
01653 {
01654     KIconLoader *loader = KIconLoader::global();
01655     return loader->loadIconSet( name, KIconLoader::MainToolbar, force_size );
01656 }
01657 #endif
01658 
01659 QPixmap UserIcon(const QString& name, int state, const QStringList &overlays)
01660 {
01661     KIconLoader *loader = KIconLoader::global();
01662     return loader->loadIcon(name, KIconLoader::User, 0, state, overlays);
01663 }
01664 
01665 // deprecated
01666 #ifndef KDE_NO_DEPRECATED
01667 QIcon UserIconSet(const QString& name)
01668 {
01669     KIconLoader *loader = KIconLoader::global();
01670     return loader->loadIconSet( name, KIconLoader::User );
01671 }
01672 #endif
01673 
01674 int IconSize(KIconLoader::Group group)
01675 {
01676     KIconLoader *loader = KIconLoader::global();
01677     return loader->currentSize(group);
01678 }
01679 
01680 QPixmap KIconLoader::unknown()
01681 {
01682     QPixmap pix;
01683     if ( QPixmapCache::find("unknown", pix) ) //krazy:exclude=iconnames
01684             return pix;
01685 
01686     QString path = global()->iconPath("unknown", KIconLoader::Small, true); //krazy:exclude=iconnames
01687     if (path.isEmpty())
01688     {
01689         kDebug(264) << "Warning: Cannot find \"unknown\" icon.";
01690         pix = QPixmap(32,32);
01691     } else
01692     {
01693         pix.load(path);
01694         QPixmapCache::insert("unknown", pix); //krazy:exclude=iconnames
01695     }
01696 
01697     return pix;
01698 }
01699 
01700 /*** the global icon loader ***/
01701 K_GLOBAL_STATIC_WITH_ARGS(KIconLoader, globalIconLoader, (KGlobal::mainComponent(), 0))
01702 
01703 KIconLoader *KIconLoader::global()
01704 {
01705     return globalIconLoader;
01706 }
01707 
01708 void KIconLoader::newIconLoader()
01709 {
01710     if ( global() == this) {
01711         KIconTheme::reconfigure();
01712     }
01713 
01714     reconfigure( objectName(), d->mpDirs );
01715     emit iconLoaderSettingsChanged();
01716 }
01717 
01718 #include "kiconloader.moc"
01719 
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:32:40 by doxygen 1.7.5.1 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.9.5 API Reference

Skip menu "kdelibs-4.9.5 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