kdecore Library API Documentation

kiconloader.cpp

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