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                     return pix;
00692 
00693                 icon = findMatchingIcon(str_unknown, size);
00694                 if (!icon.isValid())
00695                 {
00696                     kdDebug(264)
00697                         << "Warning: could not find \"Unknown\" icon for size = "
00698                         << size << endl;
00699                     return pix;
00700                 }
00701             }
00702         }
00703 
00704         if (path_store != 0L)
00705             *path_store = icon.path;
00706         if (inCache)
00707             return pix;
00708 
00709     // Use the extension as the format. Works for XPM and PNG, but not for SVG
00710     QString ext = icon.path.right(3).upper();
00711     if(ext != "SVG" && ext != "VGZ")
00712     {
00713         img = new QImage(icon.path, ext.latin1());
00714         if (img->isNull()) {
00715                 delete img;
00716         return pix;
00717             }
00718     }
00719 #ifdef HAVE_LIBART
00720     else
00721     {
00722         // Special stuff for SVG icons
00723         KSVGIconEngine *svgEngine = new KSVGIconEngine();
00724 
00725         if(svgEngine->load(size, size, icon.path))
00726         img = svgEngine->painter()->image();
00727         else
00728         img = new QImage();
00729 
00730         delete svgEngine;
00731     }
00732 #endif
00733 
00734         iconType = icon.type;
00735         iconThreshold = icon.threshold;
00736 
00737         d->lastImage = img->copy();
00738         d->lastImageKey = noEffectKey;
00739         d->lastIconType = iconType;
00740         d->lastIconThreshold = iconThreshold;
00741     }
00742     else
00743     {
00744         img = new QImage( d->lastImage.copy() );
00745         iconType = d->lastIconType;
00746         iconThreshold = d->lastIconThreshold;
00747     }
00748 
00749     // Blend in all overlays
00750     if (overlay)
00751     {
00752     QImage *ovl;
00753     KIconTheme *theme = d->mpThemeRoot->theme;
00754     if ((overlay & KIcon::LockOverlay) &&
00755         ((ovl = loadOverlay(theme->lockOverlay(), size)) != 0L))
00756         KIconEffect::overlay(*img, *ovl);
00757     if ((overlay & KIcon::LinkOverlay) &&
00758         ((ovl = loadOverlay(theme->linkOverlay(), size)) != 0L))
00759         KIconEffect::overlay(*img, *ovl);
00760     if ((overlay & KIcon::ZipOverlay) &&
00761         ((ovl = loadOverlay(theme->zipOverlay(), size)) != 0L))
00762         KIconEffect::overlay(*img, *ovl);
00763     if ((overlay & KIcon::ShareOverlay) &&
00764         ((ovl = loadOverlay(theme->shareOverlay(), size)) != 0L))
00765       KIconEffect::overlay(*img, *ovl);
00766         if (overlay & KIcon::HiddenOverlay)
00767             for (int y = 0; y < img->height(); y++)
00768             {
00769         Q_UINT32 *line = reinterpret_cast<Q_UINT32 *>(img->scanLine(y));
00770                 for (int x = 0; x < img->width();  x++)
00771                     line[x] = (line[x] & 0x00ffffff) | (QMIN(0x80, qAlpha(line[x])) << 24);
00772         }
00773     }
00774 
00775     // Scale the icon and apply effects if necessary
00776     if (iconType == KIcon::Scalable && size != img->width())
00777     {
00778         *img = img->smoothScale(size, size);
00779     }
00780     if (iconType == KIcon::Threshold && size != img->width())
00781     {
00782     if ( abs(size-img->width())>iconThreshold )
00783         *img = img->smoothScale(size, size);
00784     }
00785     if (group >= 0 && d->mpGroups[group].dblPixels)
00786     {
00787     *img = d->mpEffect.doublePixels(*img);
00788     }
00789     if (group >= 0)
00790     {
00791     *img = d->mpEffect.apply(*img, group, state);
00792     }
00793 
00794     pix.convertFromImage(*img);
00795 
00796     delete img;
00797 
00798     if (favIconOverlay)
00799     {
00800         QPixmap favIcon(name, "PNG");
00801         int x = pix.width() - favIcon.width() - 1,
00802             y = pix.height() - favIcon.height() - 1;
00803         if (pix.mask())
00804         {
00805             QBitmap mask = *pix.mask();
00806             QBitmap fmask;
00807             if (favIcon.mask())
00808         fmask = *favIcon.mask();
00809         else {
00810         // expensive, but works
00811         fmask = favIcon.createHeuristicMask();
00812         }
00813 
00814             bitBlt(&mask, x, y, &fmask,
00815                    0, 0, favIcon.width(), favIcon.height(),
00816                    favIcon.mask() ? Qt::OrROP : Qt::SetROP);
00817             pix.setMask(mask);
00818         }
00819         bitBlt(&pix, x, y, &favIcon);
00820     }
00821 
00822     QPixmapCache::insert(key, pix);
00823     return pix;
00824 }
00825 
00826 QImage *KIconLoader::loadOverlay(const QString &name, int size) const
00827 {
00828     QString key = name + '_' + QString::number(size);
00829     QImage *image = d->imgDict.find(key);
00830     if (image != 0L)
00831     return image;
00832 
00833     KIcon icon = findMatchingIcon(name, size);
00834     if (!icon.isValid())
00835     {
00836     kdDebug(264) << "Overlay " << name << "not found." << endl;
00837     return 0L;
00838     }
00839     image = new QImage(icon.path);
00840     d->imgDict.insert(key, image);
00841     return image;
00842 }
00843 
00844 
00845 
00846 QMovie KIconLoader::loadMovie(const QString& name, KIcon::Group group, int size) const
00847 {
00848     QString file = moviePath( name, group, size );
00849     if (file.isEmpty())
00850     return QMovie();
00851     int dirLen = file.findRev('/');
00852     QString icon = iconPath(name, size ? -size : group, true);
00853     if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
00854     return QMovie();
00855     return QMovie(file);
00856 }
00857 
00858 QString KIconLoader::moviePath(const QString& name, KIcon::Group group, int size) const
00859 {
00860     if (!d->mpGroups) return QString::null;
00861 
00862     if ( (group < -1 || group >= KIcon::LastGroup) && group != KIcon::User )
00863     {
00864     kdDebug(264) << "Illegal icon group: " << group << endl;
00865     group = KIcon::Desktop;
00866     }
00867     if (size == 0 && group < 0)
00868     {
00869     kdDebug(264) << "Neither size nor group specified!" << endl;
00870     group = KIcon::Desktop;
00871     }
00872 
00873     QString file = name + ".mng";
00874     if (group == KIcon::User)
00875     {
00876     file = d->mpDirs->findResource("appicon", file);
00877     }
00878     else
00879     {
00880     if (size == 0)
00881         size = d->mpGroups[group].size;
00882 
00883         KIcon icon;
00884     
00885     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00886         themeNode = d->links.next() )
00887     {
00888         icon = themeNode->theme->iconPath(file, size, KIcon::MatchExact);
00889         if (icon.isValid())
00890         break;
00891     }
00892     
00893     if ( !icon.isValid() )
00894     {
00895         for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00896             themeNode = d->links.next() )
00897         {
00898         icon = themeNode->theme->iconPath(file, size, KIcon::MatchBest);
00899         if (icon.isValid())
00900             break;
00901         }
00902     }
00903     
00904     file = icon.isValid() ? icon.path : QString::null;
00905     }
00906     return file;
00907 }
00908 
00909 
00910 QStringList KIconLoader::loadAnimated(const QString& name, KIcon::Group group, int size) const
00911 {
00912     QStringList lst;
00913 
00914     if (!d->mpGroups) return lst;
00915 
00916     if ((group < -1) || (group >= KIcon::LastGroup))
00917     {
00918     kdDebug(264) << "Illegal icon group: " << group << endl;
00919     group = KIcon::Desktop;
00920     }
00921     if ((size == 0) && (group < 0))
00922     {
00923     kdDebug(264) << "Neither size nor group specified!" << endl;
00924     group = KIcon::Desktop;
00925     }
00926 
00927     QString file = name + "/0001";
00928     if (group == KIcon::User)
00929     {
00930     file = d->mpDirs->findResource("appicon", file + ".png");
00931     } else
00932     {
00933     if (size == 0)
00934         size = d->mpGroups[group].size;
00935     KIcon icon = findMatchingIcon(file, size);
00936     file = icon.isValid() ? icon.path : QString::null;
00937 
00938     }
00939     if (file.isEmpty())
00940     return lst;
00941 
00942     QString path = file.left(file.length()-8);
00943     DIR* dp = opendir( QFile::encodeName(path) );
00944     if(!dp)
00945         return lst;
00946 
00947     struct dirent* ep;
00948     while( ( ep = readdir( dp ) ) != 0L )
00949     {
00950         QString fn(QFile::decodeName(ep->d_name));
00951         if(!(fn.left(4)).toUInt())
00952             continue;
00953 
00954         lst += path + fn;
00955     }
00956     closedir ( dp );
00957     lst.sort();
00958     return lst;
00959 }
00960 
00961 KIconTheme *KIconLoader::theme() const
00962 {
00963     if (d->mpThemeRoot) return d->mpThemeRoot->theme;
00964     return 0L;
00965 }
00966 
00967 int KIconLoader::currentSize(KIcon::Group group) const
00968 {
00969     if (!d->mpGroups) return -1;
00970 
00971     if (group < 0 || group >= KIcon::LastGroup)
00972     {
00973     kdDebug(264) << "Illegal icon group: " << group << endl;
00974     return -1;
00975     }
00976     return d->mpGroups[group].size;
00977 }
00978 
00979 QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
00980 {
00981   QDir dir(iconsDir);
00982   QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files);
00983   QStringList result;
00984   QStringList::ConstIterator it;
00985   for (it=lst.begin(); it!=lst.end(); ++it)
00986     result += iconsDir + "/" + *it;
00987   return result;
00988 }
00989 
00990 QStringList KIconLoader::queryIconsByContext(int group_or_size,
00991                         KIcon::Context context) const
00992 {
00993     QStringList result;
00994     if (group_or_size >= KIcon::LastGroup)
00995     {
00996     kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
00997     return result;
00998     }
00999     int size;
01000     if (group_or_size >= 0)
01001     size = d->mpGroups[group_or_size].size;
01002     else
01003     size = -group_or_size;
01004 
01005     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
01006             themeNode = d->links.next() )
01007        themeNode->queryIconsByContext(&result, size, context);
01008 
01009     // Eliminate duplicate entries (same icon in different directories)
01010     QString name;
01011     QStringList res2, entries;
01012     QStringList::ConstIterator it;
01013     for (it=result.begin(); it!=result.end(); ++it)
01014     {
01015     int n = (*it).findRev('/');
01016     if (n == -1)
01017         name = *it;
01018     else
01019         name = (*it).mid(n+1);
01020     if (!entries.contains(name))
01021     {
01022         entries += name;
01023         res2 += *it;
01024     }
01025     }
01026     return res2;
01027 
01028 }
01029 
01030 QStringList KIconLoader::queryIcons(int group_or_size, KIcon::Context context) const
01031 {
01032     QStringList result;
01033     if (group_or_size >= KIcon::LastGroup)
01034     {
01035     kdDebug(264) << "Illegal icon group: " << group_or_size << endl;
01036     return result;
01037     }
01038     int size;
01039     if (group_or_size >= 0)
01040     size = d->mpGroups[group_or_size].size;
01041     else
01042     size = -group_or_size;
01043 
01044     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
01045             themeNode = d->links.next() )
01046        themeNode->queryIcons(&result, size, context);
01047 
01048     // Eliminate duplicate entries (same icon in different directories)
01049     QString name;
01050     QStringList res2, entries;
01051     QStringList::ConstIterator it;
01052     for (it=result.begin(); it!=result.end(); ++it)
01053     {
01054     int n = (*it).findRev('/');
01055     if (n == -1)
01056         name = *it;
01057     else
01058         name = (*it).mid(n+1);
01059     if (!entries.contains(name))
01060     {
01061         entries += name;
01062         res2 += *it;
01063     }
01064     }
01065     return res2;
01066 }
01067 
01068 KIconEffect * KIconLoader::iconEffect() const
01069 {
01070     return &d->mpEffect;
01071 }
01072 
01073 bool KIconLoader::alphaBlending(KIcon::Group group) const
01074 {
01075     if (!d->mpGroups) return -1;
01076 
01077     if (group < 0 || group >= KIcon::LastGroup)
01078     {
01079     kdDebug(264) << "Illegal icon group: " << group << endl;
01080     return -1;
01081     }
01082     return d->mpGroups[group].alphaBlending;
01083 }
01084 
01085 QIconSet KIconLoader::loadIconSet(const QString& name, KIcon::Group group, int size)
01086 {
01087     return loadIconSet( name, group, size, false );
01088 }
01089 
01090 /*** class for delayed icon loading for QIconSet ***/
01091 
01092 class KIconFactory
01093     : public QIconFactory
01094     {
01095     public:
01096         KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01097             int size_P, KIconLoader* loader_P );
01098         virtual QPixmap* createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode, QIconSet::State );
01099     private:
01100         QString iconName;
01101         KIcon::Group group;
01102         int size;
01103         KIconLoader* loader;
01104     };
01105 
01106 
01107 QIconSet KIconLoader::loadIconSet( const QString& name, KIcon::Group g, int s,
01108     bool canReturnNull)
01109 {
01110     if ( !d->delayedLoading )
01111         return loadIconSetNonDelayed( name, g, s, canReturnNull );
01112 
01113     if (g < -1 || g > 6) {
01114         kdDebug() << "KIconLoader::loadIconSet " << name << " " << (int)g << " " << s << endl;
01115         qDebug("%s", kdBacktrace().latin1());
01116         abort();
01117     }
01118 
01119     if(canReturnNull)
01120     { // we need to find out if the icon actually exists
01121         QPixmap pm = loadIcon( name, g, s, KIcon::DefaultState, NULL, true );
01122         if( pm.isNull())
01123             return QIconSet();
01124 
01125         QIconSet ret( pm );
01126         ret.installIconFactory( new KIconFactory( name, g, s, this ));
01127         return ret;
01128     }
01129 
01130     QIconSet ret;
01131     ret.installIconFactory( new KIconFactory( name, g, s, this ));
01132     return ret;
01133 }
01134 
01135 QIconSet KIconLoader::loadIconSetNonDelayed( const QString& name,
01136                                              KIcon::Group g,
01137                                              int s, bool canReturnNull )
01138 {
01139     QIconSet iconset;
01140     QPixmap tmp = loadIcon(name, g, s, KIcon::ActiveState, NULL, canReturnNull);
01141     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Active );
01142     // we don't use QIconSet's resizing anyway
01143     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Active );
01144     tmp = loadIcon(name, g, s, KIcon::DisabledState, NULL, canReturnNull);
01145     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Disabled );
01146     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Disabled );
01147     tmp = loadIcon(name, g, s, KIcon::DefaultState, NULL, canReturnNull);
01148     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Normal );
01149     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Normal );
01150     return iconset;
01151 }
01152 
01153 KIconFactory::KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01154     int size_P, KIconLoader* loader_P )
01155     : iconName( iconName_P ), group( group_P ), size( size_P ), loader( loader_P )
01156 {
01157     setAutoDelete( true );
01158 }
01159 
01160 QPixmap* KIconFactory::createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode mode_P, QIconSet::State )
01161     {
01162     // QIconSet::Mode to KIcon::State conversion
01163     static const KIcon::States tbl[] = { KIcon::DefaultState, KIcon::DisabledState, KIcon::ActiveState };
01164     int state = KIcon::DefaultState;
01165     if( mode_P <= QIconSet::Active )
01166         state = tbl[ mode_P ];
01167     if( group >= 0 && state == KIcon::ActiveState )
01168     { // active and normal icon are usually the same
01169     if( loader->iconEffect()->fingerprint(group, KIcon::ActiveState )
01170             == loader->iconEffect()->fingerprint(group, KIcon::DefaultState ))
01171             return 0; // so let QIconSet simply duplicate it
01172     }
01173     // ignore passed size
01174     // ignore passed state (i.e. on/off)
01175     QPixmap pm = loader->loadIcon( iconName, group, size, state );
01176     return new QPixmap( pm );
01177     }
01178 
01179 // Easy access functions
01180 
01181 QPixmap DesktopIcon(const QString& name, int force_size, int state,
01182     KInstance *instance)
01183 {
01184     KIconLoader *loader = instance->iconLoader();
01185     return loader->loadIcon(name, KIcon::Desktop, force_size, state);
01186 }
01187 
01188 QPixmap DesktopIcon(const QString& name, KInstance *instance)
01189 {
01190     return DesktopIcon(name, 0, KIcon::DefaultState, instance);
01191 }
01192 
01193 QIconSet DesktopIconSet(const QString& name, int force_size, KInstance *instance)
01194 {
01195     KIconLoader *loader = instance->iconLoader();
01196     return loader->loadIconSet( name, KIcon::Desktop, force_size );
01197 }
01198 
01199 QPixmap BarIcon(const QString& name, int force_size, int state,
01200     KInstance *instance)
01201 {
01202     KIconLoader *loader = instance->iconLoader();
01203     return loader->loadIcon(name, KIcon::Toolbar, force_size, state);
01204 }
01205 
01206 QPixmap BarIcon(const QString& name, KInstance *instance)
01207 {
01208     return BarIcon(name, 0, KIcon::DefaultState, instance);
01209 }
01210 
01211 QIconSet BarIconSet(const QString& name, int force_size, KInstance *instance)
01212 {
01213     KIconLoader *loader = instance->iconLoader();
01214     return loader->loadIconSet( name, KIcon::Toolbar, force_size );
01215 }
01216 
01217 QPixmap SmallIcon(const QString& name, int force_size, int state,
01218     KInstance *instance)
01219 {
01220     KIconLoader *loader = instance->iconLoader();
01221     return loader->loadIcon(name, KIcon::Small, force_size, state);
01222 }
01223 
01224 QPixmap SmallIcon(const QString& name, KInstance *instance)
01225 {
01226     return SmallIcon(name, 0, KIcon::DefaultState, instance);
01227 }
01228 
01229 QIconSet SmallIconSet(const QString& name, int force_size, KInstance *instance)
01230 {
01231     KIconLoader *loader = instance->iconLoader();
01232     return loader->loadIconSet( name, KIcon::Small, force_size );
01233 }
01234 
01235 QPixmap MainBarIcon(const QString& name, int force_size, int state,
01236     KInstance *instance)
01237 {
01238     KIconLoader *loader = instance->iconLoader();
01239     return loader->loadIcon(name, KIcon::MainToolbar, force_size, state);
01240 }
01241 
01242 QPixmap MainBarIcon(const QString& name, KInstance *instance)
01243 {
01244     return MainBarIcon(name, 0, KIcon::DefaultState, instance);
01245 }
01246 
01247 QIconSet MainBarIconSet(const QString& name, int force_size, KInstance *instance)
01248 {
01249     KIconLoader *loader = instance->iconLoader();
01250     return loader->loadIconSet( name, KIcon::MainToolbar, force_size );
01251 }
01252 
01253 QPixmap UserIcon(const QString& name, int state, KInstance *instance)
01254 {
01255     KIconLoader *loader = instance->iconLoader();
01256     return loader->loadIcon(name, KIcon::User, 0, state);
01257 }
01258 
01259 QPixmap UserIcon(const QString& name, KInstance *instance)
01260 {
01261     return UserIcon(name, KIcon::DefaultState, instance);
01262 }
01263 
01264 QIconSet UserIconSet(const QString& name, KInstance *instance)
01265 {
01266     KIconLoader *loader = instance->iconLoader();
01267     return loader->loadIconSet( name, KIcon::User );
01268 }
01269 
01270 int IconSize(KIcon::Group group, KInstance *instance)
01271 {
01272     KIconLoader *loader = instance->iconLoader();
01273     return loader->currentSize(group);
01274 }
01275 
01276 QPixmap KIconLoader::unknown()
01277 {
01278     QPixmap pix;
01279     if ( QPixmapCache::find("unknown", pix) )
01280             return pix;
01281 
01282     QString path = KGlobal::iconLoader()->iconPath("unknown", KIcon::Small, true);
01283     if (path.isEmpty())
01284     {
01285     kdDebug(264) << "Warning: Cannot find \"unknown\" icon." << endl;
01286     pix.resize(32,32);
01287     } else
01288     {
01289         pix.load(path);
01290         QPixmapCache::insert("unknown", pix);
01291     }
01292 
01293     return pix;
01294 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun May 16 22:01:19 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003