kdecore Library API Documentation

kiconloader.cpp

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