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