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
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
00136
00137 d->sharedConfig = KSharedConfig::openConfig( fileName,
true ,
false );
00138
KConfig& cfg = *d->sharedConfig;
00139
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
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
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
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
00321
00322
00323
QStringList iconlist[128];
00324
00325
00326
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;
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
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
00390
00391
00392
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
00408
if (match == KIcon::MatchExact)
00409
return icon;
00410
else
00411 {
00412 delta = dw;
00413
if (delta==0)
return icon;
00414 }
00415 }
00416
return icon;
00417 }
00418
00419
00420
QString *KIconTheme::_theme = 0L;
00421
00422
00423
QStringList *KIconTheme::_theme_list = 0L;
00424
00425
00426 QString KIconTheme::current()
00427 {
00428
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
00438
00439
00440
00441
00442
00443
00444
return *_theme;
00445 }
00446
00447
00448 QStringList KIconTheme::list()
00449 {
00450
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
00481 void KIconTheme::reconfigure()
00482 {
00483
delete _theme;
00484 _theme=0L;
00485
delete _theme_list;
00486 _theme_list=0L;
00487 }
00488
00489
00490 QString KIconTheme::defaultThemeName()
00491 {
00492
return QString::fromLatin1(
"crystalsvg");
00493 }
00494
00495
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;
00503 mMaxSize = 50;
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 }