# kdecore Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kiconloader.cpp

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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:46:34 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001