kdecore Library API Documentation

kiconloader.cpp

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