2
This source file is part of Konsole, a terminal emulator.
4
Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23
#include "ColorScheme.h"
36
//#include <KColorScheme>
40
//#include <KConfigGroup>
41
//#include <KStandardDirs>
43
using namespace Konsole;
45
const ColorEntry ColorScheme::defaultTable[TABLE_COLORS] =
46
// The following are almost IBM standard color codes, with some slight
47
// gamma correction for the dim colors to compensate for bright X screens.
48
// It contains the 8 ansiterm/xterm colors in 2 intensities.
50
ColorEntry( QColor(0x00,0x00,0x00), 0), ColorEntry(
51
QColor(0xFF,0xFF,0xFF), 1), // Dfore, Dback
52
ColorEntry( QColor(0x00,0x00,0x00), 0), ColorEntry(
53
QColor(0xB2,0x18,0x18), 0), // Black, Red
54
ColorEntry( QColor(0x18,0xB2,0x18), 0), ColorEntry(
55
QColor(0xB2,0x68,0x18), 0), // Green, Yellow
56
ColorEntry( QColor(0x18,0x18,0xB2), 0), ColorEntry(
57
QColor(0xB2,0x18,0xB2), 0), // Blue, Magenta
58
ColorEntry( QColor(0x18,0xB2,0xB2), 0), ColorEntry(
59
QColor(0xB2,0xB2,0xB2), 0), // Cyan, White
61
ColorEntry( QColor(0x00,0x00,0x00), 0), ColorEntry(
62
QColor(0xFF,0xFF,0xFF), 1),
63
ColorEntry( QColor(0x68,0x68,0x68), 0), ColorEntry(
64
QColor(0xFF,0x54,0x54), 0),
65
ColorEntry( QColor(0x54,0xFF,0x54), 0), ColorEntry(
66
QColor(0xFF,0xFF,0x54), 0),
67
ColorEntry( QColor(0x54,0x54,0xFF), 0), ColorEntry(
68
QColor(0xFF,0x54,0xFF), 0),
69
ColorEntry( QColor(0x54,0xFF,0xFF), 0), ColorEntry(
70
QColor(0xFF,0xFF,0xFF), 0)
73
const char* const ColorScheme::colorNames[TABLE_COLORS] =
96
// dummy silently comment out the tr_NOOP
98
const char* const ColorScheme::translatedColorNames[TABLE_COLORS] =
100
tr_NOOP("Foreground"),
101
tr_NOOP("Background"),
110
tr_NOOP("Foreground (Intense)"),
111
tr_NOOP("Background (Intense)"),
112
tr_NOOP("Color 1 (Intense)"),
113
tr_NOOP("Color 2 (Intense)"),
114
tr_NOOP("Color 3 (Intense)"),
115
tr_NOOP("Color 4 (Intense)"),
116
tr_NOOP("Color 5 (Intense)"),
117
tr_NOOP("Color 6 (Intense)"),
118
tr_NOOP("Color 7 (Intense)"),
119
tr_NOOP("Color 8 (Intense)")
122
ColorScheme::ColorScheme()
128
ColorScheme::ColorScheme(const ColorScheme& other)
129
: _opacity(other._opacity)
133
setName(other.name());
134
setDescription(other.description());
136
if ( other._table != 0 )
138
for ( int i = 0 ; i < TABLE_COLORS ; i++ )
139
setColorTableEntry(i,other._table[i]);
142
if ( other._randomTable != 0 )
144
for ( int i = 0 ; i < TABLE_COLORS ; i++ )
146
const RandomizationRange& range = other._randomTable[i];
147
setRandomizationRange(i,range.hue,range.saturation,range.value);
151
ColorScheme::~ColorScheme()
154
delete[] _randomTable;
157
void ColorScheme::setDescription(const QString& description) { _description = description; }
158
QString ColorScheme::description() const { return _description; }
160
void ColorScheme::setName(const QString& name) { _name = name; }
161
QString ColorScheme::name() const { return _name; }
163
void ColorScheme::setColorTableEntry(int index , const ColorEntry& entry)
165
Q_ASSERT( index >= 0 && index < TABLE_COLORS );
169
_table = new ColorEntry[TABLE_COLORS];
171
for (int i=0;i<TABLE_COLORS;i++)
172
_table[i] = defaultTable[i];
175
_table[index] = entry;
177
ColorEntry ColorScheme::colorEntry(int index , uint randomSeed) const
179
Q_ASSERT( index >= 0 && index < TABLE_COLORS );
181
if ( randomSeed != 0 )
184
ColorEntry entry = colorTable()[index];
186
if ( randomSeed != 0 &&
188
!_randomTable[index].isNull() )
190
const RandomizationRange& range = _randomTable[index];
193
int hueDifference = range.hue ? (qrand() % range.hue) - range.hue/2 : 0;
194
int saturationDifference = range.saturation ? (qrand() % range.saturation) - range.saturation/2 : 0;
195
int valueDifference = range.value ? (qrand() % range.value) - range.value/2 : 0;
197
QColor& color = entry.color;
199
int newHue = qAbs( (color.hue() + hueDifference) % MAX_HUE );
200
int newValue = qMin( qAbs(color.value() + valueDifference) , 255 );
201
int newSaturation = qMin( qAbs(color.saturation() + saturationDifference) , 255 );
203
color.setHsv(newHue,newSaturation,newValue);
208
void ColorScheme::getColorTable(ColorEntry* table , uint randomSeed) const
210
for ( int i = 0 ; i < TABLE_COLORS ; i++ )
211
table[i] = colorEntry(i,randomSeed);
213
bool ColorScheme::randomizedBackgroundColor() const
215
return _randomTable == 0 ? false : !_randomTable[1].isNull();
217
void ColorScheme::setRandomizedBackgroundColor(bool randomize)
219
// the hue of the background colour is allowed to be randomly
220
// adjusted as much as possible.
222
// the value and saturation are left alone to maintain read-ability
225
setRandomizationRange( 1 /* background color index */ , MAX_HUE , 255 , 0 );
230
setRandomizationRange( 1 /* background color index */ , 0 , 0 , 0 );
234
void ColorScheme::setRandomizationRange( int index , quint16 hue , quint8 saturation ,
237
Q_ASSERT( hue <= MAX_HUE );
238
Q_ASSERT( index >= 0 && index < TABLE_COLORS );
240
if ( _randomTable == 0 )
241
_randomTable = new RandomizationRange[TABLE_COLORS];
243
_randomTable[index].hue = hue;
244
_randomTable[index].value = value;
245
_randomTable[index].saturation = saturation;
248
const ColorEntry* ColorScheme::colorTable() const
255
QColor ColorScheme::foregroundColor() const
257
return colorTable()[0].color;
259
QColor ColorScheme::backgroundColor() const
261
return colorTable()[1].color;
263
bool ColorScheme::hasDarkBackground() const
265
// value can range from 0 - 255, with larger values indicating higher brightness.
266
// so 127 is in the middle, anything less is deemed 'dark'
267
return backgroundColor().value() < 127;
269
void ColorScheme::setOpacity(qreal opacity) { _opacity = opacity; }
270
qreal ColorScheme::opacity() const { return _opacity; }
272
void ColorScheme::read(const QString & fileName)
274
QSettings s(fileName, QSettings::IniFormat);
275
s.beginGroup("General");
277
_description = s.value("Description", QObject::tr("Un-named Color Scheme")).toString();
278
_opacity = s.value("Opacity",qreal(1.0)).toDouble();
281
for (int i=0 ; i < TABLE_COLORS ; i++)
283
readColorEntry(&s, i);
287
// implemented upstream - user apps
288
void ColorScheme::read(KConfig& config)
290
KConfigGroup configGroup = config.group("General");
292
QString description = configGroup.readEntry("Description", QObject::tr("Un-named Color Scheme"));
294
_description = tr(description.toUtf8());
295
_opacity = configGroup.readEntry("Opacity",qreal(1.0));
297
for (int i=0 ; i < TABLE_COLORS ; i++)
299
readColorEntry(config,i);
302
void ColorScheme::write(KConfig& config) const
304
KConfigGroup configGroup = config.group("General");
306
configGroup.writeEntry("Description",_description);
307
configGroup.writeEntry("Opacity",_opacity);
309
for (int i=0 ; i < TABLE_COLORS ; i++)
311
RandomizationRange random = _randomTable != 0 ? _randomTable[i] : RandomizationRange();
312
writeColorEntry(config,colorNameForIndex(i),colorTable()[i],random);
317
QString ColorScheme::colorNameForIndex(int index)
319
Q_ASSERT( index >= 0 && index < TABLE_COLORS );
321
return QString(colorNames[index]);
323
QString ColorScheme::translatedColorNameForIndex(int index)
325
Q_ASSERT( index >= 0 && index < TABLE_COLORS );
327
return translatedColorNames[index];
330
void ColorScheme::readColorEntry(QSettings * s , int index)
332
s->beginGroup(colorNameForIndex(index));
336
QStringList rgbList = s->value("Color", QStringList()).toStringList();
337
if (rgbList.count() != 3)
342
r = rgbList[0].toInt();
343
g = rgbList[1].toInt();
344
b = rgbList[2].toInt();
345
entry.color = QColor(r, g, b);
347
entry.transparent = s->value("Transparent",false).toBool();
349
// Deprecated key from KDE 4.0 which set 'Bold' to true to force
350
// a color to be bold or false to use the current format
352
// TODO - Add a new tri-state key which allows for bold, normal or
354
if (s->contains("Bold"))
355
entry.fontWeight = s->value("Bold",false).toBool() ? ColorEntry::Bold :
356
ColorEntry::UseCurrentFormat;
358
quint16 hue = s->value("MaxRandomHue",0).toInt();
359
quint8 value = s->value("MaxRandomValue",0).toInt();
360
quint8 saturation = s->value("MaxRandomSaturation",0).toInt();
362
setColorTableEntry( index , entry );
364
if ( hue != 0 || value != 0 || saturation != 0 )
365
setRandomizationRange( index , hue , saturation , value );
370
// implemented upstream - user apps
371
void ColorScheme::writeColorEntry(KConfig& config , const QString& colorName, const ColorEntry& entry , const RandomizationRange& random) const
373
KConfigGroup configGroup(&config,colorName);
375
configGroup.writeEntry("Color",entry.color);
376
configGroup.writeEntry("Transparency",(bool)entry.transparent);
377
if (entry.fontWeight != ColorEntry::UseCurrentFormat)
379
configGroup.writeEntry("Bold",entry.fontWeight == ColorEntry::Bold);
382
// record randomization if this color has randomization or
383
// if one of the keys already exists
384
if ( !random.isNull() || configGroup.hasKey("MaxRandomHue") )
386
configGroup.writeEntry("MaxRandomHue",(int)random.hue);
387
configGroup.writeEntry("MaxRandomValue",(int)random.value);
388
configGroup.writeEntry("MaxRandomSaturation",(int)random.saturation);
394
// Work In Progress - A color scheme for use on KDE setups for users
395
// with visual disabilities which means that they may have trouble
396
// reading text with the supplied color schemes.
398
// This color scheme uses only the 'safe' colors defined by the
399
// KColorScheme class.
401
// A complication this introduces is that each color provided by
402
// KColorScheme is defined as a 'background' or 'foreground' color.
403
// Only foreground colors are allowed to be used to render text and
404
// only background colors are allowed to be used for backgrounds.
406
// The ColorEntry and TerminalDisplay classes do not currently
407
// support this restriction.
410
// - A color scheme which uses only colors from the KColorScheme class
411
// - Ability to restrict which colors the TerminalDisplay widget
412
// uses as foreground and background color
413
// - Make use of KGlobalSettings::allowDefaultBackgroundImages() as
414
// a hint to determine whether this accessible color scheme should
415
// be used by default.
418
// -- Robert Knight <robertknight@gmail.com> 21/07/2007
420
AccessibleColorScheme::AccessibleColorScheme()
424
// It's not finished in konsole and it breaks Qt4 compilation as well
426
setName("accessible");
427
setDescription(QObject::tr("Accessible Color Scheme"));
430
const int ColorRoleCount = 8;
432
const KColorScheme colorScheme(QPalette::Active);
434
QBrush colors[ColorRoleCount] =
436
colorScheme.foreground( colorScheme.NormalText ),
437
colorScheme.background( colorScheme.NormalBackground ),
439
colorScheme.foreground( colorScheme.InactiveText ),
440
colorScheme.foreground( colorScheme.ActiveText ),
441
colorScheme.foreground( colorScheme.LinkText ),
442
colorScheme.foreground( colorScheme.VisitedText ),
443
colorScheme.foreground( colorScheme.NegativeText ),
444
colorScheme.foreground( colorScheme.NeutralText )
447
for ( int i = 0 ; i < TABLE_COLORS ; i++ )
450
entry.color = colors[ i % ColorRoleCount ].color();
452
setColorTableEntry( i , entry );
457
KDE3ColorSchemeReader::KDE3ColorSchemeReader( QIODevice* device ) :
461
ColorScheme* KDE3ColorSchemeReader::read()
463
Q_ASSERT( _device->openMode() == QIODevice::ReadOnly ||
464
_device->openMode() == QIODevice::ReadWrite );
466
ColorScheme* scheme = new ColorScheme();
468
QRegExp comment("#.*$");
469
while ( !_device->atEnd() )
471
QString line(_device->readLine());
472
line.remove(comment);
473
line = line.simplified();
475
if ( line.isEmpty() )
478
if ( line.startsWith(QLatin1String("color")) )
480
if (!readColorLine(line,scheme))
481
qDebug() << "Failed to read KDE 3 color scheme line" << line;
483
else if ( line.startsWith(QLatin1String("title")) )
485
if (!readTitleLine(line,scheme))
486
qDebug() << "Failed to read KDE 3 color scheme title line" << line;
490
qDebug() << "KDE 3 color scheme contains an unsupported feature, '" <<
497
bool KDE3ColorSchemeReader::readColorLine(const QString& line,ColorScheme* scheme)
499
QStringList list = line.split(QChar(' '));
501
if (list.count() != 7)
503
if (list.first() != "color")
506
int index = list[1].toInt();
507
int red = list[2].toInt();
508
int green = list[3].toInt();
509
int blue = list[4].toInt();
510
int transparent = list[5].toInt();
511
int bold = list[6].toInt();
513
const int MAX_COLOR_VALUE = 255;
515
if( (index < 0 || index >= TABLE_COLORS )
516
|| (red < 0 || red > MAX_COLOR_VALUE )
517
|| (blue < 0 || blue > MAX_COLOR_VALUE )
518
|| (green < 0 || green > MAX_COLOR_VALUE )
519
|| (transparent != 0 && transparent != 1 )
520
|| (bold != 0 && bold != 1) )
524
entry.color = QColor(red,green,blue);
525
entry.transparent = ( transparent != 0 );
526
entry.fontWeight = ( bold != 0 ) ? ColorEntry::Bold : ColorEntry::UseCurrentFormat;
528
scheme->setColorTableEntry(index,entry);
531
bool KDE3ColorSchemeReader::readTitleLine(const QString& line,ColorScheme* scheme)
533
if( !line.startsWith(QLatin1String("title")) )
536
int spacePos = line.indexOf(' ');
540
QString description = line.mid(spacePos+1);
542
scheme->setDescription(description.toUtf8());
545
ColorSchemeManager::ColorSchemeManager()
546
: _haveLoadedAll(false)
549
ColorSchemeManager::~ColorSchemeManager()
551
QHashIterator<QString,const ColorScheme*> iter(_colorSchemes);
552
while (iter.hasNext())
558
void ColorSchemeManager::loadAllColorSchemes()
560
qDebug() << "loadAllColorSchemes";
564
QList<QString> nativeColorSchemes = listColorSchemes();
566
QListIterator<QString> nativeIter(nativeColorSchemes);
567
while ( nativeIter.hasNext() )
569
if ( loadColorScheme( nativeIter.next() ) )
575
QList<QString> kde3ColorSchemes = listKDE3ColorSchemes();
576
QListIterator<QString> kde3Iter(kde3ColorSchemes);
577
while ( kde3Iter.hasNext() )
579
if ( loadKDE3ColorScheme( kde3Iter.next() ) )
586
qDebug() << "failed to load " << failed << " color schemes.";
588
_haveLoadedAll = true;
590
QList<const ColorScheme*> ColorSchemeManager::allColorSchemes()
592
if ( !_haveLoadedAll )
594
loadAllColorSchemes();
597
return _colorSchemes.values();
599
bool ColorSchemeManager::loadKDE3ColorScheme(const QString& filePath)
601
QFile file(filePath);
602
if (!filePath.endsWith(QLatin1String(".schema")) || !file.open(QIODevice::ReadOnly))
605
KDE3ColorSchemeReader reader(&file);
606
ColorScheme* scheme = reader.read();
607
scheme->setName(QFileInfo(file).baseName());
610
if (scheme->name().isEmpty())
612
qDebug() << "color scheme name is not valid.";
617
QFileInfo info(filePath);
619
if ( !_colorSchemes.contains(info.baseName()) )
620
_colorSchemes.insert(scheme->name(),scheme);
623
qDebug() << "color scheme with name" << scheme->name() << "has already been" <<
631
void ColorSchemeManager::addColorScheme(ColorScheme* scheme)
633
_colorSchemes.insert(scheme->name(),scheme);
635
// save changes to disk
636
QString path = KGlobal::dirs()->saveLocation("data","konsole/") + scheme->name() + ".colorscheme";
637
KConfig config(path , KConfig::NoGlobals);
639
scheme->write(config);
643
bool ColorSchemeManager::loadCustomColorScheme(const QString& path)
645
if (path.endsWith(QLatin1String(".colorscheme")))
646
return loadColorScheme(path);
647
else if (path.endsWith(QLatin1String(".schema")))
648
return loadKDE3ColorScheme(path);
653
bool ColorSchemeManager::loadColorScheme(const QString& filePath)
655
if ( !filePath.endsWith(QLatin1String(".colorscheme")) || !QFile::exists(filePath) )
658
QFileInfo info(filePath);
660
const QString& schemeName = info.baseName();
662
ColorScheme* scheme = new ColorScheme();
663
scheme->setName(schemeName);
664
scheme->read(filePath);
666
if (scheme->name().isEmpty())
668
qDebug() << "Color scheme in" << filePath << "does not have a valid name and was not loaded.";
673
if ( !_colorSchemes.contains(schemeName) )
675
_colorSchemes.insert(schemeName,scheme);
679
qDebug() << "color scheme with name" << schemeName << "has already been" <<
687
QList<QString> ColorSchemeManager::listKDE3ColorSchemes()
689
QString dname(get_color_schemes_dir());
692
filters << "*.schema";
693
dir.setNameFilters(filters);
694
QStringList list = dir.entryList(filters);
696
foreach(QString i, list)
697
ret << dname + "/" + i;
699
//return KGlobal::dirs()->findAllResources("data",
700
// "konsole/*.schema",
701
// KStandardDirs::NoDuplicates);
704
QList<QString> ColorSchemeManager::listColorSchemes()
706
QString dname(get_color_schemes_dir());
709
filters << "*.colorscheme";
710
dir.setNameFilters(filters);
711
QStringList list = dir.entryList(filters);
713
foreach(QString i, list)
714
ret << dname + "/" + i;
716
// return KGlobal::dirs()->findAllResources("data",
717
// "konsole/*.colorscheme",
718
// KStandardDirs::NoDuplicates);
720
const ColorScheme ColorSchemeManager::_defaultColorScheme;
721
const ColorScheme* ColorSchemeManager::defaultColorScheme() const
723
return &_defaultColorScheme;
725
bool ColorSchemeManager::deleteColorScheme(const QString& name)
727
Q_ASSERT( _colorSchemes.contains(name) );
729
// lookup the path and delete
730
QString path = findColorSchemePath(name);
731
if ( QFile::remove(path) )
733
_colorSchemes.remove(name);
738
qDebug() << "Failed to remove color scheme -" << path;
742
QString ColorSchemeManager::findColorSchemePath(const QString& name) const
744
// QString path = KStandardDirs::locate("data","konsole/"+name+".colorscheme");
745
QString path(get_color_schemes_dir() + "/"+ name + ".colorscheme");
746
if ( !path.isEmpty() )
749
//path = KStandardDirs::locate("data","konsole/"+name+".schema");
750
path = get_color_schemes_dir() + "/"+ name + ".schema";
754
const ColorScheme* ColorSchemeManager::findColorScheme(const QString& name)
756
if ( name.isEmpty() )
757
return defaultColorScheme();
759
if ( _colorSchemes.contains(name) )
760
return _colorSchemes[name];
763
// look for this color scheme
764
QString path = findColorSchemePath(name);
765
if ( !path.isEmpty() && loadColorScheme(path) )
767
return findColorScheme(name);
771
if (!path.isEmpty() && loadKDE3ColorScheme(path))
772
return findColorScheme(name);
775
qDebug() << "Could not find color scheme - " << name;
781
ColorSchemeManager* ColorSchemeManager::theColorSchemeManager = 0;
782
//K_GLOBAL_STATIC( ColorSchemeManager , theColorSchemeManager )
783
ColorSchemeManager* ColorSchemeManager::instance()
785
if (! theColorSchemeManager)
786
theColorSchemeManager = new ColorSchemeManager();
787
return theColorSchemeManager;