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     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00434     themeNode = d->links.next() )
00435     {
00436     for (int i = 0 ; i < count ; i++)
00437     {
00438         icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchExact);
00439         if (icon.isValid())
00440         return icon;
00441     }
00442 
00443     }
00444 
00445     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00446     themeNode = d->links.next() )
00447     {
00448     for (int i = 0 ; i < count ; i++)
00449     {
00450         icon = themeNode->theme->iconPath(name + *ext[i], size, KIcon::MatchBest);
00451         if (icon.isValid())
00452         return icon;
00453     }
00454 
00455     }
00456 
00457     return icon;
00458 }
00459 
00460 inline QString KIconLoader::unknownIconPath( int size ) const
00461 {
00462     static const QString &str_unknown = KGlobal::staticQString("unknown");
00463 
00464     KIcon icon = findMatchingIcon(str_unknown, size);
00465     if (!icon.isValid())
00466     {
00467         kdDebug(264) << "Warning: could not find \"Unknown\" icon for size = "
00468                      << size << "\n";
00469         return QString::null;
00470     }
00471     return icon.path;
00472 }
00473 
00474 // Finds the absolute path to an icon.
00475 
00476 QString KIconLoader::iconPath(const QString& _name, int group_or_size,
00477                   bool canReturnNull) const
00478 {
00479     if (d->mpThemeRoot == 0L)
00480     return QString::null;
00481 
00482     if (_name.at(0) == '/')
00483     return _name;
00484 
00485     QString name = removeIconExtension( _name );
00486 
00487     QString path;
00488     if (group_or_size == KIcon::User)
00489     {
00490     static const QString &png_ext = KGlobal::staticQString(".png");
00491     static const QString &xpm_ext = KGlobal::staticQString(".xpm");
00492     path = d->mpDirs->findResource("appicon", name + png_ext);
00493 
00494 #ifdef HAVE_LIBART
00495     static const QString &svgz_ext = KGlobal::staticQString(".svgz");
00496     static const QString &svg_ext = KGlobal::staticQString(".svg");
00497     if (path.isEmpty())
00498         path = d->mpDirs->findResource("appicon", name + svgz_ext);
00499     if (path.isEmpty())
00500        path = d->mpDirs->findResource("appicon", name + svg_ext);
00501 #endif
00502     if (path.isEmpty())
00503          path = d->mpDirs->findResource("appicon", name + xpm_ext);
00504     return path;
00505     }
00506     
00507     if (group_or_size >= KIcon::LastGroup)
00508     {
00509     kdDebug(264) << "Illegal icon group: " << group_or_size << "\n";
00510     return path;
00511     }
00512 
00513     int size;
00514     if (group_or_size >= 0)
00515     size = d->mpGroups[group_or_size].size;
00516     else
00517     size = -group_or_size;
00518 
00519     if (_name.isEmpty()) {
00520         if (canReturnNull)
00521             return QString::null;
00522         else
00523             return unknownIconPath(size);
00524     }
00525 
00526     KIcon icon = findMatchingIcon(name, size);
00527 
00528     if (!icon.isValid())
00529     {
00530     // Try "User" group too.
00531     path = iconPath(name, KIcon::User, true);
00532     if (!path.isEmpty() || canReturnNull)
00533         return path;
00534     
00535     if (canReturnNull)
00536         return QString::null;
00537         else
00538             return unknownIconPath(size);
00539     }
00540     return icon.path;
00541 }
00542 
00543 QPixmap KIconLoader::loadIcon(const QString& _name, KIcon::Group group, int size,
00544                               int state, QString *path_store, bool canReturnNull) const
00545 {
00546     QString name = _name;
00547     QPixmap pix;
00548     QString key;
00549     bool absolutePath=false, favIconOverlay=false;
00550 
00551     if (d->mpThemeRoot == 0L)
00552     return pix;
00553 
00554     // Special case for absolute path icons.
00555     if (name.startsWith("favicons/"))
00556     {
00557        favIconOverlay = true;
00558        name = locateLocal("cache", name+".png");
00559     }
00560     if (name.at(0) == '/') absolutePath=true;
00561 
00562     static const QString &str_unknown = KGlobal::staticQString("unknown");
00563 
00564     // Special case for "User" icons.
00565     if (group == KIcon::User)
00566     {
00567     key = "$kicou_";
00568     key += name;
00569     bool inCache = QPixmapCache::find(key, pix);
00570     if (inCache && (path_store == 0L))
00571         return pix;
00572 
00573     QString path = (absolutePath) ? name :
00574             iconPath(name, KIcon::User, canReturnNull);
00575     if (path.isEmpty())
00576     {
00577         if (canReturnNull)
00578         return pix;
00579         // We don't know the desired size: use small
00580         path = iconPath(str_unknown, KIcon::Small, true);
00581         if (path.isEmpty())
00582         {
00583         kdDebug(264) << "Warning: Cannot find \"unknown\" icon.\n";
00584         return pix;
00585         }
00586     }
00587 
00588     if (path_store != 0L)
00589         *path_store = path;
00590     if (inCache)
00591         return pix;
00592     pix.load(path);
00593     QPixmapCache::insert(key, pix);
00594     return pix;
00595     }
00596 
00597     // Regular case: Check parameters
00598 
00599     if ((group < -1) || (group >= KIcon::LastGroup))
00600     {
00601     kdDebug(264) << "Illegal icon group: " << group << "\n";
00602     group = KIcon::Desktop;
00603     }
00604 
00605     int overlay = (state & KIcon::OverlayMask);
00606     state &= ~KIcon::OverlayMask;
00607     if ((state < 0) || (state >= KIcon::LastState))
00608     {
00609     kdDebug(264) << "Illegal icon state: " << state << "\n";
00610     state = KIcon::DefaultState;
00611     }
00612 
00613     if ((size == 0) && (group < 0))
00614     {
00615     kdDebug(264) << "Neither size nor group specified!\n";
00616     group = KIcon::Desktop;
00617     }
00618 
00619     if (!absolutePath)
00620     {
00621         if (!canReturnNull && name.isEmpty())
00622             name = str_unknown;
00623         else
00624         name = removeIconExtension(name);
00625     }
00626 
00627     // If size == 0, use default size for the specified group.
00628     if (size == 0)
00629     {
00630     size = d->mpGroups[group].size;
00631     }
00632     favIconOverlay = favIconOverlay && (size > 22);
00633 
00634     // Generate a unique cache key for the icon.
00635 
00636     key = "$kico_";
00637     key += name; key += '_';
00638     key += QString::number(size); key += '_';
00639 
00640     QString overlayStr = QString::number( overlay );
00641 
00642     QString noEffectKey = key + '_' + overlayStr;
00643 
00644     if (group >= 0)
00645     {
00646     key += d->mpEffect.fingerprint(group, state);
00647     if (d->mpGroups[group].dblPixels)
00648         key += QString::fromLatin1(":dblsize");
00649     } else
00650     key += QString::fromLatin1("noeffect");
00651     key += '_';
00652     key += overlayStr;
00653 
00654     // Is the icon in the cache?
00655     bool inCache = QPixmapCache::find(key, pix);
00656     if (inCache && (path_store == 0L))
00657     return pix;
00658 
00659     QImage *img = 0;
00660     int iconType;
00661     int iconThreshold;
00662 
00663     if ( ( path_store != 0L ) ||
00664          noEffectKey != d->lastImageKey )
00665     {
00666         // No? load it.
00667         KIcon icon;
00668         if (absolutePath && !favIconOverlay)
00669         {
00670             icon.context=KIcon::Any;
00671             icon.type=KIcon::Scalable;
00672             icon.path=name;
00673         }
00674         else
00675         {
00676             if (!name.isEmpty())
00677                 icon = findMatchingIcon(favIconOverlay ? QString("www") : name, size);
00678 
00679             if (!icon.isValid())
00680             {
00681                 // Try "User" icon too. Some apps expect this.
00682                 if (!name.isEmpty())
00683                     pix = loadIcon(name, KIcon::User, size, state, path_store, true);
00684                 if (!pix.isNull() || canReturnNull) {
00685             if (pix.width() > size || pix.height() > size) {
00686             QImage tmp = pix.convertToImage();
00687             tmp = tmp.smoothScale(size, size);
00688             pix.convertFromImage(tmp);
00689             }
00690                     return pix;
00691         }
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 << "\n";
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 ((iconType == KIcon::Fixed) && (size != img->width()))
00786     {
00787         *img = img->smoothScale(size, size);
00788     }
00789     if ((group >= 0) && d->mpGroups[group].dblPixels)
00790     {
00791     *img = d->mpEffect.doublePixels(*img);
00792     }
00793     if (group >= 0)
00794     {
00795     *img = d->mpEffect.apply(*img, group, state);
00796     }
00797 
00798     pix.convertFromImage(*img);
00799 
00800     delete img;
00801 
00802     if (favIconOverlay)
00803     {
00804         QPixmap favIcon(name, "PNG");
00805         int x = pix.width() - favIcon.width() - 1,
00806             y = pix.height() - favIcon.height() - 1;
00807         if (pix.mask())
00808         {
00809             QBitmap mask = *pix.mask();
00810             QBitmap fmask;
00811             if (favIcon.mask())
00812         fmask = *favIcon.mask();
00813         else {
00814         // expensive, but works
00815         fmask = favIcon.createHeuristicMask();
00816         }
00817         
00818             bitBlt(&mask, x, y, &fmask,
00819                    0, 0, favIcon.width(), favIcon.height(),
00820                    favIcon.mask() ? Qt::OrROP : Qt::SetROP);
00821             pix.setMask(mask);
00822         }
00823         bitBlt(&pix, x, y, &favIcon);
00824     }
00825 
00826     QPixmapCache::insert(key, pix);
00827     return pix;
00828 }
00829 
00830 QImage *KIconLoader::loadOverlay(const QString &name, int size) const
00831 {
00832     QString key = name + '_' + QString::number(size);
00833     QImage *image = d->imgDict.find(key);
00834     if (image != 0L)
00835     return image;
00836 
00837     KIcon icon = findMatchingIcon(name, size);
00838     if (!icon.isValid())
00839     {
00840     kdDebug(264) << "Overlay " << name << "not found.\n";
00841     return 0L;
00842     }
00843     image = new QImage(icon.path);
00844     d->imgDict.insert(key, image);
00845     return image;
00846 }
00847 
00848 
00849 
00850 QMovie KIconLoader::loadMovie(const QString& name, KIcon::Group group, int size) const
00851 {
00852     QString file = moviePath( name, group, size );
00853     if (file.isEmpty())
00854     return QMovie();
00855     int dirLen = file.findRev('/');
00856     QString icon = iconPath(name, size ? -size : group, true);
00857     if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen))
00858     return QMovie();
00859     return QMovie(file);
00860 }
00861 
00862 QString KIconLoader::moviePath(const QString& name, KIcon::Group group, int size) const
00863 {
00864     if (!d->mpGroups) return QString::null;
00865 
00866     if ( ((group < -1) || (group >= KIcon::LastGroup)) && (group != KIcon::User) )
00867     {
00868     kdDebug(264) << "Illegal icon group: " << group << "\n";
00869     group = KIcon::Desktop;
00870     }
00871     if ((size == 0) && (group < 0))
00872     {
00873     kdDebug(264) << "Neither size nor group specified!\n";
00874     group = KIcon::Desktop;
00875     }
00876 
00877     QString file = name + ".mng";
00878     if (group == KIcon::User)
00879     {
00880     file = d->mpDirs->findResource("appicon", file);
00881     }
00882     else
00883     {
00884     if (size == 0)
00885         size = d->mpGroups[group].size;
00886 
00887         KIcon icon;
00888         icon = d->mpThemeRoot->findIcon(file, size, KIcon::MatchExact);
00889         if (!icon.isValid())
00890         {
00891            icon = d->mpThemeRoot->findIcon(file, size, KIcon::MatchBest);
00892         }
00893     file = icon.isValid() ? icon.path : QString::null;
00894 
00895     }
00896     return file;
00897 }
00898 
00899 
00900 QStringList KIconLoader::loadAnimated(const QString& name, KIcon::Group group, int size) const
00901 {
00902     QStringList lst;
00903 
00904     if (!d->mpGroups) return lst;
00905 
00906     if ((group < -1) || (group >= KIcon::LastGroup))
00907     {
00908     kdDebug(264) << "Illegal icon group: " << group << "\n";
00909     group = KIcon::Desktop;
00910     }
00911     if ((size == 0) && (group < 0))
00912     {
00913     kdDebug(264) << "Neither size nor group specified!\n";
00914     group = KIcon::Desktop;
00915     }
00916 
00917     QString file = name + "/0001";
00918     if (group == KIcon::User)
00919     {
00920     file = d->mpDirs->findResource("appicon", file + ".png");
00921     } else
00922     {
00923     if (size == 0)
00924         size = d->mpGroups[group].size;
00925     KIcon icon = findMatchingIcon(file, size);
00926     file = icon.isValid() ? icon.path : QString::null;
00927 
00928     }
00929     if (file.isEmpty())
00930     return lst;
00931 
00932     QString path = file.left(file.length()-8);
00933     DIR* dp = opendir( QFile::encodeName(path) );
00934     if(!dp)
00935         return lst;
00936 
00937     struct dirent* ep;
00938     while( ( ep = readdir( dp ) ) != 0L )
00939     {
00940         QString fn(QFile::decodeName(ep->d_name));
00941         if(!(fn.left(4)).toUInt())
00942             continue;
00943 
00944         lst += path + fn;
00945     }
00946     closedir ( dp );
00947     lst.sort();
00948     return lst;
00949 }
00950 
00951 KIconTheme *KIconLoader::theme() const
00952 {
00953     if (d->mpThemeRoot) return d->mpThemeRoot->theme;
00954     return 0L;
00955 }
00956 
00957 int KIconLoader::currentSize(KIcon::Group group) const
00958 {
00959     if (!d->mpGroups) return -1;
00960 
00961     if ((group < 0) || (group >= KIcon::LastGroup))
00962     {
00963     kdDebug(264) << "Illegal icon group: " << group << "\n";
00964     return -1;
00965     }
00966     return d->mpGroups[group].size;
00967 }
00968 
00969 QStringList KIconLoader::queryIconsByDir( const QString& iconsDir ) const
00970 {
00971   QDir dir(iconsDir);
00972   QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files);
00973   QStringList result;
00974   QStringList::ConstIterator it;
00975   for (it=lst.begin(); it!=lst.end(); it++)
00976     result += iconsDir + "/" + *it;
00977   return result;
00978 }
00979 
00980 QStringList KIconLoader::queryIconsByContext(int group_or_size,
00981                         KIcon::Context context) const
00982 {
00983     QStringList result;
00984     if (group_or_size >= KIcon::LastGroup)
00985     {
00986     kdDebug(264) << "Illegal icon group: " << group_or_size << "\n";
00987     return result;
00988     }
00989     int size;
00990     if (group_or_size >= 0)
00991     size = d->mpGroups[group_or_size].size;
00992     else
00993     size = -group_or_size;
00994 
00995     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
00996             themeNode = d->links.next() )
00997        themeNode->queryIconsByContext(&result, size, context);
00998 
00999     // Eliminate duplicate entries (same icon in different directories)
01000     QString name;
01001     QStringList res2, entries;
01002     QStringList::ConstIterator it;
01003     for (it=result.begin(); it!=result.end(); it++)
01004     {
01005     int n = (*it).findRev('/');
01006     if (n == -1)
01007         name = *it;
01008     else
01009         name = (*it).mid(n+1);
01010     if (!entries.contains(name))
01011     {
01012         entries += name;
01013         res2 += *it;
01014     }
01015     }
01016     return res2;
01017 
01018 }
01019 
01020 QStringList KIconLoader::queryIcons(int group_or_size, KIcon::Context context) const
01021 {
01022     QStringList result;
01023     if (group_or_size >= KIcon::LastGroup)
01024     {
01025     kdDebug(264) << "Illegal icon group: " << group_or_size << "\n";
01026     return result;
01027     }
01028     int size;
01029     if (group_or_size >= 0)
01030     size = d->mpGroups[group_or_size].size;
01031     else
01032     size = -group_or_size;
01033 
01034     for ( KIconThemeNode *themeNode = d->links.first() ; themeNode ;
01035             themeNode = d->links.next() )
01036        themeNode->queryIcons(&result, size, context);
01037 
01038     // Eliminate duplicate entries (same icon in different directories)
01039     QString name;
01040     QStringList res2, entries;
01041     QStringList::ConstIterator it;
01042     for (it=result.begin(); it!=result.end(); it++)
01043     {
01044     int n = (*it).findRev('/');
01045     if (n == -1)
01046         name = *it;
01047     else
01048         name = (*it).mid(n+1);
01049     if (!entries.contains(name))
01050     {
01051         entries += name;
01052         res2 += *it;
01053     }
01054     }
01055     return res2;
01056 }
01057 
01058 KIconEffect * KIconLoader::iconEffect() const
01059 {
01060     return &d->mpEffect;
01061 }
01062 
01063 bool KIconLoader::alphaBlending(KIcon::Group group) const
01064 {
01065     if (!d->mpGroups) return -1;
01066 
01067     if ((group < 0) || (group >= KIcon::LastGroup))
01068     {
01069     kdDebug(264) << "Illegal icon group: " << group << "\n";
01070     return -1;
01071     }
01072     return d->mpGroups[group].alphaBlending;
01073 }
01074 
01075 QIconSet KIconLoader::loadIconSet(const QString& name, KIcon::Group group, int size)
01076 {
01077     return loadIconSet( name, group, size, false );
01078 }
01079 
01080 /*** class for delayed icon loading for QIconSet ***/
01081 
01082 class KIconFactory
01083     : public QIconFactory
01084     {
01085     public:
01086         KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01087             int size_P, KIconLoader* loader_P );
01088         virtual QPixmap* createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode, QIconSet::State );
01089     private:
01090         QString iconName;
01091         KIcon::Group group;
01092         int size;
01093         KIconLoader* loader;
01094     };
01095 
01096 
01097 QIconSet KIconLoader::loadIconSet( const QString& name, KIcon::Group group, int size,
01098     bool canReturnNull)
01099 {
01100     if ( !d->delayedLoading )
01101         return loadIconSetNonDelayed( name, group, size, canReturnNull );
01102 
01103     if(canReturnNull)
01104     { // we need to find out if the icon actually exists
01105         QPixmap pm = loadIcon( name, group, size, KIcon::DefaultState, NULL, true );
01106         if( pm.isNull())
01107             return QIconSet();
01108 
01109         QIconSet ret( pm );
01110         ret.installIconFactory( new KIconFactory( name, group, size, this ));
01111         return ret;
01112     }
01113     
01114     QIconSet ret;
01115     ret.installIconFactory( new KIconFactory( name, group, size, this ));
01116     return ret;
01117 }
01118 
01119 QIconSet KIconLoader::loadIconSetNonDelayed( const QString& name, 
01120                                              KIcon::Group group,
01121                                              int size, bool canReturnNull )
01122 {
01123     QIconSet iconset;
01124     QPixmap tmp = loadIcon(name, group, size, KIcon::ActiveState, NULL, canReturnNull);
01125     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Active );
01126     // we don't use QIconSet's resizing anyway
01127     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Active );
01128     tmp = loadIcon(name, group, size, KIcon::DisabledState, NULL, canReturnNull);
01129     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Disabled );
01130     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Disabled );
01131     tmp = loadIcon(name, group, size, KIcon::DefaultState, NULL, canReturnNull);
01132     iconset.setPixmap( tmp, QIconSet::Small, QIconSet::Normal );
01133     iconset.setPixmap( tmp, QIconSet::Large, QIconSet::Normal );
01134     return iconset;
01135 }
01136 
01137 KIconFactory::KIconFactory( const QString& iconName_P, KIcon::Group group_P,
01138     int size_P, KIconLoader* loader_P )
01139     : iconName( iconName_P ), group( group_P ), size( size_P ), loader( loader_P )
01140 {
01141     setAutoDelete( true );
01142 }
01143 
01144 QPixmap* KIconFactory::createPixmap( const QIconSet&, QIconSet::Size, QIconSet::Mode mode_P, QIconSet::State )
01145     {
01146     // QIconSet::Mode to KIcon::State conversion
01147     static const KIcon::States tbl[] = { KIcon::DefaultState, KIcon::DisabledState, KIcon::ActiveState };
01148     int state = KIcon::DefaultState;
01149     if( mode_P <= QIconSet::Active )
01150         state = tbl[ mode_P ];
01151     if( group >= 0 && state == KIcon::ActiveState )
01152     { // active and normal icon are usually the same
01153     if( loader->iconEffect()->fingerprint(group, KIcon::ActiveState )
01154             == loader->iconEffect()->fingerprint(group, KIcon::DefaultState ))
01155             return NULL; // so let QIconSet simply duplicate it
01156     }
01157     // ignore passed size
01158     // ignore passed state (i.e. on/off)
01159     QPixmap pm = loader->loadIcon( iconName, group, size, state );
01160     return new QPixmap( pm );
01161     }
01162 
01163 // Easy access functions
01164 
01165 QPixmap DesktopIcon(const QString& name, int force_size, int state,
01166     KInstance *instance)
01167 {
01168     KIconLoader *loader = instance->iconLoader();
01169     return loader->loadIcon(name, KIcon::Desktop, force_size, state);
01170 }
01171 
01172 QPixmap DesktopIcon(const QString& name, KInstance *instance)
01173 {
01174     return DesktopIcon(name, 0, KIcon::DefaultState, instance);
01175 }
01176 
01177 QIconSet DesktopIconSet(const QString& name, int force_size, KInstance *instance)
01178 {
01179     KIconLoader *loader = instance->iconLoader();
01180     return loader->loadIconSet( name, KIcon::Desktop, force_size );
01181 }
01182 
01183 QPixmap BarIcon(const QString& name, int force_size, int state,
01184     KInstance *instance)
01185 {
01186     KIconLoader *loader = instance->iconLoader();
01187     return loader->loadIcon(name, KIcon::Toolbar, force_size, state);
01188 }
01189 
01190 QPixmap BarIcon(const QString& name, KInstance *instance)
01191 {
01192     return BarIcon(name, 0, KIcon::DefaultState, instance);
01193 }
01194 
01195 QIconSet BarIconSet(const QString& name, int force_size, KInstance *instance)
01196 {
01197     KIconLoader *loader = instance->iconLoader();
01198     return loader->loadIconSet( name, KIcon::Toolbar, force_size );
01199 }
01200 
01201 QPixmap SmallIcon(const QString& name, int force_size, int state,
01202     KInstance *instance)
01203 {
01204     KIconLoader *loader = instance->iconLoader();
01205     return loader->loadIcon(name, KIcon::Small, force_size, state);
01206 }
01207 
01208 QPixmap SmallIcon(const QString& name, KInstance *instance)
01209 {
01210     return SmallIcon(name, 0, KIcon::DefaultState, instance);
01211 }
01212 
01213 QIconSet SmallIconSet(const QString& name, int force_size, KInstance *instance)
01214 {
01215     KIconLoader *loader = instance->iconLoader();
01216     return loader->loadIconSet( name, KIcon::Small, force_size );
01217 }
01218 
01219 QPixmap MainBarIcon(const QString& name, int force_size, int state,
01220     KInstance *instance)
01221 {
01222     KIconLoader *loader = instance->iconLoader();
01223     return loader->loadIcon(name, KIcon::MainToolbar, force_size, state);
01224 }
01225 
01226 QPixmap MainBarIcon(const QString& name, KInstance *instance)
01227 {
01228     return MainBarIcon(name, 0, KIcon::DefaultState, instance);
01229 }
01230 
01231 QIconSet MainBarIconSet(const QString& name, int force_size, KInstance *instance)
01232 {
01233     KIconLoader *loader = instance->iconLoader();
01234     return loader->loadIconSet( name, KIcon::MainToolbar, force_size );
01235 }
01236 
01237 QPixmap UserIcon(const QString& name, int state, KInstance *instance)
01238 {
01239     KIconLoader *loader = instance->iconLoader();
01240     return loader->loadIcon(name, KIcon::User, 0, state);
01241 }
01242 
01243 QPixmap UserIcon(const QString& name, KInstance *instance)
01244 {
01245     return UserIcon(name, KIcon::DefaultState, instance);
01246 }
01247 
01248 QIconSet UserIconSet(const QString& name, KInstance *instance)
01249 {
01250     KIconLoader *loader = instance->iconLoader();
01251     return loader->loadIconSet( name, KIcon::User );
01252 }
01253 
01254 int IconSize(KIcon::Group group, KInstance *instance)
01255 {
01256     KIconLoader *loader = instance->iconLoader();
01257     return loader->currentSize(group);
01258 }
01259 
01260 QPixmap KIconLoader::unknown()
01261 {
01262     QPixmap pix;
01263     if ( QPixmapCache::find("unknown", pix) )
01264             return pix;
01265 
01266     QString path = KGlobal::iconLoader()->iconPath("unknown", KIcon::Small, true);
01267     if (path.isEmpty())
01268     {
01269     kdDebug(264) << "Warning: Cannot find \"unknown\" icon.\n";
01270     pix.resize(32,32);
01271     } else
01272     {
01273         pix.load(path);
01274         QPixmapCache::insert("unknown", pix);
01275     }
01276 
01277     return pix;
01278 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.3.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Tue Oct 5 10:21:36 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001