00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "ColorScheme.h"
00024
00025
00026 #include <QtGui/QBrush>
00027 #include <QtCore/QFile>
00028 #include <QtCore/QFileInfo>
00029
00030
00031 #include <KColorScheme>
00032 #include <KConfig>
00033 #include <KLocale>
00034 #include <KDebug>
00035 #include <KConfigGroup>
00036 #include <KStandardDirs>
00037
00038 using namespace Konsole;
00039
00040 const ColorEntry ColorScheme::defaultTable[TABLE_COLORS] =
00041
00042
00043
00044 {
00045 ColorEntry( QColor(0x00,0x00,0x00), 0), ColorEntry(
00046 QColor(0xFF,0xFF,0xFF), 1),
00047 ColorEntry( QColor(0x00,0x00,0x00), 0), ColorEntry(
00048 QColor(0xB2,0x18,0x18), 0),
00049 ColorEntry( QColor(0x18,0xB2,0x18), 0), ColorEntry(
00050 QColor(0xB2,0x68,0x18), 0),
00051 ColorEntry( QColor(0x18,0x18,0xB2), 0), ColorEntry(
00052 QColor(0xB2,0x18,0xB2), 0),
00053 ColorEntry( QColor(0x18,0xB2,0xB2), 0), ColorEntry(
00054 QColor(0xB2,0xB2,0xB2), 0),
00055
00056 ColorEntry( QColor(0x00,0x00,0x00), 0), ColorEntry(
00057 QColor(0xFF,0xFF,0xFF), 1),
00058 ColorEntry( QColor(0x68,0x68,0x68), 0), ColorEntry(
00059 QColor(0xFF,0x54,0x54), 0),
00060 ColorEntry( QColor(0x54,0xFF,0x54), 0), ColorEntry(
00061 QColor(0xFF,0xFF,0x54), 0),
00062 ColorEntry( QColor(0x54,0x54,0xFF), 0), ColorEntry(
00063 QColor(0xFF,0x54,0xFF), 0),
00064 ColorEntry( QColor(0x54,0xFF,0xFF), 0), ColorEntry(
00065 QColor(0xFF,0xFF,0xFF), 0)
00066 };
00067
00068 const char* ColorScheme::colorNames[TABLE_COLORS] =
00069 {
00070 "Foreground",
00071 "Background",
00072 "Color0",
00073 "Color1",
00074 "Color2",
00075 "Color3",
00076 "Color4",
00077 "Color5",
00078 "Color6",
00079 "Color7",
00080 "ForegroundIntense",
00081 "BackgroundIntense",
00082 "Color0Intense",
00083 "Color1Intense",
00084 "Color2Intense",
00085 "Color3Intense",
00086 "Color4Intense",
00087 "Color5Intense",
00088 "Color6Intense",
00089 "Color7Intense"
00090 };
00091 const char* ColorScheme::translatedColorNames[TABLE_COLORS] =
00092 {
00093 I18N_NOOP("Foreground"),
00094 I18N_NOOP("Background"),
00095 I18N_NOOP("Color 1"),
00096 I18N_NOOP("Color 2"),
00097 I18N_NOOP("Color 3"),
00098 I18N_NOOP("Color 4"),
00099 I18N_NOOP("Color 5"),
00100 I18N_NOOP("Color 6"),
00101 I18N_NOOP("Color 7"),
00102 I18N_NOOP("Color 8"),
00103 I18N_NOOP("Foreground (Intense)"),
00104 I18N_NOOP("Background (Intense)"),
00105 I18N_NOOP("Color 1 (Intense)"),
00106 I18N_NOOP("Color 2 (Intense)"),
00107 I18N_NOOP("Color 3 (Intense)"),
00108 I18N_NOOP("Color 4 (Intense)"),
00109 I18N_NOOP("Color 5 (Intense)"),
00110 I18N_NOOP("Color 6 (Intense)"),
00111 I18N_NOOP("Color 7 (Intense)"),
00112 I18N_NOOP("Color 8 (Intense)")
00113 };
00114
00115 ColorScheme::ColorScheme()
00116 {
00117 _table = 0;
00118 _randomTable = 0;
00119 _opacity = 1.0;
00120 }
00121 ColorScheme::ColorScheme(const ColorScheme& other)
00122 : _opacity(other._opacity)
00123 ,_table(0)
00124 ,_randomTable(0)
00125 {
00126 setName(other.name());
00127 setDescription(other.description());
00128
00129 if ( other._table != 0 )
00130 {
00131 for ( int i = 0 ; i < TABLE_COLORS ; i++ )
00132 setColorTableEntry(i,other._table[i]);
00133 }
00134
00135 if ( other._randomTable != 0 )
00136 {
00137 for ( int i = 0 ; i < TABLE_COLORS ; i++ )
00138 {
00139 const RandomizationRange& range = other._randomTable[i];
00140 setRandomizationRange(i,range.hue,range.saturation,range.value);
00141 }
00142 }
00143 }
00144 ColorScheme::~ColorScheme()
00145 {
00146 delete[] _table;
00147 delete[] _randomTable;
00148 }
00149
00150 void ColorScheme::setDescription(const QString& description) { _description = description; }
00151 QString ColorScheme::description() const { return _description; }
00152
00153 void ColorScheme::setName(const QString& name) { _name = name; }
00154 QString ColorScheme::name() const { return _name; }
00155
00156 void ColorScheme::setColorTableEntry(int index , const ColorEntry& entry)
00157 {
00158 Q_ASSERT( index >= 0 && index < TABLE_COLORS );
00159
00160 if ( !_table )
00161 {
00162 _table = new ColorEntry[TABLE_COLORS];
00163
00164 for (int i=0;i<TABLE_COLORS;i++)
00165 _table[i] = defaultTable[i];
00166 }
00167
00168 _table[index] = entry;
00169 }
00170 ColorEntry ColorScheme::colorEntry(int index , uint randomSeed) const
00171 {
00172 Q_ASSERT( index >= 0 && index < TABLE_COLORS );
00173
00174 if ( randomSeed != 0 )
00175 qsrand(randomSeed);
00176
00177 ColorEntry entry = colorTable()[index];
00178
00179 if ( randomSeed != 0 &&
00180 _randomTable != 0 &&
00181 !_randomTable[index].isNull() )
00182 {
00183 const RandomizationRange& range = _randomTable[index];
00184
00185
00186 int hueDifference = range.hue ? (qrand() % range.hue) - range.hue/2 : 0;
00187 int saturationDifference = range.saturation ? (qrand() % range.saturation) - range.saturation/2 : 0;
00188 int valueDifference = range.value ? (qrand() % range.value) - range.value/2 : 0;
00189
00190 QColor& color = entry.color;
00191
00192 int newHue = qAbs( (color.hue() + hueDifference) % MAX_HUE );
00193 int newValue = qMin( qAbs(color.value() + valueDifference) , 255 );
00194 int newSaturation = qMin( qAbs(color.saturation() + saturationDifference) , 255 );
00195
00196 color.setHsv(newHue,newSaturation,newValue);
00197 }
00198
00199 return entry;
00200 }
00201 void ColorScheme::getColorTable(ColorEntry* table , uint randomSeed) const
00202 {
00203 for ( int i = 0 ; i < TABLE_COLORS ; i++ )
00204 table[i] = colorEntry(i,randomSeed);
00205 }
00206 bool ColorScheme::randomizedBackgroundColor() const
00207 {
00208 return _randomTable == 0 ? false : !_randomTable[1].isNull();
00209 }
00210 void ColorScheme::setRandomizedBackgroundColor(bool randomize)
00211 {
00212
00213
00214
00215
00216 if ( randomize )
00217 {
00218 setRandomizationRange( 1 , MAX_HUE , 255 , 0 );
00219 }
00220 else
00221 {
00222 if ( _randomTable )
00223 setRandomizationRange( 1 , 0 , 0 , 0 );
00224 }
00225 }
00226
00227 void ColorScheme::setRandomizationRange( int index , quint16 hue , quint8 saturation ,
00228 quint8 value )
00229 {
00230 Q_ASSERT( hue <= MAX_HUE );
00231 Q_ASSERT( index >= 0 && index < TABLE_COLORS );
00232
00233 if ( _randomTable == 0 )
00234 _randomTable = new RandomizationRange[TABLE_COLORS];
00235
00236 _randomTable[index].hue = hue;
00237 _randomTable[index].value = value;
00238 _randomTable[index].saturation = saturation;
00239 }
00240
00241 const ColorEntry* ColorScheme::colorTable() const
00242 {
00243 if ( _table )
00244 return _table;
00245 else
00246 return defaultTable;
00247 }
00248 QColor ColorScheme::foregroundColor() const
00249 {
00250 return colorTable()[0].color;
00251 }
00252 QColor ColorScheme::backgroundColor() const
00253 {
00254 return colorTable()[1].color;
00255 }
00256 bool ColorScheme::hasDarkBackground() const
00257 {
00258
00259
00260 return backgroundColor().value() < 127;
00261 }
00262 void ColorScheme::setOpacity(qreal opacity) { _opacity = opacity; }
00263 qreal ColorScheme::opacity() const { return _opacity; }
00264
00265 void ColorScheme::read(KConfig& config)
00266 {
00267 KConfigGroup configGroup = config.group("General");
00268
00269 QString description = configGroup.readEntry("Description", I18N_NOOP("Un-named Color Scheme"));
00270
00271 _description = i18n(description.toUtf8());
00272 _opacity = configGroup.readEntry("Opacity",qreal(1.0));
00273
00274 for (int i=0 ; i < TABLE_COLORS ; i++)
00275 {
00276 readColorEntry(config,i);
00277 }
00278 }
00279 void ColorScheme::write(KConfig& config) const
00280 {
00281 KConfigGroup configGroup = config.group("General");
00282
00283 configGroup.writeEntry("Description",_description);
00284 configGroup.writeEntry("Opacity",_opacity);
00285
00286 for (int i=0 ; i < TABLE_COLORS ; i++)
00287 {
00288 RandomizationRange random = _randomTable != 0 ? _randomTable[i] : RandomizationRange();
00289 writeColorEntry(config,colorNameForIndex(i),colorTable()[i],random);
00290 }
00291 }
00292
00293 QString ColorScheme::colorNameForIndex(int index)
00294 {
00295 Q_ASSERT( index >= 0 && index < TABLE_COLORS );
00296
00297 return QString(colorNames[index]);
00298 }
00299 QString ColorScheme::translatedColorNameForIndex(int index)
00300 {
00301 Q_ASSERT( index >= 0 && index < TABLE_COLORS );
00302
00303 return i18n(translatedColorNames[index]);
00304 }
00305 void ColorScheme::readColorEntry(KConfig& config , int index)
00306 {
00307 KConfigGroup configGroup(&config,colorNameForIndex(index));
00308
00309 ColorEntry entry;
00310
00311 entry.color = configGroup.readEntry("Color",QColor());
00312 entry.transparent = configGroup.readEntry("Transparent",false);
00313
00314
00315
00316
00317
00318
00319 if (configGroup.hasKey("Bold"))
00320 entry.fontWeight = configGroup.readEntry("Bold",false) ? ColorEntry::Bold :
00321 ColorEntry::UseCurrentFormat;
00322
00323 quint16 hue = configGroup.readEntry("MaxRandomHue",0);
00324 quint8 value = configGroup.readEntry("MaxRandomValue",0);
00325 quint8 saturation = configGroup.readEntry("MaxRandomSaturation",0);
00326
00327 setColorTableEntry( index , entry );
00328
00329 if ( hue != 0 || value != 0 || saturation != 0 )
00330 setRandomizationRange( index , hue , saturation , value );
00331 }
00332 void ColorScheme::writeColorEntry(KConfig& config , const QString& colorName, const ColorEntry& entry , const RandomizationRange& random) const
00333 {
00334 KConfigGroup configGroup(&config,colorName);
00335
00336 configGroup.writeEntry("Color",entry.color);
00337 configGroup.writeEntry("Transparency",(bool)entry.transparent);
00338 if (entry.fontWeight != ColorEntry::UseCurrentFormat)
00339 {
00340 configGroup.writeEntry("Bold",entry.fontWeight == ColorEntry::Bold);
00341 }
00342
00343
00344
00345 if ( !random.isNull() || configGroup.hasKey("MaxRandomHue") )
00346 {
00347 configGroup.writeEntry("MaxRandomHue",(int)random.hue);
00348 configGroup.writeEntry("MaxRandomValue",(int)random.value);
00349 configGroup.writeEntry("MaxRandomSaturation",(int)random.saturation);
00350 }
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 AccessibleColorScheme::AccessibleColorScheme()
00382 : ColorScheme()
00383 {
00384
00385 setName("accessible");
00386 setDescription(i18n("Accessible Color Scheme"));
00387
00388
00389 const int ColorRoleCount = 8;
00390
00391 const KColorScheme colorScheme(QPalette::Active);
00392
00393 QBrush colors[ColorRoleCount] =
00394 {
00395 colorScheme.foreground( colorScheme.NormalText ),
00396 colorScheme.background( colorScheme.NormalBackground ),
00397
00398 colorScheme.foreground( colorScheme.InactiveText ),
00399 colorScheme.foreground( colorScheme.ActiveText ),
00400 colorScheme.foreground( colorScheme.LinkText ),
00401 colorScheme.foreground( colorScheme.VisitedText ),
00402 colorScheme.foreground( colorScheme.NegativeText ),
00403 colorScheme.foreground( colorScheme.NeutralText )
00404 };
00405
00406 for ( int i = 0 ; i < TABLE_COLORS ; i++ )
00407 {
00408 ColorEntry entry;
00409 entry.color = colors[ i % ColorRoleCount ].color();
00410
00411 setColorTableEntry( i , entry );
00412 }
00413 }
00414
00415 KDE3ColorSchemeReader::KDE3ColorSchemeReader( QIODevice* device ) :
00416 _device(device)
00417 {
00418 }
00419 ColorScheme* KDE3ColorSchemeReader::read()
00420 {
00421 Q_ASSERT( _device->openMode() == QIODevice::ReadOnly ||
00422 _device->openMode() == QIODevice::ReadWrite );
00423
00424 ColorScheme* scheme = new ColorScheme();
00425
00426 QRegExp comment("#.*$");
00427 while ( !_device->atEnd() )
00428 {
00429 QString line(_device->readLine());
00430 line.replace(comment,QString());
00431 line = line.simplified();
00432
00433 if ( line.isEmpty() )
00434 continue;
00435
00436 if ( line.startsWith("color") )
00437 {
00438 if (!readColorLine(line,scheme))
00439 kWarning() << "Failed to read KDE 3 color scheme line" << line;
00440 }
00441 else if ( line.startsWith("title") )
00442 {
00443 if (!readTitleLine(line,scheme))
00444 kWarning() << "Failed to read KDE 3 color scheme title line" << line;
00445 }
00446 else
00447 {
00448 kWarning() << "KDE 3 color scheme contains an unsupported feature, '" <<
00449 line << "'";
00450 }
00451 }
00452
00453 return scheme;
00454 }
00455 bool KDE3ColorSchemeReader::readColorLine(const QString& line,ColorScheme* scheme)
00456 {
00457 QStringList list = line.split(QChar(' '));
00458
00459 if (list.count() != 7)
00460 return false;
00461 if (list.first() != "color")
00462 return false;
00463
00464 int index = list[1].toInt();
00465 int red = list[2].toInt();
00466 int green = list[3].toInt();
00467 int blue = list[4].toInt();
00468 int transparent = list[5].toInt();
00469 int bold = list[6].toInt();
00470
00471 const int MAX_COLOR_VALUE = 255;
00472
00473 if( (index < 0 || index >= TABLE_COLORS )
00474 || (red < 0 || red > MAX_COLOR_VALUE )
00475 || (blue < 0 || blue > MAX_COLOR_VALUE )
00476 || (green < 0 || green > MAX_COLOR_VALUE )
00477 || (transparent != 0 && transparent != 1 )
00478 || (bold != 0 && bold != 1) )
00479 return false;
00480
00481 ColorEntry entry;
00482 entry.color = QColor(red,green,blue);
00483 entry.transparent = ( transparent != 0 );
00484 entry.fontWeight = ( bold != 0 ) ? ColorEntry::Bold : ColorEntry::UseCurrentFormat;
00485
00486 scheme->setColorTableEntry(index,entry);
00487 return true;
00488 }
00489 bool KDE3ColorSchemeReader::readTitleLine(const QString& line,ColorScheme* scheme)
00490 {
00491 if( !line.startsWith("title") )
00492 return false;
00493
00494 int spacePos = line.indexOf(' ');
00495 if( spacePos == -1 )
00496 return false;
00497
00498 QString description = line.mid(spacePos+1);
00499
00500 scheme->setDescription(i18n(description.toUtf8()));
00501 return true;
00502 }
00503 ColorSchemeManager::ColorSchemeManager()
00504 : _haveLoadedAll(false)
00505 {
00506 }
00507 ColorSchemeManager::~ColorSchemeManager()
00508 {
00509 QHashIterator<QString,const ColorScheme*> iter(_colorSchemes);
00510 while (iter.hasNext())
00511 {
00512 iter.next();
00513 delete iter.value();
00514 }
00515 }
00516 void ColorSchemeManager::loadAllColorSchemes()
00517 {
00518 int success = 0;
00519 int failed = 0;
00520
00521 QList<QString> nativeColorSchemes = listColorSchemes();
00522
00523 QListIterator<QString> nativeIter(nativeColorSchemes);
00524 while ( nativeIter.hasNext() )
00525 {
00526 if ( loadColorScheme( nativeIter.next() ) )
00527 success++;
00528 else
00529 failed++;
00530 }
00531
00532 QList<QString> kde3ColorSchemes = listKDE3ColorSchemes();
00533 QListIterator<QString> kde3Iter(kde3ColorSchemes);
00534 while ( kde3Iter.hasNext() )
00535 {
00536 if ( loadKDE3ColorScheme( kde3Iter.next() ) )
00537 success++;
00538 else
00539 failed++;
00540 }
00541
00542 if ( failed > 0 )
00543 kWarning() << "failed to load " << failed << " color schemes.";
00544
00545 _haveLoadedAll = true;
00546 }
00547 QList<const ColorScheme*> ColorSchemeManager::allColorSchemes()
00548 {
00549 if ( !_haveLoadedAll )
00550 {
00551 loadAllColorSchemes();
00552 }
00553
00554 return _colorSchemes.values();
00555 }
00556 bool ColorSchemeManager::loadKDE3ColorScheme(const QString& filePath)
00557 {
00558 QFile file(filePath);
00559 if (!filePath.endsWith(".schema") || !file.open(QIODevice::ReadOnly))
00560 return false;
00561
00562 KDE3ColorSchemeReader reader(&file);
00563 ColorScheme* scheme = reader.read();
00564 scheme->setName(QFileInfo(file).baseName());
00565 file.close();
00566
00567 if (scheme->name().isEmpty())
00568 {
00569 kWarning() << "color scheme name is not valid.";
00570 delete scheme;
00571 return false;
00572 }
00573
00574 QFileInfo info(filePath);
00575
00576 if ( !_colorSchemes.contains(info.baseName()) )
00577 _colorSchemes.insert(scheme->name(),scheme);
00578 else
00579 {
00580 kDebug() << "color scheme with name" << scheme->name() << "has already been" <<
00581 "found, ignoring.";
00582 delete scheme;
00583 }
00584
00585 return true;
00586 }
00587 void ColorSchemeManager::addColorScheme(ColorScheme* scheme)
00588 {
00589 _colorSchemes.insert(scheme->name(),scheme);
00590
00591
00592 QString path = KGlobal::dirs()->saveLocation("data","konsole/") + scheme->name() + ".colorscheme";
00593 KConfig config(path , KConfig::NoGlobals);
00594
00595 scheme->write(config);
00596 }
00597 bool ColorSchemeManager::loadColorScheme(const QString& filePath)
00598 {
00599 if ( !filePath.endsWith(".colorscheme") || !QFile::exists(filePath) )
00600 return false;
00601
00602 QFileInfo info(filePath);
00603
00604 KConfig config(filePath , KConfig::NoGlobals);
00605 ColorScheme* scheme = new ColorScheme();
00606 scheme->setName(info.baseName());
00607 scheme->read(config);
00608
00609 if (scheme->name().isEmpty())
00610 {
00611 kWarning() << "Color scheme in" << filePath << "does not have a valid name and was not loaded.";
00612 delete scheme;
00613 return false;
00614 }
00615
00616 if ( !_colorSchemes.contains(info.baseName()) )
00617 {
00618 _colorSchemes.insert(scheme->name(),scheme);
00619 }
00620 else
00621 {
00622 kDebug() << "color scheme with name" << scheme->name() << "has already been" <<
00623 "found, ignoring.";
00624
00625 delete scheme;
00626 }
00627
00628 return true;
00629 }
00630 QList<QString> ColorSchemeManager::listKDE3ColorSchemes()
00631 {
00632 return KGlobal::dirs()->findAllResources("data",
00633 "konsole/*.schema",
00634 KStandardDirs::NoDuplicates);
00635
00636 }
00637 QList<QString> ColorSchemeManager::listColorSchemes()
00638 {
00639 return KGlobal::dirs()->findAllResources("data",
00640 "konsole/*.colorscheme",
00641 KStandardDirs::NoDuplicates);
00642 }
00643 const ColorScheme ColorSchemeManager::_defaultColorScheme;
00644 const ColorScheme* ColorSchemeManager::defaultColorScheme() const
00645 {
00646 return &_defaultColorScheme;
00647 }
00648 bool ColorSchemeManager::deleteColorScheme(const QString& name)
00649 {
00650 Q_ASSERT( _colorSchemes.contains(name) );
00651
00652
00653 QString path = findColorSchemePath(name);
00654 if ( QFile::remove(path) )
00655 {
00656 _colorSchemes.remove(name);
00657 return true;
00658 }
00659 else
00660 {
00661 kWarning() << "Failed to remove color scheme -" << path;
00662 return false;
00663 }
00664 }
00665 QString ColorSchemeManager::findColorSchemePath(const QString& name) const
00666 {
00667 QString path = KStandardDirs::locate("data","konsole/"+name+".colorscheme");
00668
00669 if ( !path.isEmpty() )
00670 return path;
00671
00672 path = KStandardDirs::locate("data","konsole/"+name+".schema");
00673
00674 return path;
00675 }
00676 const ColorScheme* ColorSchemeManager::findColorScheme(const QString& name)
00677 {
00678 if ( name.isEmpty() )
00679 return defaultColorScheme();
00680
00681 if ( _colorSchemes.contains(name) )
00682 return _colorSchemes[name];
00683 else
00684 {
00685
00686 QString path = findColorSchemePath(name);
00687 if ( !path.isEmpty() && loadColorScheme(path) )
00688 {
00689 return findColorScheme(name);
00690 }
00691 else
00692 {
00693 if (!path.isEmpty() && loadKDE3ColorScheme(path))
00694 return findColorScheme(name);
00695 }
00696
00697 kWarning() << "Could not find color scheme - " << name;
00698
00699 return 0;
00700 }
00701 }
00702 K_GLOBAL_STATIC( ColorSchemeManager , theColorSchemeManager )
00703 ColorSchemeManager* ColorSchemeManager::instance()
00704 {
00705 return theColorSchemeManager;
00706 }