kdecore Library API Documentation

kicontheme.cpp

00001 /* vi: ts=8 sts=4 sw=4 00002 * 00003 * $Id: kicontheme.cpp,v 1.56.2.1 2004/05/29 15:22:08 djurban 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 { 00164 kdWarning(264) << "Icon directory " << *itDir << " group " << *it << " not valid.\n"; 00165 delete dir; 00166 } 00167 else 00168 mDirs.append(dir); 00169 } 00170 } 00171 } 00172 00173 // Expand available sizes for scalable icons to their full range 00174 int i; 00175 QMap<int,QValueList<int> > scIcons; 00176 for (KIconThemeDir *dir=mDirs.first(); dir!=0L; dir=mDirs.next()) 00177 { 00178 if ((dir->type() == KIcon::Scalable) && !scIcons.contains(dir->size())) 00179 { 00180 QValueList<int> lst; 00181 for (i=dir->minSize(); i<=dir->maxSize(); i++) 00182 lst += i; 00183 scIcons[dir->size()] = lst; 00184 } 00185 } 00186 00187 QStringList groups; 00188 groups += "Desktop"; 00189 groups += "Toolbar"; 00190 groups += "MainToolbar"; 00191 groups += "Small"; 00192 groups += "Panel"; 00193 const int defDefSizes[] = { 32, 22, 22, 16, 32 }; 00194 cfg.setGroup(mainSection); 00195 for (it=groups.begin(), i=0; it!=groups.end(); ++it, i++) 00196 { 00197 mDefSize[i] = cfg.readNumEntry(*it + "Default", defDefSizes[i]); 00198 QValueList<int> exp, lst = cfg.readIntListEntry(*it + "Sizes"); 00199 QValueList<int>::ConstIterator it2; 00200 for (it2=lst.begin(); it2!=lst.end(); ++it2) 00201 { 00202 if (scIcons.contains(*it2)) 00203 exp += scIcons[*it2]; 00204 else 00205 exp += *it2; 00206 } 00207 mSizes[i] = exp; 00208 } 00209 00210 } 00211 00212 KIconTheme::~KIconTheme() 00213 { 00214 delete d; 00215 } 00216 00217 bool KIconTheme::isValid() const 00218 { 00219 return !mDirs.isEmpty(); 00220 } 00221 00222 bool KIconTheme::isHidden() const 00223 { 00224 return d->hidden; 00225 } 00226 00227 QString KIconTheme::example() const { return d->example; } 00228 QString KIconTheme::screenshot() const { return d->screenshot; } 00229 QString KIconTheme::linkOverlay() const { return d->linkOverlay; } 00230 QString KIconTheme::lockOverlay() const { return d->lockOverlay; } 00231 QString KIconTheme::zipOverlay() const { return d->zipOverlay; } 00232 QString KIconTheme::shareOverlay() const { return d->shareOverlay; } 00233 00234 int KIconTheme::defaultSize(KIcon::Group group) const 00235 { 00236 if ((group < 0) || (group >= KIcon::LastGroup)) 00237 { 00238 kdDebug(264) << "Illegal icon group: " << group << "\n"; 00239 return -1; 00240 } 00241 return mDefSize[group]; 00242 } 00243 00244 QValueList<int> KIconTheme::querySizes(KIcon::Group group) const 00245 { 00246 QValueList<int> empty; 00247 if ((group < 0) || (group >= KIcon::LastGroup)) 00248 { 00249 kdDebug(264) << "Illegal icon group: " << group << "\n"; 00250 return empty; 00251 } 00252 return mSizes[group]; 00253 } 00254 00255 QStringList KIconTheme::queryIcons(int size, KIcon::Context context) const 00256 { 00257 int delta = 1000, dw; 00258 00259 QPtrListIterator<KIconThemeDir> dirs(mDirs); 00260 KIconThemeDir *dir; 00261 00262 // Try to find exact match 00263 QStringList result; 00264 for ( ; dirs.current(); ++dirs) 00265 { 00266 dir = dirs.current(); 00267 if ((context != KIcon::Any) && (context != dir->context())) 00268 continue; 00269 if ((dir->type() == KIcon::Fixed) && (dir->size() == size)) 00270 { 00271 result += dir->iconList(); 00272 continue; 00273 } 00274 if ((dir->type() == KIcon::Scalable) && 00275 (size >= dir->minSize()) && (size <= dir->maxSize())) 00276 { 00277 result += dir->iconList(); 00278 continue; 00279 } 00280 if ((dir->type() == KIcon::Threshold) && 00281 (abs(size-dir->size())<dir->threshold())) 00282 result+=dir->iconList(); 00283 } 00284 00285 return result; 00286 00287 dirs.toFirst(); 00288 00289 // Find close match 00290 KIconThemeDir *best = 0L; 00291 for ( ; dirs.current(); ++dirs) 00292 { 00293 dir = dirs.current(); 00294 if ((context != KIcon::Any) && (context != dir->context())) 00295 continue; 00296 dw = dir->size() - size; 00297 if ((dw > 6) || (abs(dw) >= abs(delta))) 00298 continue; 00299 delta = dw; 00300 best = dir; 00301 } 00302 if (best == 0L) 00303 return QStringList(); 00304 00305 return best->iconList(); 00306 } 00307 00308 QStringList KIconTheme::queryIconsByContext(int size, KIcon::Context context) const 00309 { 00310 QPtrListIterator<KIconThemeDir> dirs(mDirs); 00311 int dw; 00312 KIconThemeDir *dir; 00313 00314 // We want all the icons for a given context, but we prefer icons 00315 // of size size . Note that this may (will) include duplicate icons 00316 //QStringList iconlist[34]; // 33 == 48-16+1 00317 QStringList iconlist[128]; // 33 == 48-16+1 00318 // Usually, only the 0, 6 (22-16), 10 (32-22), 16 (48-32 or 32-16), 00319 // 26 (48-22) and 32 (48-16) will be used, but who knows if someone 00320 // will make icon themes with different icon sizes. 00321 00322 for ( ; dirs.current(); ++dirs) 00323 { 00324 dir = dirs.current(); 00325 if ((context != KIcon::Any) && (context != dir->context())) 00326 continue; 00327 dw = abs(dir->size() - size); 00328 iconlist[(dw<127)?dw:127]+=dir->iconList(); 00329 } 00330 00331 QStringList iconlistResult; 00332 for (int i=0; i<128; i++) iconlistResult+=iconlist[i]; 00333 00334 return iconlistResult; 00335 } 00336 00337 KIcon KIconTheme::iconPath(const QString& name, int size, KIcon::MatchType match) const 00338 { 00339 KIcon icon; 00340 QString path; 00341 int delta = 1000, dw; 00342 KIconThemeDir *dir; 00343 00344 dw = 1000; // shut up, gcc 00345 QPtrListIterator<KIconThemeDir> dirs(mDirs); 00346 for ( ; dirs.current(); ++dirs) 00347 { 00348 dir = dirs.current(); 00349 00350 if (match == KIcon::MatchExact) 00351 { 00352 if ((dir->type() == KIcon::Fixed) && (dir->size() != size)) 00353 continue; 00354 if ((dir->type() == KIcon::Scalable) && 00355 ((size < dir->minSize()) || (size > dir->maxSize()))) 00356 continue; 00357 if ((dir->type() == KIcon::Threshold) && 00358 (abs(dir->size()-size) > dir->threshold())) 00359 continue; 00360 } else 00361 { 00362 // dw < 0 means need to scale up to get an icon of the requested size 00363 if (dir->type() == KIcon::Fixed) 00364 { 00365 dw = dir->size() - size; 00366 } else if (dir->type() == KIcon::Scalable) 00367 { 00368 if (size < dir->minSize()) 00369 dw = dir->minSize() - size; 00370 else if (size > dir->maxSize()) 00371 dw = dir->maxSize() - size; 00372 else 00373 dw = 0; 00374 } else if (dir->type() == KIcon::Threshold) 00375 { 00376 if (size < dir->size() - dir->threshold()) 00377 dw = dir->size() - dir->threshold() - size; 00378 else if (size > dir->size() + dir->threshold()) 00379 dw = dir->size() + dir->threshold() - size; 00380 else 00381 dw = 0; 00382 } 00383 /* Skip this if we've found a closer one, unless 00384 it's a downscale, and we only had upscales befores. 00385 This is to avoid scaling up unless we have to, 00386 since that looks very ugly */ 00387 if ((abs(dw) >= abs(delta)) && 00388 !(delta > 0 && dw < 0)) 00389 continue; 00390 } 00391 00392 path = dir->iconPath(name); 00393 if (path.isEmpty()) 00394 continue; 00395 icon.path = path; 00396 icon.size = dir->size(); 00397 icon.type = dir->type(); 00398 icon.threshold = dir->threshold(); 00399 icon.context = dir->context(); 00400 00401 // if we got in MatchExact that far, we find no better 00402 if (match == KIcon::MatchExact) 00403 return icon; 00404 else 00405 { 00406 delta = dw; 00407 if (delta==0) return icon; // We won't find a better match anyway 00408 } 00409 } 00410 return icon; 00411 } 00412 00413 // static 00414 QString *KIconTheme::_theme = 0L; 00415 00416 // static 00417 QStringList *KIconTheme::_theme_list = 0L; 00418 00419 // static 00420 QString KIconTheme::current() 00421 { 00422 // Static pointer because of unloading problems wrt DSO's. 00423 if (_theme != 0L) 00424 return *_theme; 00425 00426 _theme = new QString(); 00427 KConfig *config = KGlobal::config(); 00428 KConfigGroupSaver saver(config, "Icons"); 00429 *_theme = config->readEntry("Theme",defaultThemeName()); 00430 if ( *_theme == QString::fromLatin1("hicolor") ) *_theme = defaultThemeName(); 00431 /* if (_theme->isEmpty()) 00432 { 00433 if (QPixmap::defaultDepth() > 8) 00434 *_theme = defaultThemeName(); 00435 else 00436 *_theme = QString::fromLatin1("locolor"); 00437 }*/ 00438 return *_theme; 00439 } 00440 00441 // static 00442 QStringList KIconTheme::list() 00443 { 00444 // Static pointer because of unloading problems wrt DSO's. 00445 if (_theme_list != 0L) 00446 return *_theme_list; 00447 00448 _theme_list = new QStringList(); 00449 QStringList icnlibs = KGlobal::dirs()->resourceDirs("icon"); 00450 QStringList::ConstIterator it; 00451 for (it=icnlibs.begin(); it!=icnlibs.end(); ++it) 00452 { 00453 QDir dir(*it); 00454 if (!dir.exists()) 00455 continue; 00456 QStringList lst = dir.entryList(QDir::Dirs); 00457 QStringList::ConstIterator it2; 00458 for (it2=lst.begin(); it2!=lst.end(); ++it2) 00459 { 00460 if ((*it2 == ".") || (*it2 == "..") || (*it2).startsWith("default.") ) 00461 continue; 00462 if (!KStandardDirs::exists(*it + *it2 + "/index.desktop") && !KStandardDirs::exists(*it + *it2 + "/index.theme")) 00463 continue; 00464 KIconTheme oink(*it2); 00465 if (!oink.isValid()) continue; 00466 00467 if (!_theme_list->contains(*it2)) 00468 _theme_list->append(*it2); 00469 } 00470 } 00471 return *_theme_list; 00472 } 00473 00474 // static 00475 void KIconTheme::reconfigure() 00476 { 00477 delete _theme; 00478 _theme=0L; 00479 delete _theme_list; 00480 _theme_list=0L; 00481 } 00482 00483 // static 00484 QString KIconTheme::defaultThemeName() 00485 { 00486 return QString::fromLatin1("crystalsvg"); 00487 } 00488 00489 /*** KIconThemeDir ***/ 00490 00491 KIconThemeDir::KIconThemeDir(const QString& dir, const KConfigBase *config) 00492 { 00493 mbValid = false; 00494 mDir = dir; 00495 mSize = config->readNumEntry("Size"); 00496 mMinSize = 1; // just set the variables to something 00497 mMaxSize = 50; // meaningful in case someone calls minSize or maxSize 00498 mType = KIcon::Fixed; 00499 00500 if (mSize == 0) 00501 return; 00502 00503 QString tmp = config->readEntry("Context"); 00504 if (tmp == "Devices") 00505 mContext = KIcon::Device; 00506 else if (tmp == "MimeTypes") 00507 mContext = KIcon::MimeType; 00508 else if (tmp == "FileSystems") 00509 mContext = KIcon::FileSystem; 00510 else if (tmp == "Applications") 00511 mContext = KIcon::Application; 00512 else if (tmp == "Actions") 00513 mContext = KIcon::Action; 00514 else { 00515 kdDebug(264) << "Invalid Context= line for icon theme: " << mDir << "\n"; 00516 return; 00517 } 00518 tmp = config->readEntry("Type"); 00519 if (tmp == "Fixed") 00520 mType = KIcon::Fixed; 00521 else if (tmp == "Scalable") 00522 mType = KIcon::Scalable; 00523 else if (tmp == "Threshold") 00524 mType = KIcon::Threshold; 00525 else { 00526 kdDebug(264) << "Invalid Type= line for icon theme: " << mDir << "\n"; 00527 return; 00528 } 00529 if (mType == KIcon::Scalable) 00530 { 00531 mMinSize = config->readNumEntry("MinSize", mSize); 00532 mMaxSize = config->readNumEntry("MaxSize", mSize); 00533 } else if (mType == KIcon::Threshold) 00534 mThreshold = config->readNumEntry("Threshold", 2); 00535 mbValid = true; 00536 } 00537 00538 QString KIconThemeDir::iconPath(const QString& name) const 00539 { 00540 if (!mbValid) 00541 return QString::null; 00542 QString file = mDir + "/" + name; 00543 00544 if (access(QFile::encodeName(file), R_OK) == 0) 00545 return file; 00546 00547 return QString::null; 00548 } 00549 00550 QStringList KIconThemeDir::iconList() const 00551 { 00552 QDir dir(mDir); 00553 #ifdef HAVE_LIBART 00554 QStringList lst = dir.entryList("*.png;*.svg;*.svgz;*.xpm", QDir::Files); 00555 #else 00556 QStringList lst = dir.entryList("*.png;*.xpm", QDir::Files); 00557 #endif 00558 QStringList result; 00559 QStringList::ConstIterator it; 00560 for (it=lst.begin(); it!=lst.end(); ++it) 00561 result += mDir + "/" + *it; 00562 return result; 00563 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 16 17:21:42 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003