kicontheme.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kicontheme.cpp

    00001 /* vi: ts=8 sts=4 sw=4
    00002  *
    00003  * $Id: kicontheme.cpp,v 1.51.2.2 2003/06/29 21:42:59 deller 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  * kicontheme.cpp: Lowlevel icon theme handling.
    00014  */
    00015
    00016 #include <sys/stat.h>
    00017 #include <unistd.h>
    00018 #include <stdlib.h>
    00019 #include <config.h>
    00020
    00021 #include <qstring.h>
    00022 #include <qstringlist.h>
    00023 #include <qvaluelist.h>
    00024 #include <qmap.h>
    00025 #include <qpixmap.h>
    00026 #include <qpixmapcache.h>
    00027 #include <qimage.h>
    00028 #include <qfileinfo.h>
    00029 #include <qdir.h>
    00030
    00031 #include <kdebug.h>
    00032 #include <kstandarddirs.h>
    00033 #include <kglobal.h>
    00034 #include <kconfig.h>
    00035 #include <ksimpleconfig.h>
    00036 #include <kinstance.h>
    00037
    00038 #include "kicontheme.h"
    00039
    00040 class KIconThemePrivate
    00041 {
    00042 public:
    00043     QString example, screenshot;
    00044     QString linkOverlay, lockOverlay, zipOverlay, shareOverlay;
    00045     bool hidden;
    00046 };
    00047
    00051 class KIconThemeDir
    00052 {
    00053 public:
    00054     KIconThemeDir(const QString& dir, const KConfigBase *config);
    00055
    00056     bool isValid() const { return mbValid; }
    00057     QString iconPath(const QString& name) const;
    00058     QStringList iconList() const;
    00059     QString dir() const { return mDir; }
    00060
    00061     KIcon::Context context() const { return mContext; }
    00062     KIcon::Type type() const { return mType; }
    00063     int size() const { return mSize; }
    00064     int minSize() const { return mMinSize; }
    00065     int maxSize() const { return mMaxSize; }
    00066     int threshold() const { return mThreshold; }
    00067
    00068 private:
    00069     bool mbValid;
    00070     KIcon::Type mType;
    00071     KIcon::Context mContext;
    00072     int mSize, mMinSize, mMaxSize;
    00073     int mThreshold;
    00074
    00075     QString mDir;
    00076 };
    00077
    00078
    00079 /*** KIconTheme ***/
    00080
    00081 KIconTheme::KIconTheme(const QString& name, const QString& appName)
    00082 {
    00083     d = new KIconThemePrivate;
    00084
    00085     QStringList icnlibs;
    00086     QStringList::ConstIterator it, itDir;
    00087     QStringList themeDirs;
    00088     QString cDir;
    00089
    00090     // Applications can have local additions to the global "locolor" and
    00091     // "hicolor" icon themes. For these, the _global_ theme description
    00092     // files are used..
    00093
    00094     if (!appName.isEmpty() &&
    00095        ( name == "crystalsvg" || name== "hicolor" || name == "locolor" ) )
    00096     {
    00097         icnlibs = KGlobal::dirs()->resourceDirs("data");
    00098         for (it=icnlibs.begin(); it!=icnlibs.end(); it++)
    00099         {
    00100             cDir = *it + appName + "/icons/" + name;
    00101             if (QFile::exists( cDir ))
    00102                 themeDirs += cDir + "/";
    00103         }
    00104     }
    00105     // Find the theme description file. These are always global.
    00106
    00107     icnlibs = KGlobal::dirs()->resourceDirs("icon");
    00108     for (it=icnlibs.begin(); it!=icnlibs.end(); it++)
    00109     {
    00110         cDir = *it + name + "/";
    00111         if (KStandardDirs::exists(cDir))
    00112         {
    00113             themeDirs += cDir;
    00114             if (mDir.isEmpty()
    00115                     && (KStandardDirs::exists( cDir + "index.desktop") || KStandardDirs::exists( cDir + "index.theme")))
    00116                 mDir = cDir;
    00117         }
    00118     }
    00119
    00120     if (mDir.isEmpty())
    00121     {
    00122         kdDebug(264) << "Icon theme " << name << " not found.\n";
    00123         return;
    00124     }
    00125
    00126     QString fileName, mainSection;
    00127     if(QFile::exists(mDir + "index.desktop")) {
    00128         fileName = mDir + "index.desktop";
    00129         mainSection="KDE Icon Theme";
    00130     } else {
    00131         fileName = mDir + "index.theme";
    00132         mainSection="Icon Theme";
    00133     }
    00134     KSimpleConfig cfg(fileName);
    00135     cfg.setGroup(mainSection);
    00136     mName = cfg.readEntry("Name");
    00137     mDesc = cfg.readEntry("Comment");
    00138     mDepth = cfg.readNumEntry("DisplayDepth", 32);
    00139     mInherits = cfg.readListEntry("Inherits");
    00140     if ( name != "crystalsvg" )
    00141       for ( QStringList::Iterator it = mInherits.begin(); it != mInherits.end(); ++it )
    00142          if ( *it == "default" || *it == "hicolor" ) *it="crystalsvg";
    00143
    00144     d->hidden = cfg.readBoolEntry("Hidden", false);
    00145     d->example = cfg.readPathEntry("Example");
    00146     d->screenshot = cfg.readPathEntry("ScreenShot");
    00147     d->linkOverlay = cfg.readEntry("LinkOverlay", "link");
    00148     d->lockOverlay = cfg.readEntry("LockOverlay", "lock");
    00149     d->zipOverlay = cfg.readEntry("ZipOverlay", "zip");
    00150     d->shareOverlay = cfg.readEntry("ShareOverlay","share");
    00151
    00152     QStringList dirs = cfg.readPathListEntry("Directories");
    00153     mDirs.setAutoDelete(true);
    00154     for (it=dirs.begin(); it!=dirs.end(); it++)
    00155     {
    00156         cfg.setGroup(*it);
    00157         for (itDir=themeDirs.begin(); itDir!=themeDirs.end(); itDir++)
    00158         {
    00159             if (KStandardDirs::exists(*itDir + *it + "/"))
    00160             {
    00161                 KIconThemeDir *dir = new KIconThemeDir(*itDir + *it, &cfg);
    00162                 if (!dir->isValid())
    00163                     delete dir;
    00164                 else
    00165                     mDirs.append(dir);
    00166             }
    00167         }
    00168     }
    00169
    00170     // Expand available sizes for scalable icons to their full range
    00171     int i;
    00172     QMap<int,QValueList<int> > scIcons;
    00173     for (KIconThemeDir *dir=mDirs.first(); dir!=0L; dir=mDirs.next())
    00174     {
    00175         if ((dir->type() == KIcon::Scalable) && !scIcons.contains(dir->size()))
    00176         {
    00177             QValueList<int> lst;
    00178             for (i=dir->minSize(); i<=dir->maxSize(); i++)
    00179                 lst += i;
    00180             scIcons[dir->size()] = lst;
    00181         }
    00182     }
    00183
    00184     QStringList groups;
    00185     groups += "Desktop";
    00186     groups += "Toolbar";
    00187     groups += "MainToolbar";
    00188     groups += "Small";
    00189     groups += "Panel";
    00190     const int defDefSizes[] = { 32, 22, 22, 16, 32 };
    00191     cfg.setGroup(mainSection);
    00192     for (it=groups.begin(), i=0; it!=groups.end(); it++, i++)
    00193     {
    00194         mDefSize[i] = cfg.readNumEntry(*it + "Default", defDefSizes[i]);
    00195         QValueList<int> lst = cfg.readIntListEntry(*it + "Sizes"), exp;
    00196         QValueList<int>::ConstIterator it2;
    00197         for (it2=lst.begin(); it2!=lst.end(); it2++)
    00198         {
    00199             if (scIcons.contains(*it2))
    00200                 exp += scIcons[*it2];
    00201             else
    00202                 exp += *it2;
    00203         }
    00204         mSizes[i] = exp;
    00205     }
    00206
    00207 }
    00208
    00209 KIconTheme::~KIconTheme()
    00210 {
    00211     delete d;
    00212 }
    00213
    00214 bool KIconTheme::isValid() const
    00215 {
    00216     return !mDirs.isEmpty();
    00217 }
    00218
    00219 bool KIconTheme::isHidden() const
    00220 {
    00221     return d->hidden;
    00222 }
    00223
    00224 QString KIconTheme::example() const { return d->example; }
    00225 QString KIconTheme::screenshot() const { return d->screenshot; }
    00226 QString KIconTheme::linkOverlay() const { return d->linkOverlay; }
    00227 QString KIconTheme::lockOverlay() const { return d->lockOverlay; }
    00228 QString KIconTheme::zipOverlay() const { return d->zipOverlay; }
    00229 QString KIconTheme::shareOverlay() const { return d->shareOverlay; }
    00230
    00231 int KIconTheme::defaultSize(KIcon::Group group) const
    00232 {
    00233     if ((group < 0) || (group >= KIcon::LastGroup))
    00234     {
    00235         kdDebug(264) << "Illegal icon group: " << group << "\n";
    00236         return -1;
    00237     }
    00238     return mDefSize[group];
    00239 }
    00240
    00241 QValueList<int> KIconTheme::querySizes(KIcon::Group group) const
    00242 {
    00243     QValueList<int> empty;
    00244     if ((group < 0) || (group >= KIcon::LastGroup))
    00245     {
    00246         kdDebug(264) << "Illegal icon group: " << group << "\n";
    00247         return empty;
    00248     }
    00249     return mSizes[group];
    00250 }
    00251
    00252 QStringList KIconTheme::queryIcons(int size, KIcon::Context context) const
    00253 {
    00254     int delta = 1000, dw;
    00255
    00256     QPtrListIterator<KIconThemeDir> dirs(mDirs);
    00257     KIconThemeDir *dir;
    00258
    00259     // Try to find exact match
    00260     QStringList result;
    00261     for ( ; dirs.current(); ++dirs)
    00262     {
    00263         dir = dirs.current();
    00264         if ((context != KIcon::Any) && (context != dir->context()))
    00265             continue;
    00266         if ((dir->type() == KIcon::Fixed) && (dir->size() == size))
    00267         {
    00268             result += dir->iconList();
    00269             continue;
    00270         }
    00271         if ((dir->type() == KIcon::Scalable) &&
    00272             (size >= dir->minSize()) && (size <= dir->maxSize()))
    00273         {
    00274             result += dir->iconList();
    00275             continue;
    00276         }
    00277         if ((dir->type() == KIcon::Threshold) &&
    00278             (abs(size-dir->size())<dir->threshold()))
    00279             result+=dir->iconList();
    00280     }
    00281
    00282     return result;
    00283
    00284     dirs.toFirst();
    00285
    00286     // Find close match
    00287     KIconThemeDir *best = 0L;
    00288     for ( ; dirs.current(); ++dirs)
    00289     {
    00290         dir = dirs.current();
    00291         if ((context != KIcon::Any) && (context != dir->context()))
    00292             continue;
    00293         dw = dir->size() - size;
    00294         if ((dw > 6) || (abs(dw) >= abs(delta)))
    00295             continue;
    00296         delta = dw;
    00297         best = dir;
    00298     }
    00299     if (best == 0L)
    00300         return QStringList();
    00301
    00302     return best->iconList();
    00303 }
    00304
    00305 QStringList KIconTheme::queryIconsByContext(int size, KIcon::Context context) const
    00306 {
    00307     QPtrListIterator<KIconThemeDir> dirs(mDirs);
    00308     int dw;
    00309     KIconThemeDir *dir;
    00310
    00311     // We want all the icons for a given context, but we prefer icons
    00312     // of size size . Note that this may (will) include duplicate icons
    00313     QStringList iconlist[34]; // 33 == 48-16+1
    00314     // Usually, only the 0, 6 (22-16), 10 (32-22), 16 (48-32 or 32-16),
    00315     // 26 (48-22) and 32 (48-16) will be used, but who knows if someone
    00316     // will make icon themes with different icon sizes.
    00317
    00318     for ( ; dirs.current(); ++dirs)
    00319     {
    00320         dir = dirs.current();
    00321         if ((context != KIcon::Any) && (context != dir->context()))
    00322             continue;
    00323         dw = abs(dir->size() - size);
    00324         iconlist[(dw<33)?dw:33]+=dir->iconList();
    00325     }
    00326
    00327     QStringList iconlistResult;
    00328     for (int i=0; i<34; i++) iconlistResult+=iconlist[i];
    00329
    00330     return iconlistResult;
    00331 }
    00332
    00333 KIcon KIconTheme::iconPath(const QString& name, int size, KIcon::MatchType match) const
    00334 {
    00335     KIcon icon;
    00336     QString path;
    00337     int delta = 1000, dw;
    00338     KIconThemeDir *dir;
    00339
    00340     dw = 1000; // shut up, gcc
    00341     QPtrListIterator<KIconThemeDir> dirs(mDirs);
    00342     for ( ; dirs.current(); ++dirs)
    00343     {
    00344         dir = dirs.current();
    00345
    00346         if (match == KIcon::MatchExact)
    00347         {
    00348             if ((dir->type() == KIcon::Fixed) && (dir->size() != size))
    00349                 continue;
    00350             if ((dir->type() == KIcon::Scalable) &&
    00351                 ((size < dir->minSize()) || (size > dir->maxSize())))
    00352               continue;
    00353             if ((dir->type() == KIcon::Threshold) &&
    00354                 (abs(dir->size()-size) > dir->threshold()))
    00355                 continue;
    00356         } else
    00357         {
    00358             dw = dir->size() - size;
    00359             if (dir->type() != KIcon::Threshold &&
    00360                ((dw > 7) || (abs(dw) >= abs(delta))))
    00361                 continue;
    00362         }
    00363
    00364         path = dir->iconPath(name);
    00365         if (path.isEmpty())
    00366             continue;
    00367         icon.path = path;
    00368         icon.size = dir->size();
    00369         icon.type = dir->type();
    00370         icon.threshold = dir->threshold();
    00371         icon.context = dir->context();
    00372
    00373         // if we got in MatchExact that far, we find no better
    00374         if (match == KIcon::MatchExact)
    00375             return icon;
    00376         else
    00377         {
    00378             delta = dw;
    00379             if (delta==0) return icon; // We won't find a better match anyway
    00380         }
    00381     }
    00382     return icon;
    00383 }
    00384
    00385 // static
    00386 QString *KIconTheme::_theme = 0L;
    00387
    00388 // static
    00389 QStringList *KIconTheme::_theme_list = 0L;
    00390
    00391 // static
    00392 QString KIconTheme::current()
    00393 {
    00394     // Static pointer because of unloading problems wrt DSO's.
    00395     if (_theme != 0L)
    00396         return *_theme;
    00397
    00398     _theme = new QString();
    00399     KConfig *config = KGlobal::config();
    00400     KConfigGroupSaver saver(config, "Icons");
    00401     *_theme = config->readEntry("Theme",defaultThemeName());
    00402     if ( *_theme == QString::fromLatin1("hicolor") ) *_theme = defaultThemeName();
    00403 /*    if (_theme->isEmpty())
    00404     {
    00405         if (QPixmap::defaultDepth() > 8)
    00406             *_theme = defaultThemeName();
    00407         else
    00408             *_theme = QString::fromLatin1("locolor");
    00409     }*/
    00410     return *_theme;
    00411 }
    00412
    00413 // static
    00414 QStringList KIconTheme::list()
    00415 {
    00416     // Static pointer because of unloading problems wrt DSO's.
    00417     if (_theme_list != 0L)
    00418         return *_theme_list;
    00419
    00420     _theme_list = new QStringList();
    00421     QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
    00422     QStringList::ConstIterator it;
    00423     for (it=icnlibs.begin(); it!=icnlibs.end(); it++)
    00424     {
    00425         QDir dir(*it);
    00426         if (!dir.exists())
    00427             continue;
    00428         QStringList lst = dir.entryList(QDir::Dirs);
    00429         QStringList::ConstIterator it2;
    00430         for (it2=lst.begin(); it2!=lst.end(); it2++)
    00431         {
    00432             if ((*it2 == ".") || (*it2 == "..") || (*it2).startsWith("default.") )
    00433                 continue;
    00434             if (!KStandardDirs::exists(*it + *it2 + "/index.desktop") && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
    00435                 continue;
    00436             if (!_theme_list->contains(*it2))
    00437                 _theme_list->append(*it2);
    00438         }
    00439     }
    00440     return *_theme_list;
    00441 }
    00442
    00443 // static
    00444 void KIconTheme::reconfigure()
    00445 {
    00446     delete _theme;
    00447     _theme=0L;
    00448     delete _theme_list;
    00449     _theme_list=0L;
    00450 }
    00451
    00452 // static
    00453 QString KIconTheme::defaultThemeName()
    00454 {
    00455     return QString::fromLatin1("crystalsvg");
    00456 }
    00457
    00458 /*** KIconThemeDir ***/
    00459
    00460 KIconThemeDir::KIconThemeDir(const QString& dir, const KConfigBase *config)
    00461 {
    00462     mbValid = false;
    00463     mDir = dir;
    00464     mSize = config->readNumEntry("Size");
    00465     mMinSize = 1;    // just set the variables to something
    00466     mMaxSize = 50;   // meaningful in case someone calls minSize or maxSize
    00467     mType = KIcon::Fixed;
    00468
    00469     if (mSize == 0)
    00470         return;
    00471
    00472     QString tmp = config->readEntry("Context");
    00473     if (tmp == "Devices")
    00474         mContext = KIcon::Device;
    00475     else if (tmp == "MimeTypes")
    00476         mContext = KIcon::MimeType;
    00477     else if (tmp == "FileSystems")
    00478         mContext = KIcon::FileSystem;
    00479     else if (tmp == "Applications")
    00480         mContext = KIcon::Application;
    00481     else if (tmp == "Actions")
    00482         mContext = KIcon::Action;
    00483     else {
    00484         kdDebug(264) << "Invalid Context= line for icon theme: " << mDir << "\n";
    00485         return;
    00486     }
    00487     tmp = config->readEntry("Type");
    00488     if (tmp == "Fixed")
    00489         mType = KIcon::Fixed;
    00490     else if (tmp == "Scalable")
    00491         mType = KIcon::Scalable;
    00492     else if (tmp == "Threshold")
    00493         mType = KIcon::Threshold;
    00494     else {
    00495         kdDebug(264) << "Invalid Type= line for icon theme: " <<  mDir << "\n";
    00496         return;
    00497     }
    00498     if (mType == KIcon::Scalable)
    00499     {
    00500         mMinSize = config->readNumEntry("MinSize", mSize);
    00501         mMaxSize = config->readNumEntry("MaxSize", mSize);
    00502     } else if (mType == KIcon::Threshold)
    00503         mThreshold = config->readNumEntry("Threshold", 2);
    00504     mbValid = true;
    00505 }
    00506
    00507 QString KIconThemeDir::iconPath(const QString& name) const
    00508 {
    00509     if (!mbValid)
    00510         return QString::null;
    00511     QString file = mDir + "/" + name;
    00512
    00513     if (access(QFile::encodeName(file), R_OK) == 0)
    00514         return file;
    00515
    00516     return QString::null;
    00517 }
    00518
    00519 QStringList KIconThemeDir::iconList() const
    00520 {
    00521     QDir dir(mDir);
    00522 #ifdef HAVE_LIBART
    00523     QStringList lst = dir.entryList("*.png;*.svg;*.svgz;*.xpm", QDir::Files);
    00524 #else
    00525     QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files);
    00526 #endif
    00527     QStringList result;
    00528     QStringList::ConstIterator it;
    00529     for (it=lst.begin(); it!=lst.end(); it++)
    00530         result += mDir + "/" + *it;
    00531     return result;
    00532 }

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