kdecore Library API Documentation

kiconloader.cpp

00001 /* vi: ts=8 sts=4 sw=4
00002  *
00003  * $Id: kiconloader.cpp,v 1.217 2003/11/20 21:41:54 antlarr 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     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00224         appname + "/toolbar/");
00225 
00226     // Add legacy icon dirs.
00227     QStringList dirs;
00228     dirs += d->mpDirs->resourceDirs("icon");
00229     dirs += d->mpDirs->resourceDirs("pixmap");
00230     for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it)
00231     d->mpDirs->addResourceDir("appicon", *it);
00232 
00233 #ifndef NDEBUG
00234     QString dbgString = "Theme tree: ";
00235     d->mpThemeRoot->printTree(dbgString);
00236     kdDebug(264) << dbgString << endl;
00237 #endif
00238 }
00239 
00240 KIconLoader::~KIconLoader()
00241 {
00242     /* antlarr: There's no need to delete d->mpThemeRoot as it's already
00243        deleted when the elements of d->links are deleted */
00244     d->mpThemeRoot=0;
00245     delete[] d->mpGroups;
00246     delete d;
00247 }
00248 
00249 void KIconLoader::enableDelayedIconSetLoading( bool enable )
00250 {
00251     d->delayedLoading = enable;
00252 }
00253 
00254 bool KIconLoader::isDelayedIconSetLoadingEnabled() const
00255 {
00256     return d->delayedLoading;
00257 }
00258 
00259 void KIconLoader::addAppDir(const QString& appname)
00260 {
00261     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00262         appname + "/pics/");
00263     d->mpDirs->addResourceType("appicon", KStandardDirs::kde_default("data") +
00264         appname + "/toolbar/");
00265     addAppThemes(appname);
00266 }
00267 
00268 void KIconLoader::addAppThemes(const QString& appname)
00269 {
00270     if ( KIconTheme::current() != KIconTheme::defaultThemeName() )
00271     {
00272         KIconTheme *def = new KIconTheme(KIconTheme::current(), appname);
00273         if (def->isValid())
00274         {
00275             KIconThemeNode* node = new KIconThemeNode(def);
00276             d->links.append(node);
00277             addBaseThemes(node, appname);
00278         }
00279         else
00280             delete def;
00281     }
00282 
00283     KIconTheme *def = new KIconTheme(KIconTheme::defaultThemeName(), appname);
00284     KIconThemeNode* node = new KIconThemeNode(def);
00285     d->links.append(node);
00286     addBaseThemes(node, appname);
00287 }
00288 
00289 void KIconLoader::addBaseThemes(KIconThemeNode *node, const QString &appname)
00290 {
00291     QStringList lst = node->theme->inherits();
00292     QStringList::ConstIterator it;
00293 
00294     for (it=lst.begin(); it!=lst.end(); ++it)
00295     {
00296     if (!d->mThemeList.contains(*it) ||
00297         ( d->mThemesInTree.contains(*it) && (*it) != "hicolor"))
00298         continue;
00299     KIconTheme *theme = new KIconTheme(*it,appname);
00300     if (!theme->isValid()) {
00301         delete theme;
00302         continue;
00303     }
00304         KIconThemeNode *n = new KIconThemeNode(theme);
00305     d->mThemesInTree.append(*it);
00306     addBaseThemes(n, appname);
00307     d->links.append(n);
00308     }
00309 }
00310 
00311 void KIconLoader::addExtraDesktopThemes()
00312 {
00313     if ( d->extraDesktopIconsLoaded ) return;
00314 
00315     QStringList list;
00316     QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
00317     QStringList::ConstIterator it;
00318     char buf[1000];
00319     int r;
00320     for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00321     {
00322     QDir dir(*it);
00323     if (!dir.exists())
00324         continue;
00325     QStringList lst = dir.entryList("default.*", QDir::Dirs);
00326     QStringList::ConstIterator it2;
00327     for (it2=lst.begin(); it2!=lst.end(); ++it2)
00328     {
00329         if (!KStandardDirs::exists(*it + *it2 + "/index.desktop")
00330         && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
00331         continue;
00332         r=readlink( QFile::encodeName(*it + *it2) , buf, sizeof(buf)-1);
00333         if ( r>0 )
00334         {
00335           buf[r]=0;
00336           QDir dir2( buf );
00337           QString themeName=dir2.dirName();
00338 
00339           if (!list.contains(themeName))
00340         list.append(themeName);
00341         }
00342     }
00343     }
00344 
00345     for (it=list.begin(); it!=list.end(); ++it)
00346     {
00347     if ( d->mThemesInTree.contains(*it) )
00348         continue;
00349     if ( *it == QString("default.kde") ) continue;
00350 
00351     KIconTheme *def = new KIconTheme( *it, "" );
00352     KIconThemeNode* node = new KIconThemeNode(def);
00353     d->mThemesInTree.append(*it);
00354     d->links.append(node);
00355     addBaseThemes(node, "" );
00356     }
00357 
00358     d->extraDesktopIconsLoaded=true;
00359 
00360 }
00361 
00362 bool KIconLoader::extraDesktopThemesAdded() const
00363 {
00364     return d->extraDesktopIconsLoaded;
00365 }
00366 
00367 QString KIconLoader::removeIconExtension(const QString &name) const
00368 {
00369     int extensionLength=0;
00370 
00371     QString ext = name.right(4);
00372 
00373     static const QString &png_ext = KGlobal::staticQString(".png");
00374     static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00375     if (ext == png_ext || ext == xpm_ext)
00376       extensionLength=4;
00377 #ifdef HAVE_LIBART
00378     else
00379     {
00380     static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00381     static const QString &svg_ext = KGlobal::staticQString(".svg");
00382 
00383     if (name.right(5) == svgz_ext)
00384         extensionLength=5;
00385     else if (ext == svg_ext)
00386         extensionLength=4;
00387     }
00388 #endif
00389 
00390     if ( extensionLength > 0 )
00391     {
00392 #ifndef NDEBUG
00393     kdDebug(264) << "Application " << KGlobal::instance()->instanceName()
00394                      << " loads icon " << name << " with extension." << endl;
00395 #endif
00396 
00397     return name.left(name.length() - extensionLength);
00398     }
00399     return name;
00400 }
00401 
00402 
00403 KIcon KIconLoader::findMatchingIcon(const QString& name, int size) const
00404 {
00405     KIcon icon;
00406 
00407     const QString *ext[4];
00408     int count=0;
00409     static const QString &png_ext = KGlobal::staticQString(".png");
00410     ext[count++]=&png_ext;
00411 #ifdef HAVE_LIBART
00412     static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00413     ext[count++]=&svgz_ext;
00414     static const QString &svg_ext = KGlobal::staticQString(".svg");
00415     ext[count++]=&svg_ext;
00416 #endif
00417     static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00418     ext[count++]=&xpm_ext;
00419 
00420     /* antlarr: Multiple inheritance is a broken concept on icon themes, so
00421        the next code doesn't support it on purpose because in fact, it was
00422        never supported at all. This makes the order in which we look for an
00423        icon as:
00424 
00425        png, svgz, svg, xpm exact match
00426        next theme in inheritance tree : png, svgz, svg, xpm exact match
00427        next theme in inheritance tree : png, svgz, svg, xpm exact match
00428        and so on
00429 
00430        And if the icon couldn't be found then it tries best match in the same
00431        order.
00432 
00433        */
00434     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00435     themeNode = d->links.next() )
00436     {
00437     for (int i = 0 ; i < count ; i++)
00438     {
00439         icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchExact);
00440         if (icon.isValid())
00441         return icon;
00442     }
00443 
00444     }
00445 
00446     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00447     themeNode = d->links.next() )
00448     {
00449     for (int i = 0 ; i < count ; i++)
00450     {
00451         icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchBest);
00452         if (icon.isValid())
00453         return icon;
00454     }
00455 
00456     }
00457 
00458     return icon;
00459 }
00460 
00461 inline QString KIconLoader::unknownIconPath( int size ) const
00462 {
00463     static const QString &str_unknown = KGlobal::staticQString("unknown");
00464 
00465     KIcon icon = findMatchingIcon(str_unknown, size);
00466     if (!icon.isValid())
00467     {
00468         kdDebug(264) << "Warning: could not find \"Unknown\" icon for size = "
00469                      << size << endl;
00470         return QString::null;
00471     }
00472     return icon.path;
00473 }
00474 
00475 // Finds the absolute path to an icon.
00476 
00477 QString KIconLoader::iconPath(const QString& _name, int group_or_size,
00478                   bool canReturnNull) const
00479 {
00480     if (d->mpThemeRoot == 0L)
00481     return QString::null;
00482 
00483     if (_name.at(0) == '/')
00484     return _name;
00485 
00486     QString name = removeIconExtension( _name );
00487 
00488     QString path;
00489     if (group_or_size == KIcon::User)
00490     {
00491     static const QString &png_ext = KGlobal::staticQString(".png");
00492     static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00493     path = d->mpDirs->findResource("appicon", name + png_ext);
00494 
00495 #ifdef HAVE_LIBART
00496     static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00497     static const QString &svg_ext = KGlobal::staticQString(".svg");
00498     if (path.isEmpty())
00499         path = d->mpDirs->findResource("appicon", name + svgz_ext);
00500     if (path.isEmpty())
00501        path = d->mpDirs->findResource("appicon", name + svg_ext);
00502 #endif
00503     if (path.isEmpty())
00504          path = d->mpDirs->findResource("appicon", name + xpm_ext);
00505     return path;
00506     }
00507 
00508     if (group_or_size >= KIcon::LastGroup)
00509     {
00510     kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
00511     return path;
00512     }
00513 
00514     int size;
00515     if (group_or_size >= 0)
00516     size = d->mpGroups[group_or_size].size;
00517     else
00518     size = -group_or_size;
00519 
00520     if (_name.isEmpty()) {
00521         if (canReturnNull)
00522             return QString::null;
00523         else
00524             return unknownIconPath(size);
00525     }
00526 
00527     KIcon icon = findMatchingIcon(name, size);
00528 
00529     if (!icon.isValid())
00530     {
00531     // Try "User" group too.
00532     path = iconPath(name, KIcon::User, true);
00533     if (!path.isEmpty() || canReturnNull)
00534         return path;
00535 
00536     if (canReturnNull)
00537         return QString::null;
00538         else
00539             return unknownIconPath(size);
00540     }
00541     return icon.path;
00542 }
00543 
00544 QPixmap KIconLoader::loadIcon(const QString& _name, KIcon::Group group, int size,
00545                               int state, QString *path_store, bool canReturnNull) const
00546 {
00547     QString name = _name;
00548     QPixmap pix;
00549     QString key;
00550     bool absolutePath=false, favIconOverlay=false;
00551 
00552     if (d->mpThemeRoot == 0L)
00553     return pix;
00554 
00555     // Special case for absolute path icons.
00556     if (name.startsWith("favicons/"))
00557     {
00558        favIconOverlay = true;
00559        name = locateLocal("cache", name+".png");
00560     }
00561     if (name.at(0) == '/') absolutePath=true;
00562 
00563     static const QString &str_unknown = KGlobal::staticQString("unknown");
00564 
00565     // Special case for "User" icons.
00566     if (group == KIcon::User)
00567     {
00568     key = "$kicou_";
00569         key += QString::number(size); key += '_';
00570     key += name;
00571     bool inCache = QPixmapCache::find(key, pix);
00572     if (inCache && (path_store == 0L))
00573         return pix;
00574 
00575     QString path = (absolutePath) ? name :
00576             iconPath(name, KIcon::User, canReturnNull);
00577     if (path.isEmpty())
00578     {
00579         if (canReturnNull)
00580         return pix;
00581         // We don't know the desired size: use small
00582         path = iconPath(str_unknown, KIcon::Small, true);
00583         if (path.isEmpty())
00584         {
00585         kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl;
00586         return pix;
00587         }
00588     }
00589 
00590     if (path_store != 0L)
00591         *path_store = path;
00592     if (inCache)
00593         return pix;
00594     QImage img(path);
00595     if (size != 0)
00596         img=img.smoothScale(size,size);
00597 
00598     pix.convertFromImage(img);
00599     QPixmapCache::insert(key, pix);
00600     return pix;
00601     }
00602 
00603     // Regular case: Check parameters
00604 
00605     if ((group < -1) || (group >= KIcon::LastGroup))
00606     {
00607     kdDebug(264) << "Illegal icon group: " << group << endl;
00608     group = KIcon::Desktop;
00609     }
00610 
00611     int overlay = (state & KIcon::OverlayMask);
00612     state &= ~KIcon::OverlayMask;
00613     if ((state < 0) || (state >= KIcon::LastState))
00614     {
00615     kdDebug(264) << "Illegal icon state: " << state << endl;
00616     state = KIcon::DefaultState;
00617     }
00618 
00619     if (size == 0 && group < 0)
00620     {
00621     kdDebug(264) << "Neither size nor group specified!" << endl;
00622     group = KIcon::Desktop;
00623     }
00624 
00625     if (!absolutePath)
00626     {
00627         if (!canReturnNull && name.isEmpty())
00628             name = str_unknown;
00629         else
00630         name = removeIconExtension(name);
00631     }
00632 
00633     // If size == 0, use default size for the specified group.
00634     if (size == 0)
00635     {
00636     size = d->mpGroups[group].size;
00637     }
00638     favIconOverlay = favIconOverlay && size > 22;
00639 
00640     // Generate a unique cache key for the icon.
00641 
00642     key = "$kico_";
00643     key += name; key += '_';
00644     key += QString::number(size); key += '_';
00645 
00646     QString overlayStr = QString::number( overlay );
00647 
00648     QString noEffectKey = key + '_' + overlayStr;
00649 
00650     if (group >= 0)
00651     {
00652     key += d->mpEffect.fingerprint(group, state);
00653     if (d->mpGroups[group].dblPixels)
00654         key += QString::fromLatin1(":dblsize");
00655     } else
00656     key += QString::fromLatin1("noeffect");
00657     key += '_';
00658     key += overlayStr;
00659 
00660     // Is the icon in the cache?
00661     bool inCache = QPixmapCache::find(key, pix);
00662     if (inCache && (path_store == 0L))
00663     return pix;
00664 
00665     QImage *img = 0;
00666     int iconType;
00667     int iconThreshold;
00668 
00669     if ( ( path_store != 0L ) ||
00670          noEffectKey != d->lastImageKey )
00671     {
00672         // No? load it.
00673         KIcon icon;
00674         if (absolutePath && !favIconOverlay)
00675         {
00676             icon.context=KIcon::Any;
00677             icon.type=KIcon::Scalable;
00678             icon.path=name;
00679         }
00680         else
00681         {
00682             if (!name.isEmpty())
00683                 icon = findMatchingIcon(favIconOverlay ? QString("www") : name, size);
00684 
00685             if (!icon.isValid())
00686             {
00687                 // Try "User" icon too. Some apps expect this.
00688                 if (!name.isEmpty())
00689                     pix = loadIcon(name, KIcon::User, size, state, path_store, true);
00690                 if (!pix.isNull() || canReturnNull) {
00691             if ((group == KIcon::Small) && (pix.width() > 20 || pix.height() > 20)) {
00692             QImage tmp = pix.convertToImage();
00693             tmp = tmp.smoothScale(20, 20);
00694             pix.convertFromImage(tmp);
00695             }
00696                     return pix;
00697         }
00698 
00699                 icon = findMatchingIcon(str_unknown, size);
00700                 if (!icon.isValid())
00701                 {
00702                     kdDebug(264)
00703                         << "Warning: could not find \"Unknown\" icon for size = "
00704                         << size << endl;
00705                     return pix;
00706                 }
00707             }
00708         }
00709 
00710         if (path_store != 0L)
00711             *path_store = icon.path;
00712         if (inCache)
00713             return pix;
00714 
00715     // Use the extension as the format. Works for XPM and PNG, but not for SVG
00716     QString ext = icon.path.right(3).upper();
00717     if(ext != "SVG" && ext != "VGZ")
00718     {
00719         img = new QImage(icon.path, ext.latin1());
00720         if (img->isNull()) {
00721                 delete img;
00722         return pix;
00723             }
00724     }
00725 #ifdef HAVE_LIBART
00726     else
00727     {
00728         // Special stuff for SVG icons
00729         KSVGIconEngine *svgEngine = new KSVGIconEngine();
00730 
00731         if(svgEngine->load(size, size, icon.path))
00732         img = svgEngine->painter()->image();
00733         else
00734         img = new QImage();
00735 
00736         delete svgEngine;
00737     }
00738 #endif
00739 
00740         iconType = icon.type;
00741         iconThreshold = icon.threshold;
00742 
00743         d->lastImage = img->copy();
00744         d->lastImageKey = noEffectKey;
00745         d->lastIconType = iconType;
00746         d->lastIconThreshold = iconThreshold;
00747     }
00748     else
00749     {
00750         img = new QImage( d->lastImage.copy() );
00751         iconType = d->lastIconType;
00752         iconThreshold = d->lastIconThreshold;
00753     }
00754 
00755     // Blend in all overlays
00756     if (overlay)
00757     {
00758     QImage *ovl;
00759     KIconTheme *theme = d->mpThemeRoot->theme;
00760     if ((overlay & KIcon::LockOverlay) &&
00761         ((ovl = loadOverlay(theme->lockOverlay(), size)) != 0L))
00762         KIconEffect::overlay(*img, *ovl);
00763     if ((overlay & KIcon::LinkOverlay) &&
00764         ((ovl = loadOverlay(theme->linkOverlay(), size)) != 0L))
00765         KIconEffect::overlay(*img, *ovl);
00766     if ((overlay & KIcon::ZipOverlay) &&
00767         ((ovl = loadOverlay(theme->zipOverlay(), size)) != 0L))
00768         KIconEffect::overlay(*img, *ovl);
00769     if ((overlay & KIcon::ShareOverlay) &&
00770         ((ovl = loadOverlay(theme->shareOverlay(), size)) != 0L))
00771       KIconEffect::overlay(*img, *ovl);
00772         if (overlay & KIcon::HiddenOverlay)
00773             for (int y = 0; y < img->height(); y++)
00774             {
00775         Q_UINT32 *line = reinterpret_cast<Q_UINT32 *>(img->scanLine(y));
00776                 for (int x = 0; x < img->width();  x++)
00777                     line[x] = (line[x] & 0x00ffffff) | (QMIN(0x80, qAlpha(line[x])) << 24);
00778         }
00779     }
00780 
00781     // Scale the icon and apply effects if necessary
00782     if (iconType == KIcon::Scalable && size != img->width())
00783     {
00784         *img = img->smoothScale(size, size);
00785     }
00786     if (iconType == KIcon::Threshold && size != img->width())
00787     {
00788     if ( abs(size-img->width())>iconThreshold )
00789         *img = img->smoothScale(size, size);
00790     }
00791     if (group >= 0 && d->mpGroups[group].dblPixels)
00792     {
00793     *img = d->mpEffect.doublePixels(*img);
00794     }
00795     if (group >= 0)
00796     {
00797     *img = d->mpEffect.apply(*img, group, state);
00798     }
00799 
00800     pix.convertFromImage(*img);
00801 
00802     delete img;
00803 
00804     if (favIconOverlay)
00805     {
00806         QPixmap favIcon(name, "PNG");
00807         int x = pix.width() - favIcon.width() - 1,
00808             y = pix.height() - favIcon.height() - 1;
00809         if (pix.mask())
00810         {
00811             QBitmap mask = *pix.mask();
00812             QBitmap fmask;
00813             if (favIcon.mask())
00814         fmask = *favIcon.mask();
00815         else {
00816         // expensive, but works
00817         fmask = favIcon.createHeuristicMask();
00818         }
00819 
00820             bitBlt(&mask, x, y, &fmask,
00821                    0, 0, favIcon.width(), favIcon.height(),
00822                    favIcon.mask() ? Qt::OrROP : Qt::SetROP);
00823             pix.setMask(mask);
00824         }
00825         bitBlt(&pix, x, y, &favIcon);
00826     }
00827 
00828     QPixmapCache::insert(key, pix);
00829     return pix;
00830 }
00831 
00832 QImage *KIconLoader::loadOverlay(const QString &name, int size) const
00833 {
00834     QString key = name + '_' + QString::number(size);
00835     QImage *image = d->imgDict.find(key);
00836     if (image != 0L)
00837     return image;
00838 
00839     KIcon icon = findMatchingIcon(name, size);
00840     if (!icon.isValid())
00841     {
00842     kdDebug(264) << "Overlay " << name << "not found." << endl;
00843     return 0L;
00844     }
00845     image = new QImage(icon.path);
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     if (!entries.contains(name))
01027     {
01028         entries += name;
01029         res2 += *it;
01030     }
01031     }
01032     return res2;
01033 
01034 }
01035 
01036 QStringList KIconLoader::queryIcons(int group_or_size, KIcon::Context context) const
01037 {
01038     QStringList result;
01039     if (group_or_size >= KIcon::LastGroup)
01040     {
01041     kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
01042     return result;
01043     }
01044     int size;
01045     if (group_or_size >= 0)
01046     size = d->mpGroups[group_or_size].size;
01047     else
01048     size = -group_or_size;
01049 
01050     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
01051             themeNode = d->links.next() )
01052        themeNode->queryIcons(&result, size, context);
01053 
01054     // Eliminate duplicate entries (same icon in different directories)
01055     QString name;
01056     QStringList res2, entries;
01057     QStringList::ConstIterator it;
01058     for (it=result.begin(); it!=result.end(); ++it)
01059     {
01060     int n = (*it).findRev('/');
01061     if (n == -1)
01062         name = *it;
01063     else
01064         name = (*it).mid(n+1);
01065     if (!entries.contains(name))
01066     {
01067         entries += name;
01068         res2 += *it;
01069     }
01070     }
01071     return res2;
01072 }
01073 
01074 KIconEffect * KIconLoader::iconEffect() const
01075 {
01076     return &d->mpEffect;
01077 }
01078 
01079 bool KIconLoader::alphaBlending(KIcon::Group group) const
01080 {
01081     if (!d->mpGroups) return -1;
01082 
01083     if (group < 0 || group >= KIcon::LastGroup)
01084     {
01085     kdDebug(264) << "Illegal icon group: " << group << endl;
01086     return -1;
01087     }
01088     return d->mpGroups[group].alphaBlending;
01089 }
01090 
01091 QIconSet KIconLoader::loadIconSet(const QString& name, KIcon::Group group, int size)
01092 {
01093     return loadIconSet( name, group, size, false );
01094 }
01095 
01096 /*** class for delayed icon loading for QIconSet ***/
01097 
01098 class KIconFactory
01099     : public QIconFactory
01100     {
01101     public:
01102         KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01103             int size_P, KIconLoader* loader_P );
01104         virtual QPixmap* createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode, QIconSet::State );
01105     private:
01106         QString iconName;
01107         KIcon::Group group;
01108         int size;
01109         KIconLoader* loader;
01110     };
01111 
01112 
01113 QIconSet KIconLoader::loadIconSet( const QString& name, KIcon::Group g, int s,
01114     bool canReturnNull)
01115 {
01116     if ( !d->delayedLoading )
01117         return loadIconSetNonDelayed( name, g, s, canReturnNull );
01118 
01119     if (g < -1 || g > 6) {
01120         kdDebug() << "KIconLoader::loadIconSet " << name << " " << (int)g << " " << s << endl;
01121         qDebug("%s", kdBacktrace().latin1());
01122         abort();
01123     }
01124 
01125     if(canReturnNull)
01126     { // we need to find out if the icon actually exists
01127         QPixmap pm = loadIcon( name, g, s, KIcon::DefaultState, NULL, true );
01128         if( pm.isNull())
01129             return QIconSet();
01130 
01131         QIconSet ret( pm );
01132         ret.installIconFactory( new KIconFactory( name, g, s, this ));
01133         return ret;
01134     }
01135 
01136     QIconSet ret;
01137     ret.installIconFactory( new KIconFactory( name, g, s, this ));
01138     return ret;
01139 }
01140 
01141 QIconSet KIconLoader::loadIconSetNonDelayed( const QString& name,
01142                                              KIcon::Group g,
01143                                              int s, bool canReturnNull )
01144 {
01145     QIconSet iconset;
01146     QPixmap tmp = loadIcon(name, g, s, KIcon::ActiveState, NULL, canReturnNull);
01147     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Active );
01148     // we don't use QIconSet's resizing anyway
01149     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Active );
01150     tmp = loadIcon(name, g, s, KIcon::DisabledState, NULL, canReturnNull);
01151     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Disabled );
01152     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Disabled );
01153     tmp = loadIcon(name, g, s, KIcon::DefaultState, NULL, canReturnNull);
01154     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Normal );
01155     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Normal );
01156     return iconset;
01157 }
01158 
01159 KIconFactory::KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01160     int size_P, KIconLoader* loader_P )
01161     : iconName( iconName_P ), group( group_P ), size( size_P ), loader( loader_P )
01162 {
01163     setAutoDelete( true );
01164 }
01165 
01166 QPixmap* KIconFactory::createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode mode_P, QIconSet::State )
01167     {
01168     // QIconSet::Mode to KIcon::State conversion
01169     static const KIcon::States tbl[] = { KIcon::DefaultState, KIcon::DisabledState, KIcon::ActiveState };
01170     int state = KIcon::DefaultState;
01171     if( mode_P <= QIconSet::Active )
01172         state = tbl[ mode_P ];
01173     if( group >= 0 && state == KIcon::ActiveState )
01174     { // active and normal icon are usually the same
01175     if( loader->iconEffect()->fingerprint(group, KIcon::ActiveState )
01176             == loader->iconEffect()->fingerprint(group, KIcon::DefaultState ))
01177             return 0; // so let QIconSet simply duplicate it
01178     }
01179     // ignore passed size
01180     // ignore passed state (i.e. on/off)
01181     QPixmap pm = loader->loadIcon( iconName, group, size, state );
01182     return new QPixmap( pm );
01183     }
01184 
01185 // Easy access functions
01186 
01187 QPixmap DesktopIcon(const QString& name, int force_size, int state,
01188     KInstance *instance)
01189 {
01190     KIconLoader *loader = instance->iconLoader();
01191     return loader->loadIcon(name, KIcon::Desktop, force_size, state);
01192 }
01193 
01194 QPixmap DesktopIcon(const QString& name, KInstance *instance)
01195 {
01196     return DesktopIcon(name, 0, KIcon::DefaultState, instance);
01197 }
01198 
01199 QIconSet DesktopIconSet(const QString& name, int force_size, KInstance *instance)
01200 {
01201     KIconLoader *loader = instance->iconLoader();
01202     return loader->loadIconSet( name, KIcon::Desktop, force_size );
01203 }
01204 
01205 QPixmap BarIcon(const QString& name, int force_size, int state,
01206     KInstance *instance)
01207 {
01208     KIconLoader *loader = instance->iconLoader();
01209     return loader->loadIcon(name, KIcon::Toolbar, force_size, state);
01210 }
01211 
01212 QPixmap BarIcon(const QString& name, KInstance *instance)
01213 {
01214     return BarIcon(name, 0, KIcon::DefaultState, instance);
01215 }
01216 
01217 QIconSet BarIconSet(const QString& name, int force_size, KInstance *instance)
01218 {
01219     KIconLoader *loader = instance->iconLoader();
01220     return loader->loadIconSet( name, KIcon::Toolbar, force_size );
01221 }
01222 
01223 QPixmap SmallIcon(const QString& name, int force_size, int state,
01224     KInstance *instance)
01225 {
01226     KIconLoader *loader = instance->iconLoader();
01227     return loader->loadIcon(name, KIcon::Small, force_size, state);
01228 }
01229 
01230 QPixmap SmallIcon(const QString& name, KInstance *instance)
01231 {
01232     return SmallIcon(name, 0, KIcon::DefaultState, instance);
01233 }
01234 
01235 QIconSet SmallIconSet(const QString& name, int force_size, KInstance *instance)
01236 {
01237     KIconLoader *loader = instance->iconLoader();
01238     return loader->loadIconSet( name, KIcon::Small, force_size );
01239 }
01240 
01241 QPixmap MainBarIcon(const QString& name, int force_size, int state,
01242     KInstance *instance)
01243 {
01244     KIconLoader *loader = instance->iconLoader();
01245     return loader->loadIcon(name, KIcon::MainToolbar, force_size, state);
01246 }
01247 
01248 QPixmap MainBarIcon(const QString& name, KInstance *instance)
01249 {
01250     return MainBarIcon(name, 0, KIcon::DefaultState, instance);
01251 }
01252 
01253 QIconSet MainBarIconSet(const QString& name, int force_size, KInstance *instance)
01254 {
01255     KIconLoader *loader = instance->iconLoader();
01256     return loader->loadIconSet( name, KIcon::MainToolbar, force_size );
01257 }
01258 
01259 QPixmap UserIcon(const QString& name, int state, KInstance *instance)
01260 {
01261     KIconLoader *loader = instance->iconLoader();
01262     return loader->loadIcon(name, KIcon::User, 0, state);
01263 }
01264 
01265 QPixmap UserIcon(const QString& name, KInstance *instance)
01266 {
01267     return UserIcon(name, KIcon::DefaultState, instance);
01268 }
01269 
01270 QIconSet UserIconSet(const QString& name, KInstance *instance)
01271 {
01272     KIconLoader *loader = instance->iconLoader();
01273     return loader->loadIconSet( name, KIcon::User );
01274 }
01275 
01276 int IconSize(KIcon::Group group, KInstance *instance)
01277 {
01278     KIconLoader *loader = instance->iconLoader();
01279     return loader->currentSize(group);
01280 }
01281 
01282 QPixmap KIconLoader::unknown()
01283 {
01284     QPixmap pix;
01285     if ( QPixmapCache::find("unknown", pix) )
01286             return pix;
01287 
01288     QString path = KGlobal::iconLoader()->iconPath("unknown", KIcon::Small, true);
01289     if (path.isEmpty())
01290     {
01291     kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl;
01292     pix.resize(32,32);
01293     } else
01294     {
01295         pix.load(path);
01296         QPixmapCache::insert("unknown", pix);
01297     }
01298 
01299     return pix;
01300 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 30 05:15:53 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2003