• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • 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     delete d;
00456     d = new KIconLoaderPrivate(this);
00457     d->init( _appname, _dirs );
00458 }
00459 
00460 void KIconLoaderPrivate::init( const QString& _appname, KStandardDirs *_dirs )
00461 {
00462     extraDesktopIconsLoaded=false;
00463     mIconThemeInited = false;
00464     mpThemeRoot = 0;
00465 
00466     if (_dirs)
00467         mpDirs = _dirs;
00468     else
00469         mpDirs = KGlobal::dirs();
00470 
00471     appname = _appname;
00472     if (appname.isEmpty())
00473         appname = KGlobal::mainComponent().componentName();
00474 
00475     // Initialize icon cache
00476     mIconCache = new KSharedDataCache("icon-cache", 10 * 1024 * 1024);
00477     // Cost here is number of pixels, not size. So this is actually a bit
00478     // smaller.
00479     mPixmapCache.setMaxCost(10 * 1024 * 1024);
00480 
00481     // These have to match the order in kicontheme.h
00482     static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", "Dialog", 0L };
00483     KSharedConfig::Ptr config = KGlobal::config();
00484 
00485     // loading config and default sizes
00486     initIconThemes();
00487     KIconTheme *defaultSizesTheme = links.empty() ? 0 : links.first()->theme;
00488     mpGroups = new KIconGroup[(int) KIconLoader::LastGroup];
00489     for (KIconLoader::Group i = KIconLoader::FirstGroup; i < KIconLoader::LastGroup; ++i) {
00490         if (groups[i] == 0L) {
00491             break;
00492         }
00493 
00494         KConfigGroup cg(config, QLatin1String(groups[i]) + "Icons");
00495         mpGroups[i].size = cg.readEntry("Size", 0);
00496         if (QPixmap::defaultDepth() > 8) {
00497             mpGroups[i].alphaBlending = cg.readEntry("AlphaBlending", true);
00498         } else {
00499             mpGroups[i].alphaBlending = false;
00500         }
00501 
00502         if (!mpGroups[i].size && defaultSizesTheme) {
00503             mpGroups[i].size = defaultSizesTheme->defaultSize(i);
00504         }
00505     }
00506 }
00507 
00508 bool KIconLoaderPrivate::initIconThemes()
00509 {
00510     if (mIconThemeInited) {
00511         // If mpThemeRoot isn't 0 then initing has succeeded
00512         return (mpThemeRoot != 0);
00513     }
00514     //kDebug(264);
00515     mIconThemeInited = true;
00516 
00517     // Add the default theme and its base themes to the theme tree
00518     KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00519     if (!def->isValid())
00520     {
00521         delete def;
00522         // warn, as this is actually a small penalty hit
00523         kDebug(264) << "Couldn't find current icon theme, falling back to default.";
00524         def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00525         if (!def->isValid())
00526         {
00527             kError(264) << "Error: standard icon theme" << KIconTheme::defaultThemeName() << "not found!" << endl;
00528             delete def;
00529             return false;
00530         }
00531     }
00532     mpThemeRoot = new KIconThemeNode(def);
00533     mThemesInTree.append(def->internalName());
00534     links.append(mpThemeRoot);
00535     addBaseThemes(mpThemeRoot, appname);
00536 
00537     // Insert application specific themes at the top.
00538     mpDirs->addResourceType("appicon", "data", appname + "/pics/");
00539     // ################## KDE5: consider removing the toolbar directory
00540     mpDirs->addResourceType("appicon", "data", appname + "/toolbar/");
00541 
00542     // Add legacy icon dirs.
00543     QStringList dirs;
00544     dirs += mpDirs->resourceDirs("icon");
00545     dirs += mpDirs->resourceDirs("pixmap");
00546     dirs += mpDirs->resourceDirs("xdgdata-icon");
00547     dirs += "/usr/share/pixmaps";
00548     // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
00549     dirs += mpDirs->resourceDirs("xdgdata-pixmap");
00550     for (QStringList::ConstIterator it = dirs.constBegin(); it != dirs.constEnd(); ++it)
00551         mpDirs->addResourceDir("appicon", *it);
00552 
00553 #ifndef NDEBUG
00554     QString dbgString = "Theme tree: ";
00555     mpThemeRoot->printTree(dbgString);
00556     kDebug(264) << dbgString;
00557 #endif
00558 
00559     return true;
00560 }
00561 
00562 KIconLoader::~KIconLoader()
00563 {
00564     delete d;
00565 }
00566 
00567 void KIconLoader::addAppDir(const QString& appname)
00568 {
00569     d->initIconThemes();
00570 
00571     d->mpDirs->addResourceType("appicon", "data", appname + "/pics/");
00572     // ################## KDE5: consider removing the toolbar directory
00573     d->mpDirs->addResourceType("appicon", "data", appname + "/toolbar/");
00574     d->addAppThemes(appname);
00575 }
00576 
00577 void KIconLoaderPrivate::addAppThemes(const QString& appname)
00578 {
00579     initIconThemes();
00580 
00581     KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00582     if (!def->isValid()) {
00583         delete def;
00584         def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00585     }
00586     KIconThemeNode* node = new KIconThemeNode(def);
00587     bool addedToLinks = false;
00588 
00589     if (!mThemesInTree.contains(node->theme->internalName())) {
00590         mThemesInTree.append(node->theme->internalName());
00591         links.append(node);
00592         addedToLinks = true;
00593     }
00594     addBaseThemes(node, appname);
00595 
00596     if (!addedToLinks) {
00597         // Nodes in links are being deleted later - this one needs manual care.
00598         delete node;
00599     }
00600 }
00601 
00602 void KIconLoaderPrivate::addBaseThemes(KIconThemeNode *node, const QString &appname)
00603 {
00604     // Quote from the icon theme specification:
00605     //   The lookup is done first in the current theme, and then recursively
00606     //   in each of the current theme's parents, and finally in the
00607     //   default theme called "hicolor" (implementations may add more
00608     //   default themes before "hicolor", but "hicolor" must be last).
00609     //
00610     // So we first make sure that all inherited themes are added, then we
00611     // add the KDE default theme as fallback for all icons that might not be
00612     // present in an inherited theme, and hicolor goes last.
00613 
00614     addInheritedThemes(node, appname);
00615     addThemeByName(KIconTheme::defaultThemeName(), appname);
00616     addThemeByName("hicolor", appname);
00617 }
00618 
00619 void KIconLoaderPrivate::addInheritedThemes(KIconThemeNode *node, const QString &appname)
00620 {
00621     const QStringList lst = node->theme->inherits();
00622 
00623     for (QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) {
00624         if ((*it) == "hicolor") {
00625           // The icon theme spec says that "hicolor" must be the very last
00626           // of all inherited themes, so don't add it here but at the very end
00627           // of addBaseThemes().
00628           continue;
00629         }
00630         addThemeByName(*it, appname);
00631     }
00632 }
00633 
00634 void KIconLoaderPrivate::addThemeByName(const QString &themename, const QString &appname)
00635 {
00636     if (mThemesInTree.contains(themename + appname)) {
00637         return;
00638     }
00639     KIconTheme *theme = new KIconTheme(themename, appname);
00640     if (!theme->isValid()) {
00641         delete theme;
00642         return;
00643     }
00644     KIconThemeNode *n = new KIconThemeNode(theme);
00645     mThemesInTree.append(themename + appname);
00646     links.append(n);
00647     addInheritedThemes(n, appname);
00648 }
00649 
00650 void KIconLoader::addExtraDesktopThemes()
00651 {
00652     if ( d->extraDesktopIconsLoaded ) return;
00653 
00654     d->initIconThemes();
00655 
00656     QStringList list;
00657     const QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
00658     QStringList::ConstIterator it;
00659     char buf[1000];
00660     int r;
00661     for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00662     {
00663         QDir dir(*it);
00664         if (!dir.exists())
00665             continue;
00666         const QStringList lst = dir.entryList(QStringList( "default.*" ), QDir::Dirs);
00667         QStringList::ConstIterator it2;
00668         for (it2=lst.begin(); it2!=lst.end(); ++it2)
00669         {
00670             if (!KStandardDirs::exists(*it + *it2 + "/index.desktop")
00671                 && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
00672                 continue;
00673             r=readlink( QFile::encodeName(*it + *it2) , buf, sizeof(buf)-1);
00674             if ( r>0 )
00675             {
00676                 buf[r]=0;
00677                 const QDir dir2( buf );
00678                 QString themeName=dir2.dirName();
00679 
00680                 if (!list.contains(themeName))
00681                     list.append(themeName);
00682             }
00683         }
00684     }
00685 
00686     for (it = list.constBegin(); it != list.constEnd(); ++it)
00687     {
00688         // Don't add the KDE defaults once more, we have them anyways.
00689         if (*it == QLatin1String("default.kde")
00690             || *it == QLatin1String("default.kde4")) {
00691             continue;
00692         }
00693         d->addThemeByName(*it, "");
00694     }
00695 
00696     d->extraDesktopIconsLoaded=true;
00697 
00698 }
00699 
00700 bool KIconLoader::extraDesktopThemesAdded() const
00701 {
00702     return d->extraDesktopIconsLoaded;
00703 }
00704 
00705 void KIconLoader::drawOverlays(const QStringList &overlays, QPixmap &pixmap, KIconLoader::Group group, int state) const
00706 {
00707     d->drawOverlays(this, group, state, pixmap, overlays);
00708 }
00709 
00710 QString KIconLoaderPrivate::removeIconExtension(const QString &name) const
00711 {
00712     if (name.endsWith(QLatin1String(".png"))
00713         || name.endsWith(QLatin1String(".xpm"))
00714         || name.endsWith(QLatin1String(".svg"))) {
00715         return name.left(name.length() - 4);
00716     } else if (name.endsWith(QLatin1String(".svgz"))) {
00717         return name.left(name.length() - 5);
00718     }
00719 
00720     return name;
00721 }
00722 
00723 void KIconLoaderPrivate::normalizeIconMetadata(KIconLoader::Group &group, int &size, int &state) const
00724 {
00725     if ((state < 0) || (state >= KIconLoader::LastState))
00726     {
00727         kWarning(264) << "Illegal icon state: " << state;
00728         state = KIconLoader::DefaultState;
00729     }
00730 
00731     if (size < 0) {
00732         size = 0;
00733     }
00734 
00735     // For "User" icons, bail early since the size should be based on the size on disk,
00736     // which we've already checked.
00737     if (group == KIconLoader::User) {
00738         return;
00739     }
00740 
00741     if ((group < -1) || (group >= KIconLoader::LastGroup))
00742     {
00743         kWarning(264) << "Illegal icon group: " << group;
00744         group = KIconLoader::Desktop;
00745     }
00746 
00747     // If size == 0, use default size for the specified group.
00748     if (size == 0)
00749     {
00750         if (group < 0)
00751         {
00752             kWarning(264) << "Neither size nor group specified!";
00753             group = KIconLoader::Desktop;
00754         }
00755         size = mpGroups[group].size;
00756     }
00757 }
00758 
00759 QString KIconLoaderPrivate::makeCacheKey(const QString &name, KIconLoader::Group group,
00760                                          const QStringList &overlays, int size, int state) const
00761 {
00762     // The KSharedDataCache is shared so add some namespacing. The following code
00763     // uses QStringBuilder (new in Qt 4.6)
00764 
00765     return (group == KIconLoader::User
00766                   ? QLatin1Literal("$kicou_")
00767                   : QLatin1Literal("$kico_"))
00768            % name
00769            % QLatin1Char('_')
00770            % QString::number(size)
00771            % QLatin1Char('_')
00772            % overlays.join("_")
00773            % ( group >= 0 ? mpEffect.fingerprint(group, state)
00774                           : *NULL_EFFECT_FINGERPRINT);
00775 }
00776 
00777 QImage KIconLoaderPrivate::createIconImage(const QString &path, int size)
00778 {
00779     // Use the extension as the format. Works for XPM and PNG, but not for SVG. The
00780     // "VGZ" is the last 3 characters of "SVGZ"
00781     QString ext = path.right(3).toUpper();
00782     QImage img;
00783 
00784     if (ext != "SVG" && ext != "VGZ")
00785     {
00786         // Not a SVG or SVGZ
00787         img = QImage(path, ext.toLatin1());
00788 
00789         if (size != 0 && !img.isNull()) {
00790             img = img.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
00791         }
00792     }
00793     else
00794     {
00795 #ifndef _WIN32_WCE
00796         QSvgRenderer renderer(path, q);
00797 
00798         if (renderer.isValid()) {
00799             img = QImage(size, size, QImage::Format_ARGB32_Premultiplied);
00800             img.fill(0);
00801             QPainter p(&img);
00802             renderer.render(&p);
00803         }
00804 #endif
00805     }
00806 
00807     return img;
00808 }
00809 
00810 void KIconLoaderPrivate::insertCachedPixmapWithPath(
00811     const QString &key,
00812     const QPixmap &data,
00813     const QString &path = QString())
00814 {
00815     // Even if the pixmap is null, we add it to the caches so that we record
00816     // the fact that whatever icon led to us getting a null pixmap doesn't
00817     // exist.
00818 
00819     QBuffer output;
00820     output.open(QIODevice::WriteOnly);
00821 
00822     QDataStream outputStream(&output);
00823     outputStream.setVersion(QDataStream::Qt_4_6);
00824 
00825     outputStream << path;
00826 
00827     // Convert the QPixmap to PNG. This is actually done by Qt's own operator.
00828     outputStream << data;
00829 
00830     output.close();
00831 
00832     // The byte array contained in the QBuffer is what we want in the cache.
00833     mIconCache->insert(key, output.buffer());
00834 
00835     // Also insert the object into our process-local cache for even more
00836     // speed.
00837     PixmapWithPath *pixmapPath = new PixmapWithPath;
00838     pixmapPath->pixmap = data;
00839     pixmapPath->path = path;
00840 
00841     mPixmapCache.insert(key, pixmapPath, data.width() * data.height() + 1);
00842 }
00843 
00844 bool KIconLoaderPrivate::findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path)
00845 {
00846     // If the pixmap is present in our local process cache, use that since we
00847     // don't need to decompress and upload it to the X server/graphics card.
00848     const PixmapWithPath *pixmapPath = mPixmapCache.object(key);
00849     if (pixmapPath) {
00850         path = pixmapPath->path;
00851         data = pixmapPath->pixmap;
00852 
00853         return true;
00854     }
00855 
00856     // Otherwise try to find it in our shared memory cache since that will
00857     // be quicker than the disk, especially for SVGs.
00858     QByteArray result;
00859 
00860     if (!mIconCache->find(key, &result) || result.isEmpty()) {
00861         return false;
00862     }
00863 
00864     QBuffer buffer;
00865     buffer.setBuffer(&result);
00866     buffer.open(QIODevice::ReadOnly);
00867 
00868     QDataStream inputStream(&buffer);
00869     inputStream.setVersion(QDataStream::Qt_4_6);
00870 
00871     QString tempPath;
00872     inputStream >> tempPath;
00873 
00874     if (inputStream.status() == QDataStream::Ok) {
00875         QPixmap tempPixmap;
00876         inputStream >> tempPixmap;
00877 
00878         if (inputStream.status() == QDataStream::Ok) {
00879             data = tempPixmap;
00880             path = tempPath;
00881 
00882             // Since we're here we didn't have a QPixmap cache entry, add one now.
00883             PixmapWithPath *newPixmapWithPath = new PixmapWithPath;
00884             newPixmapWithPath->pixmap = data;
00885             newPixmapWithPath->path = path;
00886 
00887             mPixmapCache.insert(key, newPixmapWithPath, data.width() * data.height() + 1);
00888 
00889             return true;
00890         }
00891     }
00892 
00893     return false;
00894 }
00895 
00896 K3Icon KIconLoaderPrivate::findMatchingIconWithGenericFallbacks(const QString& name, int size) const
00897 {
00898     K3Icon icon = findMatchingIcon(name, size);
00899     if (icon.isValid())
00900         return icon;
00901 
00902     const QString genericIcon = s_globalData->genericIconFor(name);
00903     if (!genericIcon.isEmpty()) {
00904         icon = findMatchingIcon(genericIcon, size);
00905     }
00906     return icon;
00907 }
00908 
00909 K3Icon KIconLoaderPrivate::findMatchingIcon(const QString& name, int size) const
00910 {
00911     const_cast<KIconLoaderPrivate*>(this)->initIconThemes();
00912 
00913     K3Icon icon;
00914 
00915 // The following code has been commented out because the Qt SVG renderer needs
00916 // to be improved. If you are going to change/remove some code from this part,
00917 // please contact me before (ereslibre@kde.org), or kde-core-devel@kde.org. (ereslibre)
00918 #ifdef KDE_QT_SVG_RENDERER_FIXED
00919     const char * ext1[4] = { ".png", ".svgz", ".svg", ".xpm" };
00920     const char * ext2[4] = { ".svgz", ".svg", ".png", ".xpm" };
00921     const char ** ext;
00922 
00923     if (size == KIconLoader::SizeSmall ||
00924         size == KIconLoader::SizeSmallMedium ||
00925         size == KIconLoader::SizeMedium ||
00926         size == KIconLoader::SizeLarge ||
00927         size == KIconLoader::SizeHuge ||
00928         size == KIconLoader::SizeEnormous)
00929     {
00930         ext = ext1; // size is standard, give preference to PNG over SVG when searching
00931     }
00932     else
00933     {
00934         ext = ext2; // size is non-standard, give preference to SVG over PNG when searching
00935     }
00936 
00937     /* If size parameter is a standard one, that means:
00938 
00939            - KIconLoader::SizeSmall
00940            - KIconLoader::SizeSmallMedium
00941            - KIconLoader::SizeMedium
00942            - KIconLoader::SizeLarge
00943            - KIconLoader::SizeHuge
00944            - KIconLoader::SizeEnormous
00945 
00946        To follow the XDG icon theme and icon naming specifications,
00947        the order in which we look for an icon is:
00948 
00949        png, svgz, svg, xpm exact match
00950        png, svgz, svg, xpm best match
00951        less specific fallback in this theme: png, svgz, svg, xpm exact match
00952                                              png, svgz, svg, xpm best match
00953        even less specific fallback in this theme: [same order]
00954        (...)
00955 
00956        next theme in inheritance tree: png, svgz, svg, xpm exact match
00957                                        png, svgz, svg, xpm best match
00958        less specific fallbacks in this next theme
00959        (...)
00960 
00961        next theme in inheritance tree: png, svgz, svg, xpm exact match
00962                                        png, svgz, svg, xpm best match
00963        less specific fallbacks in this next theme
00964        (...)
00965 
00966        and so on.
00967 
00968        If size parameter is a non-standard one, then we give more preference to
00969        SVG format since drawing SVG's gives better quality and despite being
00970        slower than resizing a PNG image, the cases where non-standard sizes are
00971        asked are very rare. For non-standard sizes what we have is:
00972 
00973        svgz, svg, png, xpm exact match
00974        svgz, svg, png, xpm best match
00975        less specific fallback in this theme: svgz, svg, png, xpm exact match
00976                                              svgz, svg, png, xpm best match
00977        even less specific fallback in this theme: [same order]
00978        (...)
00979 
00980        next theme in inheritance tree: svgz, svg, png, xpm exact match
00981                                        svgz, svg, png, xpm best match
00982        less specific fallbacks in this next theme
00983        (...)
00984 
00985        next theme in inheritance tree: svgz, svg, png, xpm exact match
00986                                        svgz, svg, png, xpm best match
00987        less specific fallbacks in this next theme
00988        (...)
00989 
00990        and so on.
00991        */
00992 #else
00993     const char * const ext[4] = { ".png", ".svgz", ".svg", ".xpm" };
00994 #endif
00995 
00996     bool genericFallback = name.endsWith(QLatin1String("-x-generic"));
00997 
00998     foreach(KIconThemeNode *themeNode, links)
00999     {
01000         QString currentName = name;
01001 
01002         while (!currentName.isEmpty())
01003         {
01004 
01005             //kDebug(264) << "Looking up" << currentName;
01006 
01007 // The following code has been commented out because the Qt SVG renderer needs
01008 // to be improved. If you are going to change/remove some code from this part,
01009 // please contact me before (ereslibre@kde.org), or kde-core-devel@kde.org. (ereslibre)
01010 #ifdef KDE_QT_SVG_RENDERER_FIXED
01011             for (int i = 0 ; i < 4 ; i++)
01012             {
01013                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchExact);
01014                 if (icon.isValid())
01015                     return icon;
01016             }
01017 
01018             for (int i = 0 ; i < 4 ; i++)
01019             {
01020                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchBest);
01021                 if (icon.isValid())
01022                     return icon;
01023             }
01024 #else
01025             for (int i = 0 ; i < 4 ; i++)
01026             {
01027                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchExact);
01028                 if (icon.isValid())
01029                     return icon;
01030 
01031                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchBest);
01032                 if (icon.isValid())
01033                     return icon;
01034             }
01035 #endif
01036             if (genericFallback)
01037                 // we already tested the base name
01038                 break;
01039 
01040             int rindex = currentName.lastIndexOf('-');
01041             if (rindex > 1) { // > 1 so that we don't split x-content or x-epoc
01042                 currentName.truncate(rindex);
01043 
01044                 if (currentName.endsWith(QLatin1String("-x")))
01045                     currentName.chop(2);
01046             } else {
01047                 // From update-mime-database.c
01048                 static const QSet<QString> mediaTypes = QSet<QString>()
01049                     << "text" << "application" << "image" << "audio"
01050                     << "inode" << "video" << "message" << "model" << "multipart"
01051                     << "x-content" << "x-epoc";
01052                 // Shared-mime-info spec says:
01053                 // "If [generic-icon] is not specified then the mimetype is used to generate the
01054                 // generic icon by using the top-level media type (e.g. "video" in "video/ogg")
01055                 // and appending "-x-generic" (i.e. "video-x-generic" in the previous example)."
01056                 if (mediaTypes.contains(currentName)) {
01057                     currentName += QLatin1String("-x-generic");
01058                     genericFallback = true;
01059                 } else {
01060                     break;
01061                 }
01062             }
01063         }
01064     }
01065     return icon;
01066 }
01067 
01068 inline QString KIconLoaderPrivate::unknownIconPath( int size ) const
01069 {
01070     static const QString &str_unknown = KGlobal::staticQString("unknown");
01071 
01072     K3Icon icon = findMatchingIcon(str_unknown, size);
01073     if (!icon.isValid())
01074     {
01075         kDebug(264) << "Warning: could not find \"Unknown\" icon for size = "
01076                      << size << endl;
01077         return QString();
01078     }
01079     return icon.path;
01080 }
01081 
01082 // Finds the absolute path to an icon.
01083 
01084 QString KIconLoader::iconPath(const QString& _name, int group_or_size,
01085                               bool canReturnNull) const
01086 {
01087     if (!d->initIconThemes()) {
01088         return QString();
01089     }
01090 
01091     if (_name.isEmpty() || !pathIsRelative(_name))
01092     {
01093         // we have either an absolute path or nothing to work with
01094         return _name;
01095     }
01096 
01097     QString name = d->removeIconExtension( _name );
01098 
01099     QString path;
01100     if (group_or_size == KIconLoader::User)
01101     {
01102         static const QString &png_ext = KGlobal::staticQString(".png");
01103         static const QString &xpm_ext = KGlobal::staticQString(".xpm");
01104         path = d->mpDirs->findResource("appicon", name + png_ext);
01105 
01106         static const QString &svgz_ext = KGlobal::staticQString(".svgz");
01107         static const QString &svg_ext = KGlobal::staticQString(".svg");
01108         if (path.isEmpty())
01109             path = d->mpDirs->findResource("appicon", name + svgz_ext);
01110         if (path.isEmpty())
01111             path = d->mpDirs->findResource("appicon", name + svg_ext);
01112         if (path.isEmpty())
01113             path = d->mpDirs->findResource("appicon", name + xpm_ext);
01114         return path;
01115     }
01116 
01117     if (group_or_size >= KIconLoader::LastGroup)
01118     {
01119         kDebug(264) << "Illegal icon group: " << group_or_size;
01120         return path;
01121     }
01122 
01123     int size;
01124     if (group_or_size >= 0)
01125         size = d->mpGroups[group_or_size].size;
01126     else
01127         size = -group_or_size;
01128 
01129     if (_name.isEmpty()) {
01130         if (canReturnNull)
01131             return QString();
01132         else
01133             return d->unknownIconPath(size);
01134     }
01135 
01136     K3Icon icon = d->findMatchingIconWithGenericFallbacks(name, size);
01137 
01138     if (!icon.isValid())
01139     {
01140         // Try "User" group too.
01141         path = iconPath(name, KIconLoader::User, true);
01142         if (!path.isEmpty() || canReturnNull)
01143             return path;
01144 
01145         return d->unknownIconPath(size);
01146     }
01147     return icon.path;
01148 }
01149 
01150 QPixmap KIconLoader::loadMimeTypeIcon( const QString& _iconName, KIconLoader::Group group, int size,
01151                                        int state, const QStringList& overlays, QString *path_store ) const
01152 {
01153     QString iconName = _iconName;
01154     const int slashindex = iconName.indexOf(QLatin1Char('/'));
01155     if (slashindex != -1) {
01156         iconName[slashindex] = QLatin1Char('-');
01157     }
01158 
01159     if ( !d->extraDesktopIconsLoaded )
01160     {
01161         const QPixmap pixmap = loadIcon( iconName, group, size, state, overlays, path_store, true );
01162         if (!pixmap.isNull() ) {
01163             return pixmap;
01164         }
01165         const_cast<KIconLoader *>(this)->addExtraDesktopThemes();
01166     }
01167     const QPixmap pixmap = loadIcon(iconName, group, size, state, overlays, path_store, true);
01168     if (pixmap.isNull()) {
01169         // Icon not found, fallback to application/octet-stream
01170         return loadIcon("application-octet-stream", group, size, state, overlays, path_store, false);
01171     }
01172     return pixmap;
01173 }
01174 
01175 QPixmap KIconLoader::loadIcon(const QString& _name, KIconLoader::Group group, int size,
01176                               int state, const QStringList& overlays,
01177                               QString *path_store, bool canReturnNull) const
01178 {
01179     QString name = _name;
01180     bool favIconOverlay = false;
01181 
01182     if (size < 0 || _name.isEmpty())
01183         return QPixmap();
01184 
01185     /*
01186      * This method works in a kind of pipeline, with the following steps:
01187      * 1. Sanity checks.
01188      * 2. Convert _name, group, size, etc. to a key name.
01189      * 3. Check if the key is already cached.
01190      * 4. If not, initialize the theme and find/load the icon.
01191      * 4a Apply overlays
01192      * 4b Re-add to cache.
01193      */
01194 
01195     // Special case for absolute path icons.
01196     if (name.startsWith(QLatin1String("favicons/")))
01197     {
01198        favIconOverlay = true;
01199        name = KStandardDirs::locateLocal("cache", name+".png");
01200     }
01201 
01202     bool absolutePath = !pathIsRelative(name);
01203     if (!absolutePath) {
01204         name = d->removeIconExtension(name);
01205     }
01206 
01207     // Don't bother looking for an icon with no name.
01208     if (name.isEmpty()) {
01209         return QPixmap();
01210     }
01211 
01212     // May modify group, size, or state. This function puts them into sane
01213     // states.
01214     d->normalizeIconMetadata(group, size, state);
01215 
01216     // See if the image is already cached.
01217     QString key = d->makeCacheKey(name, group, overlays, size, state);
01218     QPixmap pix;
01219     bool iconWasUnknown = false;
01220     K3Icon icon;
01221 
01222     if (d->findCachedPixmapWithPath(key, pix, icon.path)) {
01223         if (path_store) {
01224             *path_store = icon.path;
01225         }
01226 
01227         // We cache the pixmap for the event of trying to find an unknown icon
01228         // with canReturnNull set to false, but if we *can* return null then
01229         // we should do so when necessary.
01230         if (canReturnNull && icon.path.isEmpty()) {
01231             return QPixmap();
01232         }
01233         return pix;
01234     }
01235 
01236     // Image is not cached... go find it and apply effects.
01237     if (!d->initIconThemes()) {
01238         return QPixmap();
01239     }
01240 
01241     favIconOverlay = favIconOverlay && size > 22;
01242 
01243     // First we look for non-User icons. If we don't find one we'd search in
01244     // the User space anyways...
01245     if (group != KIconLoader::User) {
01246         // K3Icon seems to hold some needed information.
01247 
01248         if (absolutePath && !favIconOverlay)
01249         {
01250             icon.context = KIconLoader::Any;
01251             icon.type = KIconLoader::Scalable;
01252             icon.path = name;
01253         }
01254         else
01255         {
01256             icon = d->findMatchingIconWithGenericFallbacks(favIconOverlay ? QString("text-html") : name, size);
01257         }
01258     }
01259 
01260     if (icon.path.isEmpty()) {
01261         // We do have a "User" icon, or we couldn't find the non-User one.
01262         icon.path = (absolutePath) ? name :
01263                         iconPath(name, KIconLoader::User, canReturnNull);
01264     }
01265 
01266     // Still can't find it? Use "unknown" if we can't return null.
01267     // We keep going in the function so we can ensure this result gets cached.
01268     if (icon.path.isEmpty() && !canReturnNull) {
01269         icon.path = d->unknownIconPath(size);
01270         iconWasUnknown = true;
01271     }
01272 
01273     QImage img = d->createIconImage(icon.path, size);
01274 
01275     if (group >= 0)
01276     {
01277         img = d->mpEffect.apply(img, group, state);
01278     }
01279 
01280     if (favIconOverlay)
01281     {
01282         QImage favIcon(name, "PNG");
01283         if (!favIcon.isNull()) // if favIcon not there yet, don't try to blend it
01284         {
01285             QPainter p(&img);
01286 
01287             // Align the favicon overlay
01288             QRect r(favIcon.rect());
01289             r.moveBottomRight(img.rect().bottomRight());
01290             r.adjust(-1, -1, -1, -1); // Move off edge
01291 
01292             // Blend favIcon over img.
01293             p.drawImage(r, favIcon);
01294         }
01295     }
01296 
01297     pix = QPixmap::fromImage(img);
01298 
01299     // TODO: If we make a loadIcon that returns the image we can convert
01300     // drawOverlays to use the image instead of pixmaps as well so we don't
01301     // have to transfer so much to the graphics card.
01302     d->drawOverlays(this, group, state, pix, overlays);
01303 
01304     // Don't add the path to our unknown icon to the cache, only cache the
01305     // actual image.
01306     if (iconWasUnknown) {
01307         icon.path.clear();
01308     }
01309 
01310     d->insertCachedPixmapWithPath(key, pix, icon.path);
01311 
01312     if (path_store) {
01313         *path_store = icon.path;
01314     }
01315 
01316     return pix;
01317 }
01318 
01319 QMovie *KIconLoader::loadMovie(const QString& name, KIconLoader::Group group, int size, QObject *parent) const
01320 {
01321     QString file = moviePath( name, group, size );
01322     if (file.isEmpty())
01323         return 0;
01324     int dirLen = file.lastIndexOf('/');
01325     QString icon = iconPath(name, size ? -size : group, true);
01326     if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
01327         return 0;
01328     QMovie *movie = new QMovie(file, QByteArray(), parent);
01329     if (!movie->isValid())
01330     {
01331         delete movie;
01332         return 0;
01333     }
01334     return movie;
01335 }
01336 
01337 QString KIconLoader::moviePath(const QString& name, KIconLoader::Group group, int size) const
01338 {
01339     if (!d->mpGroups) return QString();
01340 
01341     d->initIconThemes();
01342 
01343     if ( (group < -1 || group >= KIconLoader::LastGroup) && group != KIconLoader::User )
01344     {
01345         kDebug(264) << "Illegal icon group: " << group;
01346         group = KIconLoader::Desktop;
01347     }
01348     if (size == 0 && group < 0)
01349     {
01350         kDebug(264) << "Neither size nor group specified!";
01351         group = KIconLoader::Desktop;
01352     }
01353 
01354     QString file = name + ".mng";
01355     if (group == KIconLoader::User)
01356     {
01357         file = d->mpDirs->findResource("appicon", file);
01358     }
01359     else
01360     {
01361         if (size == 0)
01362             size = d->mpGroups[group].size;
01363 
01364         K3Icon icon;
01365 
01366         foreach(KIconThemeNode *themeNode, d->links)
01367         {
01368             icon = themeNode->theme->iconPath(file, size, KIconLoader::MatchExact);
01369             if (icon.isValid())
01370                 break;
01371         }
01372 
01373         if ( !icon.isValid() )
01374         {
01375             foreach(KIconThemeNode *themeNode, d->links)
01376             {
01377                 icon = themeNode->theme->iconPath(file, size, KIconLoader::MatchBest);
01378                 if (icon.isValid())
01379                     break;
01380             }
01381         }
01382 
01383         file = icon.isValid() ? icon.path : QString();
01384     }
01385     return file;
01386 }
01387 
01388 
01389 QStringList KIconLoader::loadAnimated(const QString& name, KIconLoader::Group group, int size) const
01390 {
01391     QStringList lst;
01392 
01393     if (!d->mpGroups) return lst;
01394 
01395     d->initIconThemes();
01396 
01397     if ((group < -1) || (group >= KIconLoader::LastGroup))
01398     {
01399         kDebug(264) << "Illegal icon group: " << group;
01400         group = KIconLoader::Desktop;
01401     }
01402     if ((size == 0) && (group < 0))
01403     {
01404         kDebug(264) << "Neither size nor group specified!";
01405         group = KIconLoader::Desktop;
01406     }
01407 
01408     QString file = name + "/0001";
01409     if (group == KIconLoader::User)
01410     {
01411         file = d->mpDirs->findResource("appicon", file + ".png");
01412     } else
01413     {
01414         if (size == 0)
01415             size = d->mpGroups[group].size;
01416         K3Icon icon = d->findMatchingIcon(file, size);
01417         file = icon.isValid() ? icon.path : QString();
01418 
01419     }
01420     if (file.isEmpty())
01421         return lst;
01422 
01423     QString path = file.left(file.length()-8);
01424     DIR* dp = opendir( QFile::encodeName(path) );
01425     if(!dp)
01426         return lst;
01427 
01428     KDE_struct_dirent* ep;
01429     while( ( ep = KDE_readdir( dp ) ) != 0L )
01430     {
01431         QString fn(QFile::decodeName(ep->d_name));
01432         if(!(fn.left(4)).toUInt())
01433             continue;
01434 
01435         lst += path + fn;
01436     }
01437     closedir ( dp );
01438     lst.sort();
01439     return lst;
01440 }
01441 
01442 KIconTheme *KIconLoader::theme() const
01443 {
01444     d->initIconThemes();
01445     if (d->mpThemeRoot) return d->mpThemeRoot->theme;
01446     return 0L;
01447 }
01448 
01449 int KIconLoader::currentSize(KIconLoader::Group group) const
01450 {
01451     if (!d->mpGroups) return -1;
01452 
01453     if (group < 0 || group >= KIconLoader::LastGroup)
01454     {
01455         kDebug(264) << "Illegal icon group: " << group;
01456         return -1;
01457     }
01458     return d->mpGroups[group].size;
01459 }
01460 
01461 QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
01462 {
01463     const QDir dir(iconsDir);
01464     const QStringList formats = QStringList() << "*.png" << "*.xpm" << "*.svg" << "*.svgz";
01465     const QStringList lst = dir.entryList(formats, QDir::Files);
01466     QStringList result;
01467     QStringList::ConstIterator it;
01468     for (it=lst.begin(); it!=lst.end(); ++it)
01469         result += iconsDir + '/' + *it;
01470     return result;
01471 }
01472 
01473 QStringList KIconLoader::queryIconsByContext(int group_or_size,
01474                                              KIconLoader::Context context) const
01475 {
01476     d->initIconThemes();
01477 
01478     QStringList result;
01479     if (group_or_size >= KIconLoader::LastGroup)
01480     {
01481         kDebug(264) << "Illegal icon group: " << group_or_size;
01482         return result;
01483     }
01484     int size;
01485     if (group_or_size >= 0)
01486         size = d->mpGroups[group_or_size].size;
01487     else
01488         size = -group_or_size;
01489 
01490     foreach(KIconThemeNode *themeNode, d->links)
01491        themeNode->queryIconsByContext(&result, size, context);
01492 
01493     // Eliminate duplicate entries (same icon in different directories)
01494     QString name;
01495     QStringList res2, entries;
01496     QStringList::ConstIterator it;
01497     for (it=result.constBegin(); it!=result.constEnd(); ++it)
01498     {
01499         int n = (*it).lastIndexOf('/');
01500         if (n == -1)
01501             name = *it;
01502         else
01503             name = (*it).mid(n+1);
01504         name = d->removeIconExtension(name);
01505         if (!entries.contains(name))
01506         {
01507             entries += name;
01508             res2 += *it;
01509         }
01510     }
01511     return res2;
01512 
01513 }
01514 
01515 QStringList KIconLoader::queryIcons(int group_or_size, KIconLoader::Context context) const
01516 {
01517     d->initIconThemes();
01518 
01519     QStringList result;
01520     if (group_or_size >= KIconLoader::LastGroup)
01521     {
01522         kDebug(264) << "Illegal icon group: " << group_or_size;
01523         return result;
01524     }
01525     int size;
01526     if (group_or_size >= 0)
01527         size = d->mpGroups[group_or_size].size;
01528     else
01529         size = -group_or_size;
01530 
01531     foreach(KIconThemeNode *themeNode, d->links)
01532        themeNode->queryIcons(&result, size, context);
01533 
01534     // Eliminate duplicate entries (same icon in different directories)
01535     QString name;
01536     QStringList res2, entries;
01537     QStringList::ConstIterator it;
01538     for (it=result.constBegin(); it!=result.constEnd(); ++it)
01539     {
01540         int n = (*it).lastIndexOf('/');
01541         if (n == -1)
01542             name = *it;
01543         else
01544             name = (*it).mid(n+1);
01545         name = d->removeIconExtension(name);
01546         if (!entries.contains(name))
01547         {
01548             entries += name;
01549             res2 += *it;
01550         }
01551     }
01552     return res2;
01553 }
01554 
01555 // used by KIconDialog to find out which contexts to offer in a combobox
01556 bool KIconLoader::hasContext(KIconLoader::Context context) const
01557 {
01558     d->initIconThemes();
01559 
01560     foreach(KIconThemeNode *themeNode, d->links)
01561        if( themeNode->theme->hasContext( context ))
01562            return true;
01563     return false;
01564 }
01565 
01566 KIconEffect * KIconLoader::iconEffect() const
01567 {
01568     return &d->mpEffect;
01569 }
01570 
01571 bool KIconLoader::alphaBlending(KIconLoader::Group group) const
01572 {
01573     if (!d->mpGroups) return false;
01574 
01575     if (group < 0 || group >= KIconLoader::LastGroup)
01576     {
01577         kDebug(264) << "Illegal icon group: " << group;
01578         return false;
01579     }
01580     return d->mpGroups[group].alphaBlending;
01581 }
01582 
01583 // deprecated
01584 #ifndef KDE_NO_DEPRECATED
01585 QIcon KIconLoader::loadIconSet( const QString& name, KIconLoader::Group g, int s,
01586                                 bool canReturnNull )
01587 {
01588     QIcon iconset;
01589     QPixmap tmp = loadIcon(name, g, s, KIconLoader::ActiveState, QStringList(), NULL, canReturnNull);
01590     iconset.addPixmap( tmp, QIcon::Active, QIcon::On );
01591     // we don't use QIconSet's resizing anyway
01592     tmp = loadIcon(name, g, s, KIconLoader::DisabledState, QStringList(), NULL, canReturnNull);
01593     iconset.addPixmap( tmp, QIcon::Disabled, QIcon::On );
01594     tmp = loadIcon(name, g, s, KIconLoader::DefaultState, QStringList(), NULL, canReturnNull);
01595     iconset.addPixmap( tmp, QIcon::Normal, QIcon::On );
01596     return iconset;
01597 }
01598 #endif
01599 
01600 // Easy access functions
01601 
01602 QPixmap DesktopIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01603 {
01604     KIconLoader *loader = KIconLoader::global();
01605     return loader->loadIcon(name, KIconLoader::Desktop, force_size, state, overlays);
01606 }
01607 
01608 // deprecated
01609 #ifndef KDE_NO_DEPRECATED
01610 QIcon DesktopIconSet(const QString& name, int force_size)
01611 {
01612     KIconLoader *loader = KIconLoader::global();
01613     return loader->loadIconSet(name, KIconLoader::Desktop, force_size);
01614 }
01615 #endif
01616 
01617 QPixmap BarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01618 {
01619     KIconLoader *loader = KIconLoader::global();
01620     return loader->loadIcon(name, KIconLoader::Toolbar, force_size, state, overlays);
01621 }
01622 
01623 // deprecated
01624 #ifndef KDE_NO_DEPRECATED
01625 QIcon BarIconSet(const QString& name, int force_size)
01626 {
01627     KIconLoader *loader = KIconLoader::global();
01628     return loader->loadIconSet( name, KIconLoader::Toolbar, force_size );
01629 }
01630 #endif
01631 
01632 QPixmap SmallIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01633 {
01634     KIconLoader *loader = KIconLoader::global();
01635     return loader->loadIcon(name, KIconLoader::Small, force_size, state, overlays);
01636 }
01637 
01638 // deprecated
01639 #ifndef KDE_NO_DEPRECATED
01640 QIcon SmallIconSet(const QString& name, int force_size)
01641 {
01642     KIconLoader *loader = KIconLoader::global();
01643     return loader->loadIconSet( name, KIconLoader::Small, force_size );
01644 }
01645 #endif
01646 
01647 QPixmap MainBarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01648 {
01649     KIconLoader *loader = KIconLoader::global();
01650     return loader->loadIcon(name, KIconLoader::MainToolbar, force_size, state, overlays);
01651 }
01652 
01653 // deprecated
01654 #ifndef KDE_NO_DEPRECATED
01655 QIcon MainBarIconSet(const QString& name, int force_size)
01656 {
01657     KIconLoader *loader = KIconLoader::global();
01658     return loader->loadIconSet( name, KIconLoader::MainToolbar, force_size );
01659 }
01660 #endif
01661 
01662 QPixmap UserIcon(const QString& name, int state, const QStringList &overlays)
01663 {
01664     KIconLoader *loader = KIconLoader::global();
01665     return loader->loadIcon(name, KIconLoader::User, 0, state, overlays);
01666 }
01667 
01668 // deprecated
01669 #ifndef KDE_NO_DEPRECATED
01670 QIcon UserIconSet(const QString& name)
01671 {
01672     KIconLoader *loader = KIconLoader::global();
01673     return loader->loadIconSet( name, KIconLoader::User );
01674 }
01675 #endif
01676 
01677 int IconSize(KIconLoader::Group group)
01678 {
01679     KIconLoader *loader = KIconLoader::global();
01680     return loader->currentSize(group);
01681 }
01682 
01683 QPixmap KIconLoader::unknown()
01684 {
01685     QPixmap pix;
01686     if ( QPixmapCache::find("unknown", pix) ) //krazy:exclude=iconnames
01687             return pix;
01688 
01689     QString path = global()->iconPath("unknown", KIconLoader::Small, true); //krazy:exclude=iconnames
01690     if (path.isEmpty())
01691     {
01692         kDebug(264) << "Warning: Cannot find \"unknown\" icon.";
01693         pix = QPixmap(32,32);
01694     } else
01695     {
01696         pix.load(path);
01697         QPixmapCache::insert("unknown", pix); //krazy:exclude=iconnames
01698     }
01699 
01700     return pix;
01701 }
01702 
01703 /*** the global icon loader ***/
01704 K_GLOBAL_STATIC_WITH_ARGS(KIconLoader, globalIconLoader, (KGlobal::mainComponent(), 0))
01705 
01706 KIconLoader *KIconLoader::global()
01707 {
01708     return globalIconLoader;
01709 }
01710 
01711 void KIconLoader::newIconLoader()
01712 {
01713     if ( global() == this) {
01714         KIconTheme::reconfigure();
01715     }
01716 
01717     reconfigure( objectName(), d->mpDirs );
01718     emit iconLoaderSettingsChanged();
01719 }
01720 
01721 #include "kiconloader.moc"
01722 

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

Skip menu "kdelibs"
  • 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
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal