KDECore
kicontheme.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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 KSharedConfig::Ptr sharedConfig;
00047 };
00048
00052 class KIconThemeDir
00053 {
00054 public:
00055 KIconThemeDir(const QString& dir, const KConfigBase *config);
00056
00057 bool isValid() const { return mbValid; }
00058 QString iconPath(const QString& name) const;
00059 QStringList iconList() const;
00060 QString dir() const { return mDir; }
00061
00062 KIcon::Context context() const { return mContext; }
00063 KIcon::Type type() const { return mType; }
00064 int size() const { return mSize; }
00065 int minSize() const { return mMinSize; }
00066 int maxSize() const { return mMaxSize; }
00067 int threshold() const { return mThreshold; }
00068
00069 private:
00070 bool mbValid;
00071 KIcon::Type mType;
00072 KIcon::Context mContext;
00073 int mSize, mMinSize, mMaxSize;
00074 int mThreshold;
00075
00076 QString mDir;
00077 };
00078
00079
00080
00081
00082 KIconTheme::KIconTheme(const QString& name, const QString& appName)
00083 {
00084 d = new KIconThemePrivate;
00085
00086 QStringList icnlibs;
00087 QStringList::ConstIterator it, itDir;
00088 QStringList themeDirs;
00089 QString cDir;
00090
00091
00092
00093
00094
00095 if (!appName.isEmpty() &&
00096 ( name == "crystalsvg" || name== "hicolor" || name == "locolor" ) )
00097 {
00098 icnlibs = KGlobal::dirs()->resourceDirs("data");
00099 for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00100 {
00101 cDir = *it + appName + "/icons/" + name;
00102 if (QFile::exists( cDir ))
00103 themeDirs += cDir + "/";
00104 }
00105 }
00106
00107
00108 icnlibs = KGlobal::dirs()->resourceDirs("icon");
00109 icnlibs += KGlobal::dirs()->resourceDirs("xdgdata-icon");
00110 icnlibs += "/usr/share/pixmaps";
00111
00112 icnlibs += KGlobal::dirs()->resourceDirs("xdgdata-pixmap");
00113 for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00114 {
00115 cDir = *it + name + "/";
00116 if (KStandardDirs::exists(cDir))
00117 {
00118 themeDirs += cDir;
00119 if (mDir.isEmpty()
00120 && (KStandardDirs::exists( cDir + "index.desktop") || KStandardDirs::exists( cDir + "index.theme")))
00121 mDir = cDir;
00122 }
00123 }
00124
00125 if (mDir.isEmpty())
00126 {
00127 kdDebug(264) << "Icon theme " << name << " not found.\n";
00128 return;
00129 }
00130
00131 QString fileName, mainSection;
00132 if(QFile::exists(mDir + "index.desktop")) {
00133 fileName = mDir + "index.desktop";
00134 mainSection="KDE Icon Theme";
00135 } else {
00136 fileName = mDir + "index.theme";
00137 mainSection="Icon Theme";
00138 }
00139
00140
00141 d->sharedConfig = KSharedConfig::openConfig( fileName, true , false );
00142 KConfig& cfg = *d->sharedConfig;
00143
00144
00145 cfg.setGroup(mainSection);
00146 mName = cfg.readEntry("Name");
00147 mDesc = cfg.readEntry("Comment");
00148 mDepth = cfg.readNumEntry("DisplayDepth", 32);
00149 mInherits = cfg.readListEntry("Inherits");
00150 if ( name != "crystalsvg" )
00151 for ( QStringList::Iterator it = mInherits.begin(); it != mInherits.end(); ++it )
00152 if ( *it == "default" || *it == "hicolor" ) *it="crystalsvg";
00153
00154 d->hidden = cfg.readBoolEntry("Hidden", false);
00155 d->example = cfg.readPathEntry("Example");
00156 d->screenshot = cfg.readPathEntry("ScreenShot");
00157 d->linkOverlay = cfg.readEntry("LinkOverlay", "link");
00158 d->lockOverlay = cfg.readEntry("LockOverlay", "lock");
00159 d->zipOverlay = cfg.readEntry("ZipOverlay", "zip");
00160 d->shareOverlay = cfg.readEntry("ShareOverlay","share");
00161
00162 QStringList dirs = cfg.readPathListEntry("Directories");
00163 mDirs.setAutoDelete(true);
00164 for (it=dirs.begin(); it!=dirs.end(); ++it)
00165 {
00166 cfg.setGroup(*it);
00167 for (itDir=themeDirs.begin(); itDir!=themeDirs.end(); ++itDir)
00168 {
00169 if (KStandardDirs::exists(*itDir + *it + "/"))
00170 {
00171 KIconThemeDir *dir = new KIconThemeDir(*itDir + *it, &cfg);
00172 if (!dir->isValid())
00173 {
00174 kdDebug(264) << "Icon directory " << *itDir << " group " << *it << " not valid.\n";
00175 delete dir;
00176 }
00177 else
00178 mDirs.append(dir);
00179 }
00180 }
00181 }
00182
00183
00184 int i;
00185 QMap<int,QValueList<int> > scIcons;
00186 for (KIconThemeDir *dir=mDirs.first(); dir!=0L; dir=mDirs.next())
00187 {
00188 if ((dir->type() == KIcon::Scalable) && !scIcons.contains(dir->size()))
00189 {
00190 QValueList<int> lst;
00191 for (i=dir->minSize(); i<=dir->maxSize(); i++)
00192 lst += i;
00193 scIcons[dir->size()] = lst;
00194 }
00195 }
00196
00197 QStringList groups;
00198 groups += "Desktop";
00199 groups += "Toolbar";
00200 groups += "MainToolbar";
00201 groups += "Small";
00202 groups += "Panel";
00203 const int defDefSizes[] = { 32, 22, 22, 16, 32 };
00204 cfg.setGroup(mainSection);
00205 for (it=groups.begin(), i=0; it!=groups.end(); ++it, i++)
00206 {
00207 mDefSize[i] = cfg.readNumEntry(*it + "Default", defDefSizes[i]);
00208 QValueList<int> exp, lst = cfg.readIntListEntry(*it + "Sizes");
00209 QValueList<int>::ConstIterator it2;
00210 for (it2=lst.begin(); it2!=lst.end(); ++it2)
00211 {
00212 if (scIcons.contains(*it2))
00213 exp += scIcons[*it2];
00214 else
00215 exp += *it2;
00216 }
00217 mSizes[i] = exp;
00218 }
00219
00220 }
00221
00222 KIconTheme::~KIconTheme()
00223 {
00224 delete d;
00225 }
00226
00227 bool KIconTheme::isValid() const
00228 {
00229 return !mDirs.isEmpty();
00230 }
00231
00232 bool KIconTheme::isHidden() const
00233 {
00234 return d->hidden;
00235 }
00236
00237 QString KIconTheme::example() const { return d->example; }
00238 QString KIconTheme::screenshot() const { return d->screenshot; }
00239 QString KIconTheme::linkOverlay() const { return d->linkOverlay; }
00240 QString KIconTheme::lockOverlay() const { return d->lockOverlay; }
00241 QString KIconTheme::zipOverlay() const { return d->zipOverlay; }
00242 QString KIconTheme::shareOverlay() const { return d->shareOverlay; }
00243
00244 int KIconTheme::defaultSize(KIcon::Group group) const
00245 {
00246 if ((group < 0) || (group >= KIcon::LastGroup))
00247 {
00248 kdDebug(264) << "Illegal icon group: " << group << "\n";
00249 return -1;
00250 }
00251 return mDefSize[group];
00252 }
00253
00254 QValueList<int> KIconTheme::querySizes(KIcon::Group group) const
00255 {
00256 QValueList<int> empty;
00257 if ((group < 0) || (group >= KIcon::LastGroup))
00258 {
00259 kdDebug(264) << "Illegal icon group: " << group << "\n";
00260 return empty;
00261 }
00262 return mSizes[group];
00263 }
00264
00265 QStringList KIconTheme::queryIcons(int size, KIcon::Context context) const
00266 {
00267 int delta = 1000, dw;
00268
00269 QPtrListIterator<KIconThemeDir> dirs(mDirs);
00270 KIconThemeDir *dir;
00271
00272
00273 QStringList result;
00274 for ( ; dirs.current(); ++dirs)
00275 {
00276 dir = dirs.current();
00277 if ((context != KIcon::Any) && (context != dir->context()))
00278 continue;
00279 if ((dir->type() == KIcon::Fixed) && (dir->size() == size))
00280 {
00281 result += dir->iconList();
00282 continue;
00283 }
00284 if ((dir->type() == KIcon::Scalable) &&
00285 (size >= dir->minSize()) && (size <= dir->maxSize()))
00286 {
00287 result += dir->iconList();
00288 continue;
00289 }
00290 if ((dir->type() == KIcon::Threshold) &&
00291 (abs(size-dir->size())<dir->threshold()))
00292 result+=dir->iconList();
00293 }
00294
00295 return result;
00296
00297 dirs.toFirst();
00298
00299
00300 KIconThemeDir *best = 0L;
00301 for ( ; dirs.current(); ++dirs)
00302 {
00303 dir = dirs.current();
00304 if ((context != KIcon::Any) && (context != dir->context()))
00305 continue;
00306 dw = dir->size() - size;
00307 if ((dw > 6) || (abs(dw) >= abs(delta)))
00308 continue;
00309 delta = dw;
00310 best = dir;
00311 }
00312 if (best == 0L)
00313 return QStringList();
00314
00315 return best->iconList();
00316 }
00317
00318 QStringList KIconTheme::queryIconsByContext(int size, KIcon::Context context) const
00319 {
00320 QPtrListIterator<KIconThemeDir> dirs(mDirs);
00321 int dw;
00322 KIconThemeDir *dir;
00323
00324
00325
00326
00327 QStringList iconlist[128];
00328
00329
00330
00331
00332 for ( ; dirs.current(); ++dirs)
00333 {
00334 dir = dirs.current();
00335 if ((context != KIcon::Any) && (context != dir->context()))
00336 continue;
00337 dw = abs(dir->size() - size);
00338 iconlist[(dw<127)?dw:127]+=dir->iconList();
00339 }
00340
00341 QStringList iconlistResult;
00342 for (int i=0; i<128; i++) iconlistResult+=iconlist[i];
00343
00344 return iconlistResult;
00345 }
00346
00347 bool KIconTheme::hasContext(KIcon::Context context) const
00348 {
00349 QPtrListIterator<KIconThemeDir> dirs(mDirs);
00350 KIconThemeDir *dir;
00351
00352 for ( ; dirs.current(); ++dirs)
00353 {
00354 dir = dirs.current();
00355 if ((context == KIcon::Any) || (context == dir->context()))
00356 return true;
00357 }
00358 return false;
00359 }
00360
00361 KIcon KIconTheme::iconPath(const QString& name, int size, KIcon::MatchType match) const
00362 {
00363 KIcon icon;
00364 QString path;
00365 int delta = -1000, dw;
00366 KIconThemeDir *dir;
00367
00368 dw = 1000;
00369 QPtrListIterator<KIconThemeDir> dirs(mDirs);
00370 for ( ; dirs.current(); ++dirs)
00371 {
00372 dir = dirs.current();
00373
00374 if (match == KIcon::MatchExact)
00375 {
00376 if ((dir->type() == KIcon::Fixed) && (dir->size() != size))
00377 continue;
00378 if ((dir->type() == KIcon::Scalable) &&
00379 ((size < dir->minSize()) || (size > dir->maxSize())))
00380 continue;
00381 if ((dir->type() == KIcon::Threshold) &&
00382 (abs(dir->size()-size) > dir->threshold()))
00383 continue;
00384 } else
00385 {
00386
00387 if (dir->type() == KIcon::Fixed)
00388 {
00389 dw = dir->size() - size;
00390 } else if (dir->type() == KIcon::Scalable)
00391 {
00392 if (size < dir->minSize())
00393 dw = dir->minSize() - size;
00394 else if (size > dir->maxSize())
00395 dw = dir->maxSize() - size;
00396 else
00397 dw = 0;
00398 } else if (dir->type() == KIcon::Threshold)
00399 {
00400 if (size < dir->size() - dir->threshold())
00401 dw = dir->size() - dir->threshold() - size;
00402 else if (size > dir->size() + dir->threshold())
00403 dw = dir->size() + dir->threshold() - size;
00404 else
00405 dw = 0;
00406 }
00407
00408
00409
00410
00411 if ((abs(dw) >= abs(delta)) ||
00412 (delta > 0 && dw < 0))
00413 continue;
00414 }
00415
00416 path = dir->iconPath(name);
00417 if (path.isEmpty())
00418 continue;
00419 icon.path = path;
00420 icon.size = dir->size();
00421 icon.type = dir->type();
00422 icon.threshold = dir->threshold();
00423 icon.context = dir->context();
00424
00425
00426 if (match == KIcon::MatchExact)
00427 return icon;
00428 else
00429 {
00430 delta = dw;
00431 if (delta==0) return icon;
00432 }
00433 }
00434 return icon;
00435 }
00436
00437
00438 QString *KIconTheme::_theme = 0L;
00439
00440
00441 QStringList *KIconTheme::_theme_list = 0L;
00442
00443
00444 QString KIconTheme::current()
00445 {
00446
00447 if (_theme != 0L)
00448 return *_theme;
00449
00450 _theme = new QString();
00451 KConfig *config = KGlobal::config();
00452 KConfigGroupSaver saver(config, "Icons");
00453 *_theme = config->readEntry("Theme",defaultThemeName());
00454 if ( *_theme == QString::fromLatin1("hicolor") ) *_theme = defaultThemeName();
00455
00456
00457
00458
00459
00460
00461
00462 return *_theme;
00463 }
00464
00465
00466 QStringList KIconTheme::list()
00467 {
00468
00469 if (_theme_list != 0L)
00470 return *_theme_list;
00471
00472 _theme_list = new QStringList();
00473 QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon");
00474 icnlibs += (KGlobal::dirs()->resourceDirs("xdgdata-icon"));
00475 icnlibs += "/usr/share/pixmaps";
00476
00477 icnlibs += KGlobal::dirs()->resourceDirs("xdgdata-pixmap");
00478 QStringList::ConstIterator it;
00479 for (it=icnlibs.begin(); it!=icnlibs.end(); ++it)
00480 {
00481 QDir dir(*it);
00482 if (!dir.exists())
00483 continue;
00484 QStringList lst = dir.entryList(QDir::Dirs);
00485 QStringList::ConstIterator it2;
00486 for (it2=lst.begin(); it2!=lst.end(); ++it2)
00487 {
00488 if ((*it2 == ".") || (*it2 == "..") || (*it2).startsWith("default.") )
00489 continue;
00490 if (!KStandardDirs::exists(*it + *it2 + "/index.desktop") && !KStandardDirs::exists(*it + *it2 + "/index.theme"))
00491 continue;
00492 KIconTheme oink(*it2);
00493 if (!oink.isValid()) continue;
00494
00495 if (!_theme_list->contains(*it2))
00496 _theme_list->append(*it2);
00497 }
00498 }
00499 return *_theme_list;
00500 }
00501
00502
00503 void KIconTheme::reconfigure()
00504 {
00505 delete _theme;
00506 _theme=0L;
00507 delete _theme_list;
00508 _theme_list=0L;
00509 }
00510
00511
00512 QString KIconTheme::defaultThemeName()
00513 {
00514 return QString::fromLatin1("crystalsvg");
00515 }
00516
00517
00518
00519 KIconThemeDir::KIconThemeDir(const QString& dir, const KConfigBase *config)
00520 {
00521 mbValid = false;
00522 mDir = dir;
00523 mSize = config->readNumEntry("Size");
00524 mMinSize = 1;
00525 mMaxSize = 50;
00526 mType = KIcon::Fixed;
00527
00528 if (mSize == 0)
00529 return;
00530
00531 QString tmp = config->readEntry("Context");
00532 if (tmp == "Devices")
00533 mContext = KIcon::Device;
00534 else if (tmp == "MimeTypes")
00535 mContext = KIcon::MimeType;
00536 else if (tmp == "FileSystems")
00537 mContext = KIcon::FileSystem;
00538 else if (tmp == "Applications")
00539 mContext = KIcon::Application;
00540 else if (tmp == "Actions")
00541 mContext = KIcon::Action;
00542 else if (tmp == "Animations")
00543 mContext = KIcon::Animation;
00544 else if (tmp == "Categories")
00545 mContext = KIcon::Category;
00546 else if (tmp == "Emblems")
00547 mContext = KIcon::Emblem;
00548 else if (tmp == "Emotes")
00549 mContext = KIcon::Emote;
00550 else if (tmp == "International")
00551 mContext = KIcon::International;
00552 else if (tmp == "Places")
00553 mContext = KIcon::Place;
00554 else if (tmp == "Status")
00555 mContext = KIcon::StatusIcon;
00556 else {
00557 kdDebug(264) << "Invalid Context= line for icon theme: " << mDir << "\n";
00558 return;
00559 }
00560 tmp = config->readEntry("Type");
00561 if (tmp == "Fixed")
00562 mType = KIcon::Fixed;
00563 else if (tmp == "Scalable")
00564 mType = KIcon::Scalable;
00565 else if (tmp == "Threshold")
00566 mType = KIcon::Threshold;
00567 else {
00568 kdDebug(264) << "Invalid Type= line for icon theme: " << mDir << "\n";
00569 return;
00570 }
00571 if (mType == KIcon::Scalable)
00572 {
00573 mMinSize = config->readNumEntry("MinSize", mSize);
00574 mMaxSize = config->readNumEntry("MaxSize", mSize);
00575 } else if (mType == KIcon::Threshold)
00576 mThreshold = config->readNumEntry("Threshold", 2);
00577 mbValid = true;
00578 }
00579
00580 QString KIconThemeDir::iconPath(const QString& name) const
00581 {
00582 if (!mbValid)
00583 return QString::null;
00584 QString file = mDir + "/" + name;
00585
00586 if (access(QFile::encodeName(file), R_OK) == 0)
00587 return file;
00588
00589 return QString::null;
00590 }
00591
00592 QStringList KIconThemeDir::iconList() const
00593 {
00594 QDir dir(mDir);
00595 #ifdef HAVE_LIBART
00596 QStringList lst = dir.entryList("*.png;*.svg;*.svgz;*.xpm", QDir::Files);
00597 #else
00598 QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files);
00599 #endif
00600 QStringList result;
00601 QStringList::ConstIterator it;
00602 for (it=lst.begin(); it!=lst.end(); ++it)
00603 result += mDir + "/" + *it;
00604 return result;
00605 }