• Skip to content
  • Skip to link menu
KDE 4.3 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 
00182     K3Icon findMatchingIconWithGenericFallbacks(const QString& name, int size) const;
00183 
00188     void addAppThemes(const QString& appname);
00189 
00195     void addBaseThemes(KIconThemeNode *node, const QString &appname);
00196 
00202     void addInheritedThemes(KIconThemeNode *node, const QString &appname);
00203 
00210     void addThemeByName(const QString &themename, const QString &appname);
00211 
00216     QString unknownIconPath( int size ) const;
00217 
00222     QString removeIconExtension(const QString &name) const;
00223 
00224     KIconLoader *q;
00225 
00226     QStringList mThemesInTree;
00227     KIconGroup *mpGroups;
00228     KIconThemeNode *mpThemeRoot;
00229     KStandardDirs *mpDirs;
00230     KIconEffect mpEffect;
00231     QHash<QString, QImage*> imgDict;
00232     QImage lastImage; // last loaded image without effect applied
00233     QString lastImageKey; // key for icon without effect
00234     int lastIconType; // see KIconLoader::type
00235     int lastIconThreshold; // see KIconLoader::threshold
00236     QList<KIconThemeNode *> links;
00237     QHash<QString, KSvgRenderer*> svgRenderers;
00238     KIconCache* mIconCache;
00239     bool extraDesktopIconsLoaded :1;
00240     // lazy loading: initIconThemes() is only needed when the "links" list is needed
00241     // mIconThemeInited is used inside initIconThemes() to init only once
00242     bool mIconThemeInited :1;
00243     bool lastWasUnknown :1; // last loaded image was the unknown image
00244     QString appname;
00245 
00246     void drawOverlays(const KIconLoader *loader, KIconLoader::Group group, int state, QPixmap& pix, const QStringList& overlays);
00247 };
00248 
00249 class KIconLoaderGlobalData
00250 {
00251 public:
00252     KIconLoaderGlobalData() {
00253         const QStringList genericIconsFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "generic-icons");
00254         //kDebug() << genericIconsFiles;
00255         Q_FOREACH(const QString& file, genericIconsFiles) {
00256             parseGenericIconsFiles(file);
00257         }
00258     }
00259 
00260     QString genericIconFor(const QString& icon) const {
00261         return m_genericIcons.value(icon);
00262     }
00263 
00264 private:
00265     void parseGenericIconsFiles(const QString& fileName);
00266     QHash<QString, QString> m_genericIcons;
00267 };
00268 
00269 void KIconLoaderGlobalData::parseGenericIconsFiles(const QString& fileName)
00270 {
00271     QFile file(fileName);
00272     if (file.open(QIODevice::ReadOnly)) {
00273         QTextStream stream(&file);
00274         stream.setCodec("ISO 8859-1");
00275         while (!stream.atEnd()) {
00276             const QString line = stream.readLine();
00277             if (line.isEmpty() || line[0] == '#')
00278                 continue;
00279             const int pos = line.indexOf(':');
00280             if (pos == -1) // syntax error
00281                 continue;
00282             QString mimeIcon = line.left(pos);
00283             const int slashindex = mimeIcon.indexOf(QLatin1Char('/'));
00284             if (slashindex != -1) {
00285                 mimeIcon[slashindex] = QLatin1Char('-');
00286             }
00287 
00288             const QString genericIcon = line.mid(pos+1);
00289             m_genericIcons.insert(mimeIcon, genericIcon);
00290             //kDebug(264) << mimeIcon << "->" << genericIcon;
00291         }
00292     }
00293 }
00294 K_GLOBAL_STATIC(KIconLoaderGlobalData, s_globalData)
00295 
00296 void KIconLoaderPrivate::drawOverlays(const KIconLoader *iconLoader, KIconLoader::Group group, int state, QPixmap& pix, const QStringList& overlays)
00297 {
00298     if (overlays.isEmpty()) {
00299         return;
00300     }
00301 
00302     const int iconSize = pix.size().width();
00303     int overlaySize;
00304 
00305     if (iconSize < 32) {
00306         overlaySize = 8;
00307     } else if (iconSize <= 48) {
00308         overlaySize = 16;
00309     } else if (iconSize <= 96) {
00310         overlaySize = 22;
00311     } else if (iconSize < 256) {
00312         overlaySize = 32;
00313     } else {
00314         overlaySize = 64;
00315     }
00316 
00317     QPainter painter(&pix);
00318 
00319     int count = 0;
00320     foreach (const QString& overlay, overlays) {
00321         // Ensure empty strings fill up a emblem spot
00322         // Needed when you have several emblems to ensure they're always painted
00323         // at the same place, even if one is not here
00324         if (overlay.isEmpty()) {
00325             ++count;
00326             continue;
00327         }
00328 
00329         //TODO: should we pass in the kstate? it results in a slower
00330         //      path, and perhaps emblems should remain in the default state
00331         //      anyways?
00332         const QPixmap pixmap = iconLoader->loadIcon(overlay, group, overlaySize, state, QStringList(), 0, true);
00333 
00334         if (pixmap.isNull()) {
00335             continue;
00336         }
00337 
00338         QPoint startPoint;
00339         switch (count) {
00340         case 0:
00341             // bottom left corner
00342             startPoint = QPoint(2, iconSize - overlaySize - 2);
00343             break;
00344         case 1:
00345             // bottom right corner
00346             startPoint = QPoint(iconSize - overlaySize - 2,
00347                                 iconSize - overlaySize - 2);
00348             break;
00349         case 2:
00350             // top right corner
00351             startPoint = QPoint(iconSize - overlaySize - 2, 2);
00352             break;
00353         case 3:
00354             // top left corner
00355             startPoint = QPoint(2, 2);
00356             break;
00357         }
00358 
00359         painter.drawPixmap(startPoint, pixmap);
00360 
00361         ++count;
00362         if (count > 3) {
00363             break;
00364         }
00365     }
00366 }
00367 
00368 KIconLoader::KIconLoader(const QString& _appname, KStandardDirs *_dirs, QObject* parent)
00369     : QObject(parent)
00370 {
00371     setObjectName(_appname);
00372     d = new KIconLoaderPrivate(this);
00373 
00374     connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
00375             this, SLOT(newIconLoader()));
00376     d->init( _appname, _dirs );
00377 }
00378 
00379 KIconLoader::KIconLoader(const KComponentData &componentData, QObject* parent)
00380     : QObject(parent)
00381 {
00382     setObjectName(componentData.componentName());
00383     d = new KIconLoaderPrivate(this);
00384 
00385     connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
00386             this, SLOT(newIconLoader()));
00387     d->init(componentData.componentName(), componentData.dirs());
00388 }
00389 
00390 void KIconLoader::reconfigure( const QString& _appname, KStandardDirs *_dirs )
00391 {
00392     delete d;
00393     d = new KIconLoaderPrivate(this);
00394     d->init( _appname, _dirs );
00395 }
00396 
00397 void KIconLoaderPrivate::init( const QString& _appname, KStandardDirs *_dirs )
00398 {
00399     extraDesktopIconsLoaded=false;
00400     mIconThemeInited = false;
00401     mpThemeRoot = 0;
00402 
00403     if (_dirs)
00404         mpDirs = _dirs;
00405     else
00406         mpDirs = KGlobal::dirs();
00407 
00408     appname = _appname;
00409     if (appname.isEmpty())
00410         appname = KGlobal::mainComponent().componentName();
00411 
00412     // Initialize icon cache
00413     mIconCache = new KIconCache;
00414     if (!mIconCache->isValid()) {
00415         initIconThemes();
00416         QList<KIconTheme*> allThemes;
00417         foreach (KIconThemeNode* node, links) {
00418             allThemes.append(node->theme);
00419         }
00420         mIconCache->setThemeInfo(allThemes);
00421     }
00422 
00423     // These have to match the order in kicontheme.h
00424     static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", "Dialog", 0L };
00425     KSharedConfig::Ptr config = KGlobal::config();
00426 
00427     // loading config and default sizes
00428     mpGroups = new KIconGroup[(int) KIconLoader::LastGroup];
00429     for (KIconLoader::Group i=KIconLoader::FirstGroup; i<KIconLoader::LastGroup; i++)
00430     {
00431         if (groups[i] == 0L)
00432             break;
00433 
00434         KConfigGroup cg(config, QLatin1String(groups[i]) + "Icons");
00435         mpGroups[i].size = cg.readEntry("Size", 0);
00436         if (QPixmap::defaultDepth()>8)
00437             mpGroups[i].alphaBlending = cg.readEntry("AlphaBlending", true);
00438         else
00439             mpGroups[i].alphaBlending = false;
00440 
00441         if (!mpGroups[i].size)
00442             mpGroups[i].size = mIconCache->defaultIconSize(i);
00443     }
00444 
00445 #ifdef NO_LAZYLOAD_ICONTHEME
00446     initIconThemes();
00447 #endif
00448 }
00449 
00450 bool KIconLoaderPrivate::initIconThemes()
00451 {
00452     if (mIconThemeInited) {
00453         // If mpThemeRoot isn't 0 then initing has succeeded
00454         return (mpThemeRoot != 0);
00455     }
00456     //kDebug(264);
00457     mIconThemeInited = true;
00458 
00459     // Add the default theme and its base themes to the theme tree
00460     KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00461     if (!def->isValid())
00462     {
00463         delete def;
00464         // warn, as this is actually a small penalty hit
00465         kDebug(264) << "Couldn't find current icon theme, falling back to default.";
00466         def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00467         if (!def->isValid())
00468         {
00469             kError(264) << "Error: standard icon theme" << KIconTheme::defaultThemeName() << "not found!" << endl;
00470             delete def;
00471             return false;
00472         }
00473     }
00474     mpThemeRoot = new KIconThemeNode(def);
00475     mThemesInTree.append(def->internalName());
00476     links.append(mpThemeRoot);
00477     addBaseThemes(mpThemeRoot, appname);
00478 
00479     // Insert application specific themes at the top.
00480     mpDirs->addResourceType("appicon", "data", appname + "/pics/");
00481     // ################## KDE5: consider removing the toolbar directory
00482     mpDirs->addResourceType("appicon", "data", appname + "/toolbar/");
00483 
00484     // Add legacy icon dirs.
00485     QStringList dirs;
00486     dirs += mpDirs->resourceDirs("icon");
00487     dirs += mpDirs->resourceDirs("pixmap");
00488     dirs += mpDirs->resourceDirs("xdgdata-icon");
00489     dirs += "/usr/share/pixmaps";
00490     // These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
00491     dirs += mpDirs->resourceDirs("xdgdata-pixmap");
00492     for (QStringList::ConstIterator it = dirs.constBegin(); it != dirs.constEnd(); ++it)
00493         mpDirs->addResourceDir("appicon", *it);
00494 
00495 #ifndef NDEBUG
00496     QString dbgString = "Theme tree: ";
00497     mpThemeRoot->printTree(dbgString);
00498     kDebug(264) << dbgString;
00499 #endif
00500 
00501     return true;
00502 }
00503 
00504 KIconLoader::~KIconLoader()
00505 {
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     // ################## KDE5: 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                 const 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.constBegin(); it != list.constEnd(); ++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::findMatchingIconWithGenericFallbacks(const QString& name, int size) const
00660 {
00661     K3Icon icon = findMatchingIcon(name, size);
00662     if (icon.isValid())
00663         return icon;
00664 
00665     const QString genericIcon = s_globalData->genericIconFor(name);
00666     if (!genericIcon.isEmpty()) {
00667         icon = findMatchingIcon(genericIcon, size);
00668         if (icon.isValid())
00669             return icon;
00670     }
00671 
00672     // From update-mime-database.c
00673     static const char* const media_types[] = {
00674         "text", "application", "image", "audio",
00675         "inode", "video", "message", "model", "multipart",
00676         "x-content", "x-epoc"
00677     };
00678     // Shared-mime-info spec says:
00679     // "If [generic-icon] is not specified then the mimetype is used to generate the
00680     // generic icon by using the top-level media type (e.g. "video" in "video/ogg")
00681     // and appending "-x-generic" (i.e. "video-x-generic" in the previous example)."
00682     for (uint i = 0 ; i < sizeof(media_types)/sizeof(*media_types) ; i++) {
00683         if (name.startsWith(QLatin1String(media_types[i]))) {
00684             icon = findMatchingIcon(QString::fromLatin1(media_types[i]) + "-x-generic", size);
00685             if (icon.isValid())
00686                 return icon;
00687             break;
00688         }
00689     }
00690     // not found
00691     return icon;
00692 }
00693 
00694 K3Icon KIconLoaderPrivate::findMatchingIcon(const QString& name, int size) const
00695 {
00696     const_cast<KIconLoaderPrivate*>(this)->initIconThemes();
00697 
00698     K3Icon icon;
00699 
00700 // The following code has been commented out because the Qt SVG renderer needs
00701 // to be improved. If you are going to change/remove some code from this part,
00702 // please contact me before (ereslibre@kde.org), or kde-core-devel@kde.org. (ereslibre)
00703 #ifdef KDE_QT_SVG_RENDERER_FIXED
00704     const char * ext1[4] = { ".png", ".svgz", ".svg", ".xpm" };
00705     const char * ext2[4] = { ".svgz", ".svg", ".png", ".xpm" };
00706     const char ** ext;
00707 
00708     if (size == KIconLoader::SizeSmall ||
00709         size == KIconLoader::SizeSmallMedium ||
00710         size == KIconLoader::SizeMedium ||
00711         size == KIconLoader::SizeLarge ||
00712         size == KIconLoader::SizeHuge ||
00713         size == KIconLoader::SizeEnormous)
00714     {
00715         ext = ext1; // size is standard, give preference to PNG over SVG when searching
00716     }
00717     else
00718     {
00719         ext = ext2; // size is non-standard, give preference to SVG over PNG when searching
00720     }
00721 
00722     /* If size parameter is a standard one, that means:
00723 
00724            - KIconLoader::SizeSmall
00725            - KIconLoader::SizeSmallMedium
00726            - KIconLoader::SizeMedium
00727            - KIconLoader::SizeLarge
00728            - KIconLoader::SizeHuge
00729            - KIconLoader::SizeEnormous
00730 
00731        To follow the XDG icon theme and icon naming specifications,
00732        the order in which we look for an icon is:
00733 
00734        png, svgz, svg, xpm exact match
00735        png, svgz, svg, xpm best match
00736        less specific fallback in this theme: png, svgz, svg, xpm exact match
00737                                              png, svgz, svg, xpm best match
00738        even less specific fallback in this theme: [same order]
00739        (...)
00740 
00741        next theme in inheritance tree: png, svgz, svg, xpm exact match
00742                                        png, svgz, svg, xpm best match
00743        less specific fallbacks in this next theme
00744        (...)
00745 
00746        next theme in inheritance tree: png, svgz, svg, xpm exact match
00747                                        png, svgz, svg, xpm best match
00748        less specific fallbacks in this next theme
00749        (...)
00750 
00751        and so on.
00752 
00753        If size parameter is a non-standard one, then we give more preference to
00754        SVG format since drawing SVG's gives better quality and despite being
00755        slower than resizing a PNG image, the cases where non-standard sizes are
00756        asked are very rare. For non-standard sizes what we have is:
00757 
00758        svgz, svg, png, xpm exact match
00759        svgz, svg, png, xpm best match
00760        less specific fallback in this theme: svgz, svg, png, xpm exact match
00761                                              svgz, svg, png, xpm best match
00762        even less specific fallback in this theme: [same order]
00763        (...)
00764 
00765        next theme in inheritance tree: svgz, svg, png, xpm exact match
00766                                        svgz, svg, png, xpm best match
00767        less specific fallbacks in this next theme
00768        (...)
00769 
00770        next theme in inheritance tree: svgz, svg, png, xpm exact match
00771                                        svgz, svg, png, xpm best match
00772        less specific fallbacks in this next theme
00773        (...)
00774 
00775        and so on.
00776        */
00777 #else
00778     const char * const ext[4] = { ".png", ".svgz", ".svg", ".xpm" };
00779 #endif
00780 
00781     foreach(KIconThemeNode *themeNode, links)
00782     {
00783         QStringList nameParts = name.split('-');
00784         QString currentName = name;
00785 
00786         while (!nameParts.isEmpty())
00787         {
00788 
00789             //kDebug(264) << "Looking up" << currentName;
00790 
00791 // The following code has been commented out because the Qt SVG renderer needs
00792 // to be improved. If you are going to change/remove some code from this part,
00793 // please contact me before (ereslibre@kde.org), or kde-core-devel@kde.org. (ereslibre)
00794 #ifdef KDE_QT_SVG_RENDERER_FIXED
00795             for (int i = 0 ; i < 4 ; i++)
00796             {
00797                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchExact);
00798                 if (icon.isValid())
00799                     return icon;
00800             }
00801 
00802             for (int i = 0 ; i < 4 ; i++)
00803             {
00804                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchBest);
00805                 if (icon.isValid())
00806                     return icon;
00807             }
00808 #else
00809             for (int i = 0 ; i < 4 ; i++)
00810             {
00811                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchExact);
00812                 if (icon.isValid())
00813                     return icon;
00814 
00815                 icon = themeNode->theme->iconPath(currentName + ext[i], size, KIconLoader::MatchBest);
00816                 if (icon.isValid())
00817                     return icon;
00818             }
00819 #endif
00820 
00821             nameParts.removeLast();
00822             currentName = nameParts.join("-");
00823         }
00824     }
00825     return icon;
00826 }
00827 
00828 inline QString KIconLoaderPrivate::unknownIconPath( int size ) const
00829 {
00830     static const QString &str_unknown = KGlobal::staticQString("unknown");
00831 
00832     K3Icon icon = findMatchingIcon(str_unknown, size);
00833     if (!icon.isValid())
00834     {
00835         kDebug(264) << "Warning: could not find \"Unknown\" icon for size = "
00836                      << size << endl;
00837         return QString();
00838     }
00839     return icon.path;
00840 }
00841 
00842 // Finds the absolute path to an icon.
00843 
00844 QString KIconLoader::iconPath(const QString& _name, int group_or_size,
00845                               bool canReturnNull) const
00846 {
00847     if (!d->initIconThemes()) {
00848         return QString();
00849     }
00850 
00851     if (_name.isEmpty()
00852 #ifdef Q_OS_WIN
00853         || (_name.length() > 1 &&
00854             (_name[0].isLetter() && _name[1] == QLatin1Char(':') ||
00855              _name[0] == '/'     && _name[1] == '/' ||
00856              _name[0] == '\\'    && _name[1] == '\\')))
00857 #else
00858         || _name[0] == '/')
00859 #endif
00860     {
00861         // we have either an absolute path or nothing to work with
00862         return _name;
00863     }
00864 
00865     QString name = d->removeIconExtension( _name );
00866 
00867     QString path;
00868     if (group_or_size == KIconLoader::User)
00869     {
00870         static const QString &png_ext = KGlobal::staticQString(".png");
00871         static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00872         path = d->mpDirs->findResource("appicon", name + png_ext);
00873 
00874         static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00875         static const QString &svg_ext = KGlobal::staticQString(".svg");
00876         if (path.isEmpty())
00877             path = d->mpDirs->findResource("appicon", name + svgz_ext);
00878         if (path.isEmpty())
00879             path = d->mpDirs->findResource("appicon", name + svg_ext);
00880         if (path.isEmpty())
00881             path = d->mpDirs->findResource("appicon", name + xpm_ext);
00882         return path;
00883     }
00884 
00885     if (group_or_size >= KIconLoader::LastGroup)
00886     {
00887         kDebug(264) << "Illegal icon group: " << group_or_size;
00888         return path;
00889     }
00890 
00891     int size;
00892     if (group_or_size >= 0)
00893         size = d->mpGroups[group_or_size].size;
00894     else
00895         size = -group_or_size;
00896 
00897     if (_name.isEmpty()) {
00898         if (canReturnNull)
00899             return QString();
00900         else
00901             return d->unknownIconPath(size);
00902     }
00903 
00904     K3Icon icon = d->findMatchingIconWithGenericFallbacks(name, size);
00905 
00906     if (!icon.isValid())
00907     {
00908         // Try "User" group too.
00909         path = iconPath(name, KIconLoader::User, true);
00910         if (!path.isEmpty() || canReturnNull)
00911             return path;
00912 
00913         return d->unknownIconPath(size);
00914     }
00915     return icon.path;
00916 }
00917 
00918 QPixmap KIconLoader::loadMimeTypeIcon( const QString& iconName, KIconLoader::Group group, int size,
00919                                        int state, const QStringList& overlays, QString *path_store ) const
00920 {
00921     if ( !d->extraDesktopIconsLoaded )
00922     {
00923         const QPixmap pixmap = loadIcon( iconName, group, size, state, overlays, path_store, true );
00924         if (!pixmap.isNull() ) {
00925             return pixmap;
00926         }
00927         const_cast<KIconLoader *>(this)->addExtraDesktopThemes();
00928     }
00929     const QPixmap pixmap = loadIcon(iconName, group, size, state, overlays, path_store, true);
00930     if (pixmap.isNull()) {
00931         // Icon not found, fallback to application/octet-stream
00932         return loadIcon("application-octet-stream", group, size, state, overlays, path_store, false);
00933     }
00934     return pixmap;
00935 }
00936 
00937 QPixmap KIconLoader::loadIcon(const QString& _name, KIconLoader::Group group, int size,
00938                               int state, const QStringList& overlays,
00939                               QString *path_store, bool canReturnNull) const
00940 {
00941     QString name = _name;
00942     QString path;
00943     QPixmap pix;
00944     bool unknownIcon = false;
00945     bool absolutePath = false;
00946     bool favIconOverlay = false;
00947 
00948     if (size < 0)
00949         return pix;
00950 
00951     // Special case for absolute path icons.
00952     if (name.startsWith("favicons/"))
00953     {
00954        favIconOverlay = true;
00955        name = KStandardDirs::locateLocal("cache", name+".png");
00956     }
00957 
00958     if (!name.isEmpty()
00959 #ifdef Q_WS_WIN
00960         && !QDir::isRelativePath(name))
00961 #else
00962         && name[0] == '/')
00963 #endif
00964     {
00965         absolutePath = true;
00966     }
00967 
00968     static const QString &str_unknown = KGlobal::staticQString("unknown");
00969 
00970     // Special case for "User" icons.
00971     if (group == KIconLoader::User)
00972     {
00973         QString key;
00974         key.reserve(200);
00975         key.append("$kicou_");
00976         key.append(name).append('_').append(QString::number(size));
00977         key.append(overlays.join("_")); // krazy:exclude=doublequote_chars
00978 
00979         if (d->mIconCache->find(key, pix, path_store)) {
00980             //kDebug(264) << "KIL: " << "found the icon from KIC";
00981             if (!pix.isNull() || canReturnNull) {
00982                 return pix;
00983             } else if (_name != str_unknown) {
00984                 return loadIcon(str_unknown, group, size, state,
00985                             overlays, path_store, canReturnNull);
00986             }
00987         }
00988         if (!d->initIconThemes()) {
00989             return pix;  // null pixmap
00990         }
00991 
00992         path = (absolutePath) ? name :
00993                         iconPath(name, KIconLoader::User, canReturnNull);
00994         if (path.isEmpty())
00995         {
00996             d->mIconCache->insert(key, pix); //insert the null icon so we know it's null
00997             if (!canReturnNull) {
00998 #ifndef NDEBUG
00999                 kWarning(264) << "No such icon" << _name;
01000 #endif
01001                 unknownIcon = true;
01002             } else {
01003                 return pix; // null pixmap
01004             }
01005             // We don't know the desired size: use small
01006             path = iconPath(str_unknown, KIconLoader::Small, true);
01007             if (path.isEmpty())
01008             {
01009                 kWarning(264) << "Warning: Cannot find \"unknown\" icon.";
01010                 return pix;
01011             }
01012         }
01013 
01014         if (path_store != 0L)
01015             *path_store = path;
01016         //if (inCache)
01017         //    return pix;
01018         QImage img(path);
01019         if (size != 0)
01020             img=img.scaled(size,size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
01021 
01022         pix = QPixmap::fromImage(img);
01023         d->drawOverlays(this, KIconLoader::Desktop, state, pix, overlays);
01024         if (!unknownIcon)
01025             d->mIconCache->insert(key, pix, path);
01026         return pix;
01027     }
01028 
01029     // Regular case: Check parameters
01030 
01031     if ((group < -1) || (group >= KIconLoader::LastGroup))
01032     {
01033         kDebug(264) << "Illegal icon group: " << group;
01034         group = KIconLoader::Desktop;
01035     }
01036 
01037     if ((state < 0) || (state >= KIconLoader::LastState))
01038     {
01039         kDebug(264) << "Illegal icon state: " << state;
01040         state = KIconLoader::DefaultState;
01041     }
01042 
01043     if (size == 0 && group < 0)
01044     {
01045         kDebug(264) << "Neither size nor group specified!";
01046         group = KIconLoader::Desktop;
01047     }
01048 
01049     if (!absolutePath)
01050     {
01051         if (!canReturnNull && name.isEmpty())
01052             name = str_unknown;
01053         else
01054             name = d->removeIconExtension(name);
01055     }
01056 
01057     // If size == 0, use default size for the specified group.
01058     if (size == 0)
01059     {
01060         size = d->mpGroups[group].size;
01061     }
01062     favIconOverlay = favIconOverlay && size > 22;
01063 
01064     // Generate a unique cache key for the icon.
01065 
01066     QString key;
01067     key.reserve(100);
01068     key.append("$kico_");
01069     key.append(name).append('_').append(QString::number(size));
01070 
01071     QString overlayKey = overlays.join("_"); // krazy:exclude=doublequote_chars
01072     QString noEffectKey = key + overlayKey;
01073 
01074     if (group >= 0)
01075     {
01076         key.append(d->mpEffect.fingerprint(group, state));
01077     } else {
01078         key.append(QLatin1String("noeffect"));
01079     }
01080     key.append(overlayKey);
01081 
01082     // Is the icon in the cache?
01083     if (d->mIconCache->find(key, pix, path_store)) {
01084         //kDebug() << "KIL: " << "found icon from KIC";
01085         if (!pix.isNull() || canReturnNull) {
01086             return pix;
01087         } else if (_name != str_unknown) {
01088             return loadIcon(str_unknown, group, size, state,
01089                             overlays, path_store, canReturnNull);
01090         }
01091     }
01092     if (!d->initIconThemes()) {
01093         return pix; // null pixmap
01094     }
01095 
01096     QImage *img = 0;
01097     int iconType;
01098     int iconThreshold;
01099 
01100     if ( ( path_store != 0 ) ||
01101          ( noEffectKey != d->lastImageKey ) ||
01102          ( d->lastWasUnknown && canReturnNull ) )
01103     {
01104         // Not in cache and not the same as the last requested icon -> load it.
01105         K3Icon icon;
01106         if (absolutePath && !favIconOverlay)
01107         {
01108             icon.context=KIconLoader::Any;
01109             icon.type=KIconLoader::Scalable;
01110             icon.path=name;
01111         }
01112         else
01113         {
01114             if (!name.isEmpty())
01115                 icon = d->findMatchingIconWithGenericFallbacks(favIconOverlay ? QString("text-html") : name, size);
01116 
01117             if (!icon.isValid())
01118             {
01119                 // Try "User" icon too. Some apps expect this.
01120                 if (!name.isEmpty()) {
01121                     pix = loadIcon(name, KIconLoader::User, size, state, overlays, path_store, true);
01122                 }
01123                 d->mIconCache->insert(key, pix, path);
01124                 if (!pix.isNull() || canReturnNull) {
01125                     return pix;
01126                 }
01127 #ifndef NDEBUG
01128                 kWarning(264) << "No such icon" << _name;
01129 #endif
01130                 unknownIcon = true;
01131                 icon = d->findMatchingIcon(str_unknown, size);
01132                 if (!icon.isValid())
01133                 {
01134                     kDebug(264)
01135                         << "Warning: could not find \"Unknown\" icon for size = "
01136                         << size << endl;
01137                     return pix;
01138                 }
01139             }
01140         }
01141 
01142         if (path_store != 0)
01143             *path_store = icon.path;
01144 
01145         // Use the extension as the format. Works for XPM and PNG, but not for SVG
01146         QString ext = icon.path.right(3).toUpper();
01147         if(ext != "SVG" && ext != "VGZ")
01148         {
01149             img = new QImage(icon.path, ext.toLatin1());
01150             if (img->isNull()) {
01151                 if (!unknownIcon)
01152                     d->mIconCache->insert(key, pix, path);
01153                 delete img;
01154                 return pix;
01155             }
01156         }
01157         else
01158         {
01159             KSvgRenderer *renderer = d->svgRenderers[icon.path];
01160             if (!renderer) {
01161                 renderer = new KSvgRenderer(icon.path);
01162                 if (renderer->isValid()) {
01163                     if (d->svgRenderers.count() >= MAX_SVG_RENDERERS) {
01164                         QList<QString> keys = d->svgRenderers.keys();
01165                         for (int i = 0; i < MAX_SVG_RENDERERS/2; ++i) {
01166                             KSvgRenderer *oldRenderer = d->svgRenderers.take(keys[i]);
01167                             delete oldRenderer;
01168                         }
01169                     }
01170                     d->svgRenderers.insert(icon.path, renderer);
01171                 }
01172             }
01173             // Special stuff for SVG icons
01174 
01175             if (renderer && renderer->isValid()) {
01176                 img = new QImage(size, size, QImage::Format_ARGB32_Premultiplied);
01177                 img->fill(0);
01178                 QPainter p(img);
01179                 renderer->render(&p);
01180             } else {
01181                 delete renderer;
01182                 if (!unknownIcon)
01183                     d->mIconCache->insert(key, pix, path);
01184                 return pix;
01185             }
01186         }
01187 
01188         iconType = icon.type;
01189         iconThreshold = icon.threshold;
01190         path = icon.path;
01191 
01192         d->lastImage = img->copy();
01193         d->lastImageKey = noEffectKey;
01194         d->lastIconType = iconType;
01195         d->lastIconThreshold = iconThreshold;
01196         d->lastWasUnknown = unknownIcon;
01197     }
01198     else
01199     {
01200         img = new QImage( d->lastImage.copy() );
01201         iconType = d->lastIconType;
01202         iconThreshold = d->lastIconThreshold;
01203         unknownIcon = d->lastWasUnknown;
01204     }
01205 
01206     // Scale the icon and apply effects if necessary
01207 #ifndef KDE_QT_SVG_RENDERER_FIXED
01208     // The following code needs to be removed after the SVG rendering has been
01209     // fixed (please take a look at the comment above). Please do not remove the
01210     // #if condition as it marks what needs to be removed (ereslibre)
01211     if (iconType == KIconLoader::Scalable && size != img->width())
01212     {
01213         *img = img->scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
01214     }
01215 #endif
01216     if (iconType == KIconLoader::Threshold && size != img->width())
01217     {
01218         const int sizeDiff = size - img->width();
01219         if (sizeDiff < 0 || sizeDiff > iconThreshold)
01220             *img = img->scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
01221     }
01222     if (group >= 0)
01223     {
01224         *img = d->mpEffect.apply(*img, group, state);
01225     }
01226 
01227     if (favIconOverlay)
01228     {
01229         QImage favIcon(name, "PNG");
01230         if (!favIcon.isNull()) // if favIcon not there yet, don't try to blend it
01231         {
01232             // Blend favIcon over img.
01233             // FIXME: This code should be updated to use modern QPainter
01234             // features.
01235             int x = img->width() - favIcon.width() - 1,
01236                 y = img->height() - favIcon.height() - 1;
01237             favIcon = favIcon.convertToFormat(QImage::Format_ARGB32);
01238             *img = img->convertToFormat(QImage::Format_ARGB32);
01239             for( int line = 0;
01240                  line < favIcon.height();
01241                  ++line )
01242             {
01243                 QRgb* fpos = reinterpret_cast< QRgb* >( favIcon.scanLine( line ));
01244                 QRgb* ipos = reinterpret_cast< QRgb* >( img->scanLine( line + y )) + x;
01245                 for( int i = 0;
01246                      i < favIcon.width();
01247                      ++i, ++fpos, ++ipos )
01248                     *ipos = qRgba( ( qRed( *ipos ) * ( 255 - qAlpha( *fpos )) + qRed( *fpos ) * qAlpha( *fpos )) / 255,
01249                                    ( qGreen( *ipos ) * ( 255 - qAlpha( *fpos )) + qGreen( *fpos ) * qAlpha( *fpos )) / 255,
01250                                    ( qBlue( *ipos ) * ( 255 - qAlpha( *fpos )) + qBlue( *fpos ) * qAlpha( *fpos )) / 255,
01251                                    ( qAlpha( *ipos ) * ( 255 - qAlpha( *fpos )) + qAlpha( *fpos ) * qAlpha( *fpos )) / 255 );
01252             }
01253         }
01254     }
01255 
01256     pix = QPixmap::fromImage(*img);
01257 
01258     d->drawOverlays(this, group, state, pix, overlays);
01259 
01260     delete img;
01261 
01262     if (!unknownIcon)
01263     {
01264         d->mIconCache->insert(key, pix, path);
01265     }
01266     return pix;
01267 }
01268 
01269 QMovie *KIconLoader::loadMovie(const QString& name, KIconLoader::Group group, int size, QObject *parent) const
01270 {
01271     QString file = moviePath( name, group, size );
01272     if (file.isEmpty())
01273         return 0;
01274     int dirLen = file.lastIndexOf('/');
01275     QString icon = iconPath(name, size ? -size : group, true);
01276     if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
01277         return 0;
01278     QMovie *movie = new QMovie(file, QByteArray(), parent);
01279     if (!movie->isValid())
01280     {
01281         delete movie;
01282         return 0;
01283     }
01284     return movie;
01285 }
01286 
01287 QString KIconLoader::moviePath(const QString& name, KIconLoader::Group group, int size) const
01288 {
01289     if (!d->mpGroups) return QString();
01290 
01291     d->initIconThemes();
01292 
01293     if ( (group < -1 || group >= KIconLoader::LastGroup) && group != KIconLoader::User )
01294     {
01295         kDebug(264) << "Illegal icon group: " << group;
01296         group = KIconLoader::Desktop;
01297     }
01298     if (size == 0 && group < 0)
01299     {
01300         kDebug(264) << "Neither size nor group specified!";
01301         group = KIconLoader::Desktop;
01302     }
01303 
01304     QString file = name + ".mng";
01305     if (group == KIconLoader::User)
01306     {
01307         file = d->mpDirs->findResource("appicon", file);
01308     }
01309     else
01310     {
01311         if (size == 0)
01312             size = d->mpGroups[group].size;
01313 
01314         K3Icon icon;
01315 
01316         foreach(KIconThemeNode *themeNode, d->links)
01317         {
01318             icon = themeNode->theme->iconPath(file, size, KIconLoader::MatchExact);
01319             if (icon.isValid())
01320                 break;
01321         }
01322 
01323         if ( !icon.isValid() )
01324         {
01325             foreach(KIconThemeNode *themeNode, d->links)
01326             {
01327                 icon = themeNode->theme->iconPath(file, size, KIconLoader::MatchBest);
01328                 if (icon.isValid())
01329                     break;
01330             }
01331         }
01332 
01333         file = icon.isValid() ? icon.path : QString();
01334     }
01335     return file;
01336 }
01337 
01338 
01339 QStringList KIconLoader::loadAnimated(const QString& name, KIconLoader::Group group, int size) const
01340 {
01341     QStringList lst;
01342 
01343     if (!d->mpGroups) return lst;
01344 
01345     d->initIconThemes();
01346 
01347     if ((group < -1) || (group >= KIconLoader::LastGroup))
01348     {
01349         kDebug(264) << "Illegal icon group: " << group;
01350         group = KIconLoader::Desktop;
01351     }
01352     if ((size == 0) && (group < 0))
01353     {
01354         kDebug(264) << "Neither size nor group specified!";
01355         group = KIconLoader::Desktop;
01356     }
01357 
01358     QString file = name + "/0001";
01359     if (group == KIconLoader::User)
01360     {
01361         file = d->mpDirs->findResource("appicon", file + ".png");
01362     } else
01363     {
01364         if (size == 0)
01365             size = d->mpGroups[group].size;
01366         K3Icon icon = d->findMatchingIcon(file, size);
01367         file = icon.isValid() ? icon.path : QString();
01368 
01369     }
01370     if (file.isEmpty())
01371         return lst;
01372 
01373     QString path = file.left(file.length()-8);
01374     DIR* dp = opendir( QFile::encodeName(path) );
01375     if(!dp)
01376         return lst;
01377 
01378     KDE_struct_dirent* ep;
01379     while( ( ep = KDE_readdir( dp ) ) != 0L )
01380     {
01381         QString fn(QFile::decodeName(ep->d_name));
01382         if(!(fn.left(4)).toUInt())
01383             continue;
01384 
01385         lst += path + fn;
01386     }
01387     closedir ( dp );
01388     lst.sort();
01389     return lst;
01390 }
01391 
01392 KIconTheme *KIconLoader::theme() const
01393 {
01394     d->initIconThemes();
01395     if (d->mpThemeRoot) return d->mpThemeRoot->theme;
01396     return 0L;
01397 }
01398 
01399 int KIconLoader::currentSize(KIconLoader::Group group) const
01400 {
01401     if (!d->mpGroups) return -1;
01402 
01403     if (group < 0 || group >= KIconLoader::LastGroup)
01404     {
01405         kDebug(264) << "Illegal icon group: " << group;
01406         return -1;
01407     }
01408     return d->mpGroups[group].size;
01409 }
01410 
01411 QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
01412 {
01413     const QDir dir(iconsDir);
01414     const QStringList formats = QStringList() << "*.png" << "*.xpm" << "*.svg" << "*.svgz";
01415     const QStringList lst = dir.entryList(formats, QDir::Files);
01416     QStringList result;
01417     QStringList::ConstIterator it;
01418     for (it=lst.begin(); it!=lst.end(); ++it)
01419         result += iconsDir + '/' + *it;
01420     return result;
01421 }
01422 
01423 QStringList KIconLoader::queryIconsByContext(int group_or_size,
01424                                              KIconLoader::Context context) const
01425 {
01426     d->initIconThemes();
01427 
01428     QStringList result;
01429     if (group_or_size >= KIconLoader::LastGroup)
01430     {
01431         kDebug(264) << "Illegal icon group: " << group_or_size;
01432         return result;
01433     }
01434     int size;
01435     if (group_or_size >= 0)
01436         size = d->mpGroups[group_or_size].size;
01437     else
01438         size = -group_or_size;
01439 
01440     foreach(KIconThemeNode *themeNode, d->links)
01441        themeNode->queryIconsByContext(&result, size, context);
01442 
01443     // Eliminate duplicate entries (same icon in different directories)
01444     QString name;
01445     QStringList res2, entries;
01446     QStringList::ConstIterator it;
01447     for (it=result.constBegin(); it!=result.constEnd(); ++it)
01448     {
01449         int n = (*it).lastIndexOf('/');
01450         if (n == -1)
01451             name = *it;
01452         else
01453             name = (*it).mid(n+1);
01454         name = d->removeIconExtension(name);
01455         if (!entries.contains(name))
01456         {
01457             entries += name;
01458             res2 += *it;
01459         }
01460     }
01461     return res2;
01462 
01463 }
01464 
01465 QStringList KIconLoader::queryIcons(int group_or_size, KIconLoader::Context context) const
01466 {
01467     d->initIconThemes();
01468 
01469     QStringList result;
01470     if (group_or_size >= KIconLoader::LastGroup)
01471     {
01472         kDebug(264) << "Illegal icon group: " << group_or_size;
01473         return result;
01474     }
01475     int size;
01476     if (group_or_size >= 0)
01477         size = d->mpGroups[group_or_size].size;
01478     else
01479         size = -group_or_size;
01480 
01481     foreach(KIconThemeNode *themeNode, d->links)
01482        themeNode->queryIcons(&result, size, context);
01483 
01484     // Eliminate duplicate entries (same icon in different directories)
01485     QString name;
01486     QStringList res2, entries;
01487     QStringList::ConstIterator it;
01488     for (it=result.constBegin(); it!=result.constEnd(); ++it)
01489     {
01490         int n = (*it).lastIndexOf('/');
01491         if (n == -1)
01492             name = *it;
01493         else
01494             name = (*it).mid(n+1);
01495         name = d->removeIconExtension(name);
01496         if (!entries.contains(name))
01497         {
01498             entries += name;
01499             res2 += *it;
01500         }
01501     }
01502     return res2;
01503 }
01504 
01505 // used by KIconDialog to find out which contexts to offer in a combobox
01506 bool KIconLoader::hasContext(KIconLoader::Context context) const
01507 {
01508     d->initIconThemes();
01509 
01510     foreach(KIconThemeNode *themeNode, d->links)
01511        if( themeNode->theme->hasContext( context ))
01512            return true;
01513     return false;
01514 }
01515 
01516 KIconEffect * KIconLoader::iconEffect() const
01517 {
01518     return &d->mpEffect;
01519 }
01520 
01521 bool KIconLoader::alphaBlending(KIconLoader::Group group) const
01522 {
01523     if (!d->mpGroups) return false;
01524 
01525     if (group < 0 || group >= KIconLoader::LastGroup)
01526     {
01527         kDebug(264) << "Illegal icon group: " << group;
01528         return false;
01529     }
01530     return d->mpGroups[group].alphaBlending;
01531 }
01532 
01533 // deprecated
01534 QIcon KIconLoader::loadIconSet( const QString& name, KIconLoader::Group g, int s,
01535                                 bool canReturnNull )
01536 {
01537     QIcon iconset;
01538     QPixmap tmp = loadIcon(name, g, s, KIconLoader::ActiveState, QStringList(), NULL, canReturnNull);
01539     iconset.addPixmap( tmp, QIcon::Active, QIcon::On );
01540     // we don't use QIconSet's resizing anyway
01541     tmp = loadIcon(name, g, s, KIconLoader::DisabledState, QStringList(), NULL, canReturnNull);
01542     iconset.addPixmap( tmp, QIcon::Disabled, QIcon::On );
01543     tmp = loadIcon(name, g, s, KIconLoader::DefaultState, QStringList(), NULL, canReturnNull);
01544     iconset.addPixmap( tmp, QIcon::Normal, QIcon::On );
01545     return iconset;
01546 }
01547 
01548 // Easy access functions
01549 
01550 QPixmap DesktopIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01551 {
01552     KIconLoader *loader = KIconLoader::global();
01553     return loader->loadIcon(name, KIconLoader::Desktop, force_size, state, overlays);
01554 }
01555 
01556 // deprecated
01557 QIcon DesktopIconSet(const QString& name, int force_size)
01558 {
01559     KIconLoader *loader = KIconLoader::global();
01560     return loader->loadIconSet(name, KIconLoader::Desktop, force_size);
01561 }
01562 
01563 QPixmap BarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01564 {
01565     KIconLoader *loader = KIconLoader::global();
01566     return loader->loadIcon(name, KIconLoader::Toolbar, force_size, state, overlays);
01567 }
01568 
01569 // deprecated
01570 QIcon BarIconSet(const QString& name, int force_size)
01571 {
01572     KIconLoader *loader = KIconLoader::global();
01573     return loader->loadIconSet( name, KIconLoader::Toolbar, force_size );
01574 }
01575 
01576 QPixmap SmallIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01577 {
01578     KIconLoader *loader = KIconLoader::global();
01579     return loader->loadIcon(name, KIconLoader::Small, force_size, state, overlays);
01580 }
01581 
01582 // deprecated
01583 QIcon SmallIconSet(const QString& name, int force_size)
01584 {
01585     KIconLoader *loader = KIconLoader::global();
01586     return loader->loadIconSet( name, KIconLoader::Small, force_size );
01587 }
01588 
01589 QPixmap MainBarIcon(const QString& name, int force_size, int state, const QStringList &overlays)
01590 {
01591     KIconLoader *loader = KIconLoader::global();
01592     return loader->loadIcon(name, KIconLoader::MainToolbar, force_size, state, overlays);
01593 }
01594 
01595 // deprecated
01596 QIcon MainBarIconSet(const QString& name, int force_size)
01597 {
01598     KIconLoader *loader = KIconLoader::global();
01599     return loader->loadIconSet( name, KIconLoader::MainToolbar, force_size );
01600 }
01601 
01602 QPixmap UserIcon(const QString& name, int state, const QStringList &overlays)
01603 {
01604     KIconLoader *loader = KIconLoader::global();
01605     return loader->loadIcon(name, KIconLoader::User, 0, state, overlays);
01606 }
01607 
01608 // deprecated
01609 QIcon UserIconSet(const QString& name)
01610 {
01611     KIconLoader *loader = KIconLoader::global();
01612     return loader->loadIconSet( name, KIconLoader::User );
01613 }
01614 
01615 int IconSize(KIconLoader::Group group)
01616 {
01617     KIconLoader *loader = KIconLoader::global();
01618     return loader->currentSize(group);
01619 }
01620 
01621 QPixmap KIconLoader::unknown()
01622 {
01623     QPixmap pix;
01624     if ( QPixmapCache::find("unknown", pix) ) //krazy:exclude=iconnames
01625             return pix;
01626 
01627     QString path = global()->iconPath("unknown", KIconLoader::Small, true); //krazy:exclude=iconnames
01628     if (path.isEmpty())
01629     {
01630         kDebug(264) << "Warning: Cannot find \"unknown\" icon.";
01631         pix = QPixmap(32,32);
01632     } else
01633     {
01634         pix.load(path);
01635         QPixmapCache::insert("unknown", pix); //krazy:exclude=iconnames
01636     }
01637 
01638     return pix;
01639 }
01640 
01641 /*** the global icon loader ***/
01642 K_GLOBAL_STATIC_WITH_ARGS(KIconLoader, globalIconLoader, (KGlobal::mainComponent(), 0))
01643 
01644 KIconLoader *KIconLoader::global()
01645 {
01646     return globalIconLoader;
01647 }
01648 
01649 void KIconLoader::newIconLoader()
01650 {
01651     if ( global() == this) {
01652         KIconTheme::reconfigure();
01653     }
01654 
01655     reconfigure( objectName(), d->mpDirs );
01656     emit iconLoaderSettingsChanged();
01657 }
01658 
01659 #include "kiconloader.moc"
01660 

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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