kdecore Library API Documentation

kiconloader.cpp

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