kdecore Library API Documentation

kicontheme.cpp

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