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 };
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
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
00091
00092
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
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
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
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
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
00315
00316
00317
QStringList iconlist[128];
00318
00319
00320
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;
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
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
00384
00385
00386
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
00402
if (match == KIcon::MatchExact)
00403
return icon;
00404
else
00405 {
00406 delta = dw;
00407
if (delta==0)
return icon;
00408 }
00409 }
00410
return icon;
00411 }
00412
00413
00414
QString *KIconTheme::_theme = 0L;
00415
00416
00417
QStringList *KIconTheme::_theme_list = 0L;
00418
00419
00420 QString KIconTheme::current()
00421 {
00422
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
00432
00433
00434
00435
00436
00437
00438
return *_theme;
00439 }
00440
00441
00442 QStringList KIconTheme::list()
00443 {
00444
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
00475 void KIconTheme::reconfigure()
00476 {
00477
delete _theme;
00478 _theme=0L;
00479
delete _theme_list;
00480 _theme_list=0L;
00481 }
00482
00483
00484 QString KIconTheme::defaultThemeName()
00485 {
00486
return QString::fromLatin1(
"crystalsvg");
00487 }
00488
00489
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;
00497 mMaxSize = 50;
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 }