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

KDEUI

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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.3
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