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

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
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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