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

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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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