kdecore Library API Documentation

kiconloader.cpp

00001 /* vi: ts=8 sts=4 sw=4
00002  *
00003  * $Id: kiconloader.cpp,v 1.220 2004/07/31 10:17:48 binner Exp $
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 is free software; it comes under the GNU Library General
00010  * Public License, version 2. See the file "COPYING.LIB" for the
00011  * exact licensing terms.
00012  *
00013  * kiconloader.cpp: An icon loader for KDE with theming functionality.
00014  */
00015 
00016 #include <qstring.h>
00017 #include <qstringlist.h>
00018 #include <qptrlist.h>
00019 #include <qintdict.h>
00020 #include <qpixmap.h>
00021 #include <qpixmapcache.h>
00022 #include <qimage.h>
00023 #include <qfileinfo.h>
00024 #include <qdir.h>
00025 #include <qiconset.h>
00026 #include <qmovie.h>
00027 #include <qbitmap.h>
00028 
00029 #include <kdebug.h>
00030 #include <kstandarddirs.h>
00031 #include <kglobal.h>
00032 #include <kconfig.h>
00033 #include <ksimpleconfig.h>
00034 #include <kinstance.h>
00035 
00036 #include <kicontheme.h>
00037 #include <kiconloader.h>
00038 #include <kiconeffect.h>
00039 
00040 #include <sys/types.h>
00041 #include <stdlib.h> //for abs
00042 #include <unistd.h>     //for readlink
00043 #include <dirent.h>
00044 #include <config.h>
00045 #include <assert.h>
00046 
00047 #ifdef HAVE_LIBART
00048 #include "svgicons/ksvgiconengine.h"
00049 #include "svgicons/ksvgiconpainter.h"
00050 #endif
00051 
00052 /*** KIconThemeNode: A node in the icon theme dependancy tree. ***/
00053 
00054 class KIconThemeNode
00055 {
00056 public:
00057 
00058     KIconThemeNode(KIconTheme *_theme);
00059     ~KIconThemeNode();
00060 
00061     void queryIcons(QStringList *lst, int size, KIcon::Context context) const;
00062     void queryIconsByContext(QStringList *lst, int size, KIcon::Context context) const;
00063     KIcon findIcon(const QString& name, int size, KIcon::MatchType match) const;
00064     void printTree(QString& dbgString) const;
00065 
00066     KIconTheme *theme;
00067 };
00068 
00069 KIconThemeNode::KIconThemeNode(KIconTheme *_theme)
00070 {
00071     theme = _theme;
00072 }
00073 
00074 KIconThemeNode::~KIconThemeNode()
00075 {
00076     delete theme;
00077 }
00078 
00079 void KIconThemeNode::printTree(QString& dbgString) const
00080 {
00081     /* This method doesn't have much sense anymore, so maybe it should
00082        be removed in the (near?) future */
00083     dbgString += "(";
00084     dbgString += theme->name();
00085     dbgString += ")";
00086 }
00087 
00088 void KIconThemeNode::queryIcons(QStringList *result,
00089                 int size, KIcon::Context context) const
00090 {
00091     // add the icons of this theme to it
00092     *result += theme->queryIcons(size, context);
00093 }
00094 
00095 void KIconThemeNode::queryIconsByContext(QStringList *result,
00096                 int size, KIcon::Context context) const
00097 {
00098     // add the icons of this theme to it
00099     *result += theme->queryIconsByContext(size, context);
00100 }
00101 
00102 KIcon KIconThemeNode::findIcon(const QString& name, int size,
00103                    KIcon::MatchType match) const
00104 {
00105     return theme->iconPath(name, size, match);
00106 }
00107 
00108 
00109 /*** KIconGroup: Icon type description. ***/
00110 
00111 struct KIconGroup
00112 {
00113     int size;
00114     bool dblPixels;
00115     bool alphaBlending;
00116 };
00117 
00118 
00119 /*** d pointer for KIconLoader. ***/
00120 
00121 struct KIconLoaderPrivate
00122 {
00123     QStringList mThemeList;
00124     QStringList mThemesInTree;
00125     KIconGroup *mpGroups;
00126     KIconThemeNode *mpThemeRoot;
00127     KStandardDirs *mpDirs;
00128     KIconEffect mpEffect;
00129     QDict<QImage> imgDict;
00130     QImage lastImage; // last loaded image without effect applied
00131     QString lastImageKey; // key for icon without effect
00132     int lastIconType; // see KIcon::type
00133     int lastIconThreshold; // see KIcon::threshold
00134     QPtrList<KIconThemeNode> links;
00135     bool extraDesktopIconsLoaded :1;
00136     bool delayedLoading :1;
00137 };
00138 
00139 /*** KIconLoader: the icon loader ***/
00140 
00141 KIconLoader::KIconLoader(const QString& _appname, KStandardDirs *_dirs)
00142 {
00143     init( _appname, _dirs );
00144 }
00145 
00146 void KIconLoader::reconfigure( const QString& _appname, KStandardDirs *_dirs )
00147 {
00148     delete d;
00149     init( _appname, _dirs );
00150 }
00151 
00152 void KIconLoader::init( const QString& _appname, KStandardDirs *_dirs )
00153 {
00154     d = new KIconLoaderPrivate;
00155     d->imgDict.setAutoDelete( true );
00156     d->links.setAutoDelete(true);
00157     d->extraDesktopIconsLoaded=false;
00158     d->delayedLoading=false;
00159 
00160     if (_dirs)
00161     d->mpDirs = _dirs;
00162     else
00163     d->mpDirs = KGlobal::dirs();
00164 
00165     // If this is unequal to 0, the iconloader is initialized
00166     // successfully.
00167     d->mpThemeRoot = 0L;
00168 
00169     // Check installed themes.
00170     d->mThemeList = KIconTheme::list();
00171     if (!d->mThemeList.contains(KIconTheme::defaultThemeName()))
00172     {
00173         kdError(264) << "Error: standard icon theme"
00174                      << " \"" << KIconTheme::defaultThemeName() << "\" "
00175                      << " not found!" << endl;
00176         d->mpGroups=0L;
00177 
00178         return;
00179     }
00180 
00181     QString appname = _appname;
00182     if (appname.isEmpty())
00183     appname = KGlobal::instance()->instanceName();
00184 
00185     // Add the default theme and its base themes to the theme tree
00186     KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00187     if (!def->isValid())
00188     {
00189     delete def;
00190     def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00191     }
00192     d->mpThemeRoot = new KIconThemeNode(def);
00193     d->links.append(d->mpThemeRoot);
00194     d->mThemesInTree += KIconTheme::current();
00195     addBaseThemes(d->mpThemeRoot, appname);
00196 
00197     // These have to match the order in kicontheme.h
00198     static const char * const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", 0L };
00199     KConfig *config = KGlobal::config();
00200     KConfigGroupSaver cs(config, "dummy");
00201 
00202     // loading config and default sizes
00203     d->mpGroups = new KIconGroup[(int) KIcon::LastGroup];
00204     for (KIcon::Group i=KIcon::FirstGroup; i<KIcon::LastGroup; i++)
00205     {
00206     if (groups[i] == 0L)
00207         break;
00208     config->setGroup(QString::fromLatin1(groups[i]) + "Icons");
00209     d->mpGroups[i].size = config->readNumEntry("Size", 0);
00210     d->mpGroups[i].dblPixels = config->readBoolEntry("DoublePixels", false);
00211     if (QPixmap::defaultDepth()>8)
00212         d->mpGroups[i].alphaBlending = config->readBoolEntry("AlphaBlending", true);
00213     else
00214         d->mpGroups[i].alphaBlending = false;
00215 
00216     if (!d->mpGroups[i].size)
00217         d->mpGroups[i].size = d->mpThemeRoot->theme->defaultSize(i);
00218     }
00219 
00220     // Insert application specific themes at the top.
00221     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00222         appname + "/pics/");
00223     // ################## KDE4: consider removing the toolbar directory
00224     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00225         appname + "/toolbar/");
00226 
00227     // Add legacy icon dirs.
00228     QStringList dirs;
00229     dirs += d->mpDirs->resourceDirs("icon");
00230     dirs += d->mpDirs->resourceDirs("pixmap");
00231     for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it)
00232     d->mpDirs->addResourceDir("appicon", *it);
00233 
00234 #ifndef NDEBUG
00235     QString dbgString = "Theme tree: ";
00236     d->mpThemeRoot->printTree(dbgString);
00237     kdDebug(264) << dbgString << endl;
00238 #endif
00239 }
00240 
00241 KIconLoader::~KIconLoader()
00242 {
00243     /* antlarr: There's no need to delete d->mpThemeRoot as it's already
00244        deleted when the elements of d->links are deleted */
00245     d->mpThemeRoot=0;
00246     delete[] d->mpGroups;
00247     delete d;
00248 }
00249 
00250 void KIconLoader::enableDelayedIconSetLoading( bool enable )
00251 {
00252     d->delayedLoading = enable;
00253 }
00254 
00255 bool KIconLoader::isDelayedIconSetLoadingEnabled() const
00256 {
00257     return d->delayedLoading;
00258 }
00259 
00260 void KIconLoader::addAppDir(const QString& appname)
00261 {
00262     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00263         appname + "/pics/");
00264     // ################## KDE4: consider removing the toolbar directory
00265     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00266         appname + "/toolbar/");
00267     addAppThemes(appname);
00268 }
00269 
00270 void KIconLoader::addAppThemes(const QString& appname)
00271 {
00272     if ( KIconTheme::current() != KIconTheme::defaultThemeName() )
00273     {
00274         KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00275         if (def->isValid())
00276         {
00277             KIconThemeNode* node = new KIconThemeNode(def);
00278             d->links.append(node);
00279             addBaseThemes(node, appname);
00280         }
00281         else
00282             delete def;
00283     }
00284 
00285     KIconTheme *def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00286     KIconThemeNode* node = new KIconThemeNode(def);
00287     d->links.append(node);
00288     addBaseThemes(node, appname);
00289 }
00290 
00291 void KIconLoader::addBaseThemes(KIconThemeNode *node, const QString &appname)
00292 {
00293     QStringList lst = node->theme->inherits();
00294     QStringList::ConstIterator it;
00295 
00296     for (it=lst.begin(); it!=lst.end(); ++it)
00297     {
00298     if (!d->mThemeList.contains(*it) ||
00299         ( d->mThemesInTree.contains(*it) && (*it) != "hicolor"))
00300         continue;
00301     KIconTheme *theme = new KIconTheme(*it,appname);
00302     if (!theme->isValid()) {
00303         delete theme;
00304         continue;
00305     }
00306         KIconThemeNode *n = new KIconThemeNode(theme);
00307     d->mThemesInTree.append(*it);
00308     addBaseThemes(n, appname);
00309     d->links.append(n);
00310     }
00311 }
00312 
00313 void KIconLoader::addExtraDesktopThemes()
00314 {
00315     if ( d->extraDesktopIconsLoaded ) return;
00316 
00317     QStringList list;
00318     QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
00319     QStringList::ConstIterator it;
00320     char buf[1000];
00321     int r;
00322     for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00323     {
00324     QDir dir(*it);
00325     if (!dir.exists())
00326         continue;
00327     QStringList lst = dir.entryList("default.*", QDir::Dirs);
00328     QStringList::ConstIterator it2;
00329     for (it2=lst.begin(); it2!=lst.end(); ++it2)
00330     {
00331         if (!KStandardDirs::exists(*it + *it2 + "/index.desktop")
00332         && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
00333         continue;
00334         r=readlink( QFile::encodeName(*it + *it2) , buf, sizeof(buf)-1);
00335         if ( r>0 )
00336         {
00337           buf[r]=0;
00338           QDir dir2( buf );
00339           QString themeName=dir2.dirName();
00340 
00341           if (!list.contains(themeName))
00342         list.append(themeName);
00343         }
00344     }
00345     }
00346 
00347     for (it=list.begin(); it!=list.end(); ++it)
00348     {
00349     if ( d->mThemesInTree.contains(*it) )
00350         continue;
00351     if ( *it == QString("default.kde") ) continue;
00352 
00353     KIconTheme *def = new KIconTheme( *it, "" );
00354     KIconThemeNode* node = new KIconThemeNode(def);
00355     d->mThemesInTree.append(*it);
00356     d->links.append(node);
00357     addBaseThemes(node, "" );
00358     }
00359 
00360     d->extraDesktopIconsLoaded=true;
00361 
00362 }
00363 
00364 bool KIconLoader::extraDesktopThemesAdded() const
00365 {
00366     return d->extraDesktopIconsLoaded;
00367 }
00368 
00369 QString KIconLoader::removeIconExtension(const QString &name) const
00370 {
00371     int extensionLength=0;
00372 
00373     QString ext = name.right(4);
00374 
00375     static const QString &png_ext = KGlobal::staticQString(".png");
00376     static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00377     if (ext == png_ext || ext == xpm_ext)
00378       extensionLength=4;
00379 #ifdef HAVE_LIBART
00380     else
00381     {
00382     static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00383     static const QString &svg_ext = KGlobal::staticQString(".svg");
00384 
00385     if (name.right(5) == svgz_ext)
00386         extensionLength=5;
00387     else if (ext == svg_ext)
00388         extensionLength=4;
00389     }
00390 #endif
00391 
00392     if ( extensionLength > 0 )
00393     {
00394 #ifndef NDEBUG
00395     kdDebug(264) << "Application " << KGlobal::instance()->instanceName()
00396                      << " loads icon " << name << " with extension." << endl;
00397 #endif
00398 
00399     return name.left(name.length() - extensionLength);
00400     }
00401     return name;
00402 }
00403 
00404 
00405 KIcon KIconLoader::findMatchingIcon(const QString& name, int size) const
00406 {
00407     KIcon icon;
00408 
00409     const QString *ext[4];
00410     int count=0;
00411     static const QString &png_ext = KGlobal::staticQString(".png");
00412     ext[count++]=&png_ext;
00413 #ifdef HAVE_LIBART
00414     static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00415     ext[count++]=&svgz_ext;
00416     static const QString &svg_ext = KGlobal::staticQString(".svg");
00417     ext[count++]=&svg_ext;
00418 #endif
00419     static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00420     ext[count++]=&xpm_ext;
00421 
00422     /* antlarr: Multiple inheritance is a broken concept on icon themes, so
00423        the next code doesn't support it on purpose because in fact, it was
00424        never supported at all. This makes the order in which we look for an
00425        icon as:
00426 
00427        png, svgz, svg, xpm exact match
00428        next theme in inheritance tree : png, svgz, svg, xpm exact match
00429        next theme in inheritance tree : png, svgz, svg, xpm exact match
00430        and so on
00431 
00432        And if the icon couldn't be found then it tries best match in the same
00433        order.
00434 
00435        */
00436     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00437     themeNode = d->links.next() )
00438     {
00439     for (int i = 0 ; i < count ; i++)
00440     {
00441         icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchExact);
00442         if (icon.isValid())
00443         return icon;
00444     }
00445 
00446     }
00447 
00448     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00449     themeNode = d->links.next() )
00450     {
00451     for (int i = 0 ; i < count ; i++)
00452     {
00453         icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchBest);
00454         if (icon.isValid())
00455         return icon;
00456     }
00457 
00458     }
00459 
00460     return icon;
00461 }
00462 
00463 inline QString KIconLoader::unknownIconPath( int size ) const
00464 {
00465     static const QString &str_unknown = KGlobal::staticQString("unknown");
00466 
00467     KIcon icon = findMatchingIcon(str_unknown, size);
00468     if (!icon.isValid())
00469     {
00470         kdDebug(264) << "Warning: could not find \"Unknown\" icon for size = "
00471                      << size << endl;
00472         return QString::null;
00473     }
00474     return icon.path;
00475 }
00476 
00477 // Finds the absolute path to an icon.
00478 
00479 QString KIconLoader::iconPath(const QString& _name, int group_or_size,
00480                   bool canReturnNull) const
00481 {
00482     if (d->mpThemeRoot == 0L)
00483     return QString::null;
00484 
00485     if (_name.at(0) == '/')
00486     return _name;
00487 
00488     QString name = removeIconExtension( _name );
00489 
00490     QString path;
00491     if (group_or_size == KIcon::User)
00492     {
00493     static const QString &png_ext = KGlobal::staticQString(".png");
00494     static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00495     path = d->mpDirs->findResource("appicon", name + png_ext);
00496 
00497 #ifdef HAVE_LIBART
00498     static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00499     static const QString &svg_ext = KGlobal::staticQString(".svg");
00500     if (path.isEmpty())
00501         path = d->mpDirs->findResource("appicon", name + svgz_ext);
00502     if (path.isEmpty())
00503        path = d->mpDirs->findResource("appicon", name + svg_ext);
00504 #endif
00505     if (path.isEmpty())
00506          path = d->mpDirs->findResource("appicon", name + xpm_ext);
00507     return path;
00508     }
00509 
00510     if (group_or_size >= KIcon::LastGroup)
00511     {
00512     kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
00513     return path;
00514     }
00515 
00516     int size;
00517     if (group_or_size >= 0)
00518     size = d->mpGroups[group_or_size].size;
00519     else
00520     size = -group_or_size;
00521 
00522     if (_name.isEmpty()) {
00523         if (canReturnNull)
00524             return QString::null;
00525         else
00526             return unknownIconPath(size);
00527     }
00528 
00529     KIcon icon = findMatchingIcon(name, size);
00530 
00531     if (!icon.isValid())
00532     {
00533     // Try "User" group too.
00534     path = iconPath(name, KIcon::User, true);
00535     if (!path.isEmpty() || canReturnNull)
00536         return path;
00537 
00538     if (canReturnNull)
00539         return QString::null;
00540         else
00541             return unknownIconPath(size);
00542     }
00543     return icon.path;
00544 }
00545 
00546 QPixmap KIconLoader::loadIcon(const QString& _name, KIcon::Group group, int size,
00547                               int state, QString *path_store, bool canReturnNull) const
00548 {
00549     QString name = _name;
00550     QPixmap pix;
00551     QString key;
00552     bool absolutePath=false, favIconOverlay=false;
00553 
00554     if (d->mpThemeRoot == 0L)
00555     return pix;
00556 
00557     // Special case for absolute path icons.
00558     if (name.startsWith("favicons/"))
00559     {
00560        favIconOverlay = true;
00561        name = locateLocal("cache", name+".png");
00562     }
00563     if (name.at(0) == '/') absolutePath=true;
00564 
00565     static const QString &str_unknown = KGlobal::staticQString("unknown");
00566 
00567     // Special case for "User" icons.
00568     if (group == KIcon::User)
00569     {
00570     key = "$kicou_";
00571         key += QString::number(size); key += '_';
00572     key += name;
00573     bool inCache = QPixmapCache::find(key, pix);
00574     if (inCache && (path_store == 0L))
00575         return pix;
00576 
00577     QString path = (absolutePath) ? name :
00578             iconPath(name, KIcon::User, canReturnNull);
00579     if (path.isEmpty())
00580     {
00581         if (canReturnNull)
00582         return pix;
00583         // We don't know the desired size: use small
00584         path = iconPath(str_unknown, KIcon::Small, true);
00585         if (path.isEmpty())
00586         {
00587         kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl;
00588         return pix;
00589         }
00590     }
00591 
00592     if (path_store != 0L)
00593         *path_store = path;
00594     if (inCache)
00595         return pix;
00596     QImage img(path);
00597     if (size != 0)
00598         img=img.smoothScale(size,size);
00599 
00600     pix.convertFromImage(img);
00601     QPixmapCache::insert(key, pix);
00602     return pix;
00603     }
00604 
00605     // Regular case: Check parameters
00606 
00607     if ((group < -1) || (group >= KIcon::LastGroup))
00608     {
00609     kdDebug(264) << "Illegal icon group: " << group << endl;
00610     group = KIcon::Desktop;
00611     }
00612 
00613     int overlay = (state & KIcon::OverlayMask);
00614     state &= ~KIcon::OverlayMask;
00615     if ((state < 0) || (state >= KIcon::LastState))
00616     {
00617     kdDebug(264) << "Illegal icon state: " << state << endl;
00618     state = KIcon::DefaultState;
00619     }
00620 
00621     if (size == 0 && group < 0)
00622     {
00623     kdDebug(264) << "Neither size nor group specified!" << endl;
00624     group = KIcon::Desktop;
00625     }
00626 
00627     if (!absolutePath)
00628     {
00629         if (!canReturnNull && name.isEmpty())
00630             name = str_unknown;
00631         else
00632         name = removeIconExtension(name);
00633     }
00634 
00635     // If size == 0, use default size for the specified group.
00636     if (size == 0)
00637     {
00638     size = d->mpGroups[group].size;
00639     }
00640     favIconOverlay = favIconOverlay && size > 22;
00641 
00642     // Generate a unique cache key for the icon.
00643 
00644     key = "$kico_";
00645     key += name; key += '_';
00646     key += QString::number(size); key += '_';
00647 
00648     QString overlayStr = QString::number( overlay );
00649 
00650     QString noEffectKey = key + '_' + overlayStr;
00651 
00652     if (group >= 0)
00653     {
00654     key += d->mpEffect.fingerprint(group, state);
00655     if (d->mpGroups[group].dblPixels)
00656         key += QString::fromLatin1(":dblsize");
00657     } else
00658     key += QString::fromLatin1("noeffect");
00659     key += '_';
00660     key += overlayStr;
00661 
00662     // Is the icon in the cache?
00663     bool inCache = QPixmapCache::find(key, pix);
00664     if (inCache && (path_store == 0L))
00665     return pix;
00666 
00667     QImage *img = 0;
00668     int iconType;
00669     int iconThreshold;
00670 
00671     if ( ( path_store != 0L ) ||
00672          noEffectKey != d->lastImageKey )
00673     {
00674         // No? load it.
00675         KIcon icon;
00676         if (absolutePath && !favIconOverlay)
00677         {
00678             icon.context=KIcon::Any;
00679             icon.type=KIcon::Scalable;
00680             icon.path=name;
00681         }
00682         else
00683         {
00684             if (!name.isEmpty())
00685                 icon = findMatchingIcon(favIconOverlay ? QString("www") : name, size);
00686 
00687             if (!icon.isValid())
00688             {
00689                 // Try "User" icon too. Some apps expect this.
00690                 if (!name.isEmpty())
00691                     pix = loadIcon(name, KIcon::User, size, state, path_store, true);
00692                 if (!pix.isNull() || canReturnNull)
00693                     return pix;
00694 
00695                 icon = findMatchingIcon(str_unknown, size);
00696                 if (!icon.isValid())
00697                 {
00698                     kdDebug(264)
00699                         << "Warning: could not find \"Unknown\" icon for size = "
00700                         << size << endl;
00701                     return pix;
00702                 }
00703             }
00704         }
00705 
00706         if (path_store != 0L)
00707             *path_store = icon.path;
00708         if (inCache)
00709             return pix;
00710 
00711     // Use the extension as the format. Works for XPM and PNG, but not for SVG
00712     QString ext = icon.path.right(3).upper();
00713     if(ext != "SVG" && ext != "VGZ")
00714     {
00715         img = new QImage(icon.path, ext.latin1());
00716         if (img->isNull()) {
00717                 delete img;
00718         return pix;
00719             }
00720     }
00721 #ifdef HAVE_LIBART
00722     else
00723     {
00724         // Special stuff for SVG icons
00725         KSVGIconEngine *svgEngine = new KSVGIconEngine();
00726 
00727         if(svgEngine->load(size, size, icon.path))
00728         img = svgEngine->painter()->image();
00729         else
00730         img = new QImage();
00731 
00732         delete svgEngine;
00733     }
00734 #endif
00735 
00736         iconType = icon.type;
00737         iconThreshold = icon.threshold;
00738 
00739         d->lastImage = img->copy();
00740         d->lastImageKey = noEffectKey;
00741         d->lastIconType = iconType;
00742         d->lastIconThreshold = iconThreshold;
00743     }
00744     else
00745     {
00746         img = new QImage( d->lastImage.copy() );
00747         iconType = d->lastIconType;
00748         iconThreshold = d->lastIconThreshold;
00749     }
00750 
00751     // Blend in all overlays
00752     if (overlay)
00753     {
00754     QImage *ovl;
00755     KIconTheme *theme = d->mpThemeRoot->theme;
00756     if ((overlay & KIcon::LockOverlay) &&
00757         ((ovl = loadOverlay(theme->lockOverlay(), size)) != 0L))
00758         KIconEffect::overlay(*img, *ovl);
00759     if ((overlay & KIcon::LinkOverlay) &&
00760         ((ovl = loadOverlay(theme->linkOverlay(), size)) != 0L))
00761         KIconEffect::overlay(*img, *ovl);
00762     if ((overlay & KIcon::ZipOverlay) &&
00763         ((ovl = loadOverlay(theme->zipOverlay(), size)) != 0L))
00764         KIconEffect::overlay(*img, *ovl);
00765     if ((overlay & KIcon::ShareOverlay) &&
00766         ((ovl = loadOverlay(theme->shareOverlay(), size)) != 0L))
00767       KIconEffect::overlay(*img, *ovl);
00768         if (overlay & KIcon::HiddenOverlay)
00769             for (int y = 0; y < img->height(); y++)
00770             {
00771         Q_UINT32 *line = reinterpret_cast<Q_UINT32 *>(img->scanLine(y));
00772                 for (int x = 0; x < img->width();  x++)
00773                     line[x] = (line[x] & 0x00ffffff) | (QMIN(0x80, qAlpha(line[x])) << 24);
00774         }
00775     }
00776 
00777     // Scale the icon and apply effects if necessary
00778     if (iconType == KIcon::Scalable && size != img->width())
00779     {
00780         *img = img->smoothScale(size, size);
00781     }
00782     if (iconType == KIcon::Threshold && size != img->width())
00783     {
00784     if ( abs(size-img->width())>iconThreshold )
00785         *img = img->smoothScale(size, size);
00786     }
00787     if (group >= 0 && d->mpGroups[group].dblPixels)
00788     {
00789     *img = d->mpEffect.doublePixels(*img);
00790     }
00791     if (group >= 0)
00792     {
00793     *img = d->mpEffect.apply(*img, group, state);
00794     }
00795 
00796     pix.convertFromImage(*img);
00797 
00798     delete img;
00799 
00800     if (favIconOverlay)
00801     {
00802         QPixmap favIcon(name, "PNG");
00803         int x = pix.width() - favIcon.width() - 1,
00804             y = pix.height() - favIcon.height() - 1;
00805         if (pix.mask())
00806         {
00807             QBitmap mask = *pix.mask();
00808             QBitmap fmask;
00809             if (favIcon.mask())
00810         fmask = *favIcon.mask();
00811         else {
00812         // expensive, but works
00813         fmask = favIcon.createHeuristicMask();
00814         }
00815 
00816             bitBlt(&mask, x, y, &fmask,
00817                    0, 0, favIcon.width(), favIcon.height(),
00818                    favIcon.mask() ? Qt::OrROP : Qt::SetROP);
00819             pix.setMask(mask);
00820         }
00821         bitBlt(&pix, x, y, &favIcon);
00822     }
00823 
00824     QPixmapCache::insert(key, pix);
00825     return pix;
00826 }
00827 
00828 QImage *KIconLoader::loadOverlay(const QString &name, int size) const
00829 {
00830     QString key = name + '_' + QString::number(size);
00831     QImage *image = d->imgDict.find(key);
00832     if (image != 0L)
00833     return image;
00834 
00835     KIcon icon = findMatchingIcon(name, size);
00836     if (!icon.isValid())
00837     {
00838     kdDebug(264) << "Overlay " << name << "not found." << endl;
00839     return 0L;
00840     }
00841     image = new QImage(icon.path);
00842     // In some cases (since size in findMatchingIcon() is more a hint than a
00843     // constraint) image->size can be != size. If so perform rescaling.
00844     if ( size != image->width() )
00845         *image = image->smoothScale( size, size );
00846     d->imgDict.insert(key, image);
00847     return image;
00848 }
00849 
00850 
00851 
00852 QMovie KIconLoader::loadMovie(const QString& name, KIcon::Group group, int size) const
00853 {
00854     QString file = moviePath( name, group, size );
00855     if (file.isEmpty())
00856     return QMovie();
00857     int dirLen = file.findRev('/');
00858     QString icon = iconPath(name, size ? -size : group, true);
00859     if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
00860     return QMovie();
00861     return QMovie(file);
00862 }
00863 
00864 QString KIconLoader::moviePath(const QString& name, KIcon::Group group, int size) const
00865 {
00866     if (!d->mpGroups) return QString::null;
00867 
00868     if ( (group < -1 || group >= KIcon::LastGroup) && group != KIcon::User )
00869     {
00870     kdDebug(264) << "Illegal icon group: " << group << endl;
00871     group = KIcon::Desktop;
00872     }
00873     if (size == 0 && group < 0)
00874     {
00875     kdDebug(264) << "Neither size nor group specified!" << endl;
00876     group = KIcon::Desktop;
00877     }
00878 
00879     QString file = name + ".mng";
00880     if (group == KIcon::User)
00881     {
00882     file = d->mpDirs->findResource("appicon", file);
00883     }
00884     else
00885     {
00886     if (size == 0)
00887         size = d->mpGroups[group].size;
00888 
00889         KIcon icon;
00890     
00891     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00892         themeNode = d->links.next() )
00893     {
00894         icon = themeNode->theme->iconPath(file, size, KIcon::MatchExact);
00895         if (icon.isValid())
00896         break;
00897     }
00898     
00899     if ( !icon.isValid() )
00900     {
00901         for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00902             themeNode = d->links.next() )
00903         {
00904         icon = themeNode->theme->iconPath(file, size, KIcon::MatchBest);
00905         if (icon.isValid())
00906             break;
00907         }
00908     }
00909     
00910     file = icon.isValid() ? icon.path : QString::null;
00911     }
00912     return file;
00913 }
00914 
00915 
00916 QStringList KIconLoader::loadAnimated(const QString& name, KIcon::Group group, int size) const
00917 {
00918     QStringList lst;
00919 
00920     if (!d->mpGroups) return lst;
00921 
00922     if ((group < -1) || (group >= KIcon::LastGroup))
00923     {
00924     kdDebug(264) << "Illegal icon group: " << group << endl;
00925     group = KIcon::Desktop;
00926     }
00927     if ((size == 0) && (group < 0))
00928     {
00929     kdDebug(264) << "Neither size nor group specified!" << endl;
00930     group = KIcon::Desktop;
00931     }
00932 
00933     QString file = name + "/0001";
00934     if (group == KIcon::User)
00935     {
00936     file = d->mpDirs->findResource("appicon", file + ".png");
00937     } else
00938     {
00939     if (size == 0)
00940         size = d->mpGroups[group].size;
00941     KIcon icon = findMatchingIcon(file, size);
00942     file = icon.isValid() ? icon.path : QString::null;
00943 
00944     }
00945     if (file.isEmpty())
00946     return lst;
00947 
00948     QString path = file.left(file.length()-8);
00949     DIR* dp = opendir( QFile::encodeName(path) );
00950     if(!dp)
00951         return lst;
00952 
00953     struct dirent* ep;
00954     while( ( ep = readdir( dp ) ) != 0L )
00955     {
00956         QString fn(QFile::decodeName(ep->d_name));
00957         if(!(fn.left(4)).toUInt())
00958             continue;
00959 
00960         lst += path + fn;
00961     }
00962     closedir ( dp );
00963     lst.sort();
00964     return lst;
00965 }
00966 
00967 KIconTheme *KIconLoader::theme() const
00968 {
00969     if (d->mpThemeRoot) return d->mpThemeRoot->theme;
00970     return 0L;
00971 }
00972 
00973 int KIconLoader::currentSize(KIcon::Group group) const
00974 {
00975     if (!d->mpGroups) return -1;
00976 
00977     if (group < 0 || group >= KIcon::LastGroup)
00978     {
00979     kdDebug(264) << "Illegal icon group: " << group << endl;
00980     return -1;
00981     }
00982     return d->mpGroups[group].size;
00983 }
00984 
00985 QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
00986 {
00987   QDir dir(iconsDir);
00988   QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files);
00989   QStringList result;
00990   QStringList::ConstIterator it;
00991   for (it=lst.begin(); it!=lst.end(); ++it)
00992     result += iconsDir + "/" + *it;
00993   return result;
00994 }
00995 
00996 QStringList KIconLoader::queryIconsByContext(int group_or_size,
00997                         KIcon::Context context) const
00998 {
00999     QStringList result;
01000     if (group_or_size >= KIcon::LastGroup)
01001     {
01002     kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
01003     return result;
01004     }
01005     int size;
01006     if (group_or_size >= 0)
01007     size = d->mpGroups[group_or_size].size;
01008     else
01009     size = -group_or_size;
01010 
01011     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
01012             themeNode = d->links.next() )
01013        themeNode->queryIconsByContext(&result, size, context);
01014 
01015     // Eliminate duplicate entries (same icon in different directories)
01016     QString name;
01017     QStringList res2, entries;
01018     QStringList::ConstIterator it;
01019     for (it=result.begin(); it!=result.end(); ++it)
01020     {
01021     int n = (*it).findRev('/');
01022     if (n == -1)
01023         name = *it;
01024     else
01025         name = (*it).mid(n+1);
01026     name = removeIconExtension(name);
01027     if (!entries.contains(name))
01028     {
01029         entries += name;
01030         res2 += *it;
01031     }
01032     }
01033     return res2;
01034 
01035 }
01036 
01037 QStringList KIconLoader::queryIcons(int group_or_size, KIcon::Context context) const
01038 {
01039     QStringList result;
01040     if (group_or_size >= KIcon::LastGroup)
01041     {
01042     kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
01043     return result;
01044     }
01045     int size;
01046     if (group_or_size >= 0)
01047     size = d->mpGroups[group_or_size].size;
01048     else
01049     size = -group_or_size;
01050 
01051     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
01052             themeNode = d->links.next() )
01053        themeNode->queryIcons(&result, size, context);
01054 
01055     // Eliminate duplicate entries (same icon in different directories)
01056     QString name;
01057     QStringList res2, entries;
01058     QStringList::ConstIterator it;
01059     for (it=result.begin(); it!=result.end(); ++it)
01060     {
01061     int n = (*it).findRev('/');
01062     if (n == -1)
01063         name = *it;
01064     else
01065         name = (*it).mid(n+1);
01066     name = removeIconExtension(name);
01067     if (!entries.contains(name))
01068     {
01069         entries += name;
01070         res2 += *it;
01071     }
01072     }
01073     return res2;
01074 }
01075 
01076 KIconEffect * KIconLoader::iconEffect() const
01077 {
01078     return &d->mpEffect;
01079 }
01080 
01081 bool KIconLoader::alphaBlending(KIcon::Group group) const
01082 {
01083     if (!d->mpGroups) return -1;
01084 
01085     if (group < 0 || group >= KIcon::LastGroup)
01086     {
01087     kdDebug(264) << "Illegal icon group: " << group << endl;
01088     return -1;
01089     }
01090     return d->mpGroups[group].alphaBlending;
01091 }
01092 
01093 QIconSet KIconLoader::loadIconSet(const QString& name, KIcon::Group group, int size)
01094 {
01095     return loadIconSet( name, group, size, false );
01096 }
01097 
01098 /*** class for delayed icon loading for QIconSet ***/
01099 
01100 class KIconFactory
01101     : public QIconFactory
01102     {
01103     public:
01104         KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01105             int size_P, KIconLoader* loader_P );
01106         virtual QPixmap* createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode, QIconSet::State );
01107     private:
01108         QString iconName;
01109         KIcon::Group group;
01110         int size;
01111         KIconLoader* loader;
01112     };
01113 
01114 
01115 QIconSet KIconLoader::loadIconSet( const QString& name, KIcon::Group g, int s,
01116     bool canReturnNull)
01117 {
01118     if ( !d->delayedLoading )
01119         return loadIconSetNonDelayed( name, g, s, canReturnNull );
01120 
01121     if (g < -1 || g > 6) {
01122         kdDebug() << "KIconLoader::loadIconSet " << name << " " << (int)g << " " << s << endl;
01123         qDebug("%s", kdBacktrace().latin1());
01124         abort();
01125     }
01126 
01127     if(canReturnNull)
01128     { // we need to find out if the icon actually exists
01129         QPixmap pm = loadIcon( name, g, s, KIcon::DefaultState, NULL, true );
01130         if( pm.isNull())
01131             return QIconSet();
01132 
01133         QIconSet ret( pm );
01134         ret.installIconFactory( new KIconFactory( name, g, s, this ));
01135         return ret;
01136     }
01137 
01138     QIconSet ret;
01139     ret.installIconFactory( new KIconFactory( name, g, s, this ));
01140     return ret;
01141 }
01142 
01143 QIconSet KIconLoader::loadIconSetNonDelayed( const QString& name,
01144                                              KIcon::Group g,
01145                                              int s, bool canReturnNull )
01146 {
01147     QIconSet iconset;
01148     QPixmap tmp = loadIcon(name, g, s, KIcon::ActiveState, NULL, canReturnNull);
01149     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Active );
01150     // we don't use QIconSet's resizing anyway
01151     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Active );
01152     tmp = loadIcon(name, g, s, KIcon::DisabledState, NULL, canReturnNull);
01153     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Disabled );
01154     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Disabled );
01155     tmp = loadIcon(name, g, s, KIcon::DefaultState, NULL, canReturnNull);
01156     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Normal );
01157     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Normal );
01158     return iconset;
01159 }
01160 
01161 KIconFactory::KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01162     int size_P, KIconLoader* loader_P )
01163     : iconName( iconName_P ), group( group_P ), size( size_P ), loader( loader_P )
01164 {
01165     setAutoDelete( true );
01166 }
01167 
01168 QPixmap* KIconFactory::createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode mode_P, QIconSet::State )
01169     {
01170     // QIconSet::Mode to KIcon::State conversion
01171     static const KIcon::States tbl[] = { KIcon::DefaultState, KIcon::DisabledState, KIcon::ActiveState };
01172     int state = KIcon::DefaultState;
01173     if( mode_P <= QIconSet::Active )
01174         state = tbl[ mode_P ];
01175     if( group >= 0 && state == KIcon::ActiveState )
01176     { // active and normal icon are usually the same
01177     if( loader->iconEffect()->fingerprint(group, KIcon::ActiveState )
01178             == loader->iconEffect()->fingerprint(group, KIcon::DefaultState ))
01179             return 0; // so let QIconSet simply duplicate it
01180     }
01181     // ignore passed size
01182     // ignore passed state (i.e. on/off)
01183     QPixmap pm = loader->loadIcon( iconName, group, size, state );
01184     return new QPixmap( pm );
01185     }
01186 
01187 // Easy access functions
01188 
01189 QPixmap DesktopIcon(const QString& name, int force_size, int state,
01190     KInstance *instance)
01191 {
01192     KIconLoader *loader = instance->iconLoader();
01193     return loader->loadIcon(name, KIcon::Desktop, force_size, state);
01194 }
01195 
01196 QPixmap DesktopIcon(const QString& name, KInstance *instance)
01197 {
01198     return DesktopIcon(name, 0, KIcon::DefaultState, instance);
01199 }
01200 
01201 QIconSet DesktopIconSet(const QString& name, int force_size, KInstance *instance)
01202 {
01203     KIconLoader *loader = instance->iconLoader();
01204     return loader->loadIconSet( name, KIcon::Desktop, force_size );
01205 }
01206 
01207 QPixmap BarIcon(const QString& name, int force_size, int state,
01208     KInstance *instance)
01209 {
01210     KIconLoader *loader = instance->iconLoader();
01211     return loader->loadIcon(name, KIcon::Toolbar, force_size, state);
01212 }
01213 
01214 QPixmap BarIcon(const QString& name, KInstance *instance)
01215 {
01216     return BarIcon(name, 0, KIcon::DefaultState, instance);
01217 }
01218 
01219 QIconSet BarIconSet(const QString& name, int force_size, KInstance *instance)
01220 {
01221     KIconLoader *loader = instance->iconLoader();
01222     return loader->loadIconSet( name, KIcon::Toolbar, force_size );
01223 }
01224 
01225 QPixmap SmallIcon(const QString& name, int force_size, int state,
01226     KInstance *instance)
01227 {
01228     KIconLoader *loader = instance->iconLoader();
01229     return loader->loadIcon(name, KIcon::Small, force_size, state);
01230 }
01231 
01232 QPixmap SmallIcon(const QString& name, KInstance *instance)
01233 {
01234     return SmallIcon(name, 0, KIcon::DefaultState, instance);
01235 }
01236 
01237 QIconSet SmallIconSet(const QString& name, int force_size, KInstance *instance)
01238 {
01239     KIconLoader *loader = instance->iconLoader();
01240     return loader->loadIconSet( name, KIcon::Small, force_size );
01241 }
01242 
01243 QPixmap MainBarIcon(const QString& name, int force_size, int state,
01244     KInstance *instance)
01245 {
01246     KIconLoader *loader = instance->iconLoader();
01247     return loader->loadIcon(name, KIcon::MainToolbar, force_size, state);
01248 }
01249 
01250 QPixmap MainBarIcon(const QString& name, KInstance *instance)
01251 {
01252     return MainBarIcon(name, 0, KIcon::DefaultState, instance);
01253 }
01254 
01255 QIconSet MainBarIconSet(const QString& name, int force_size, KInstance *instance)
01256 {
01257     KIconLoader *loader = instance->iconLoader();
01258     return loader->loadIconSet( name, KIcon::MainToolbar, force_size );
01259 }
01260 
01261 QPixmap UserIcon(const QString& name, int state, KInstance *instance)
01262 {
01263     KIconLoader *loader = instance->iconLoader();
01264     return loader->loadIcon(name, KIcon::User, 0, state);
01265 }
01266 
01267 QPixmap UserIcon(const QString& name, KInstance *instance)
01268 {
01269     return UserIcon(name, KIcon::DefaultState, instance);
01270 }
01271 
01272 QIconSet UserIconSet(const QString& name, KInstance *instance)
01273 {
01274     KIconLoader *loader = instance->iconLoader();
01275     return loader->loadIconSet( name, KIcon::User );
01276 }
01277 
01278 int IconSize(KIcon::Group group, KInstance *instance)
01279 {
01280     KIconLoader *loader = instance->iconLoader();
01281     return loader->currentSize(group);
01282 }
01283 
01284 QPixmap KIconLoader::unknown()
01285 {
01286     QPixmap pix;
01287     if ( QPixmapCache::find("unknown", pix) )
01288             return pix;
01289 
01290     QString path = KGlobal::iconLoader()->iconPath("unknown", KIcon::Small, true);
01291     if (path.isEmpty())
01292     {
01293     kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl;
01294     pix.resize(32,32);
01295     } else
01296     {
01297         pix.load(path);
01298         QPixmapCache::insert("unknown", pix);
01299     }
01300 
01301     return pix;
01302 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Nov 27 13:41:14 2004 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003