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, 0 ), ColorEntry(
00046 QColor(0xFF,0xFF,0xFF), 1, 0 ),
00047 ColorEntry( QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry(
00048 QColor(0xB2,0x18,0x18), 0, 0 ),
00049 ColorEntry( QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry(
00050 QColor(0xB2,0x68,0x18), 0, 0 ),
00051 ColorEntry( QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry(
00052 QColor(0xB2,0x18,0xB2), 0, 0 ),
00053 ColorEntry( QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry(
00054 QColor(0xB2,0xB2,0xB2), 0, 0 ),
00055
00056 ColorEntry( QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry(
00057 QColor(0xFF,0xFF,0xFF), 1, 0 ),
00058 ColorEntry( QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry(
00059 QColor(0xFF,0x54,0x54), 0, 0 ),
00060 ColorEntry( QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry(
00061 QColor(0xFF,0xFF,0x54), 0, 0 ),
00062 ColorEntry( QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry(
00063 QColor(0xFF,0x54,0xFF), 0, 0 ),
00064 ColorEntry( QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry(
00065 QColor(0xFF,0xFF,0xFF), 0, 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 entry.bold = configGroup.readEntry("Bold",false);
00314
00315 quint16 hue = configGroup.readEntry("MaxRandomHue",0);
00316 quint8 value = configGroup.readEntry("MaxRandomValue",0);
00317 quint8 saturation = configGroup.readEntry("MaxRandomSaturation",0);
00318
00319 setColorTableEntry( index , entry );
00320
00321 if ( hue != 0 || value != 0 || saturation != 0 )
00322 setRandomizationRange( index , hue , saturation , value );
00323 }
00324 void ColorScheme::writeColorEntry(KConfig& config , const QString& colorName, const ColorEntry& entry , const RandomizationRange& random) const
00325 {
00326 KConfigGroup configGroup(&config,colorName);
00327
00328 configGroup.writeEntry("Color",entry.color);
00329 configGroup.writeEntry("Transparency",(bool)entry.transparent);
00330 configGroup.writeEntry("Bold",(bool)entry.bold);
00331
00332
00333
00334 if ( !random.isNull() || configGroup.hasKey("MaxRandomHue") )
00335 {
00336 configGroup.writeEntry("MaxRandomHue",(int)random.hue);
00337 configGroup.writeEntry("MaxRandomValue",(int)random.value);
00338 configGroup.writeEntry("MaxRandomSaturation",(int)random.saturation);
00339 }
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 AccessibleColorScheme::AccessibleColorScheme()
00371 : ColorScheme()
00372 {
00373
00374 setName("accessible");
00375 setDescription(i18n("Accessible Color Scheme"));
00376
00377
00378 const int ColorRoleCount = 8;
00379
00380 const KColorScheme colorScheme(QPalette::Active);
00381
00382 QBrush colors[ColorRoleCount] =
00383 {
00384 colorScheme.foreground( colorScheme.NormalText ),
00385 colorScheme.background( colorScheme.NormalBackground ),
00386
00387 colorScheme.foreground( colorScheme.InactiveText ),
00388 colorScheme.foreground( colorScheme.ActiveText ),
00389 colorScheme.foreground( colorScheme.LinkText ),
00390 colorScheme.foreground( colorScheme.VisitedText ),
00391 colorScheme.foreground( colorScheme.NegativeText ),
00392 colorScheme.foreground( colorScheme.NeutralText )
00393 };
00394
00395 for ( int i = 0 ; i < TABLE_COLORS ; i++ )
00396 {
00397 ColorEntry entry;
00398 entry.color = colors[ i % ColorRoleCount ].color();
00399
00400 setColorTableEntry( i , entry );
00401 }
00402 }
00403
00404 KDE3ColorSchemeReader::KDE3ColorSchemeReader( QIODevice* device ) :
00405 _device(device)
00406 {
00407 }
00408 ColorScheme* KDE3ColorSchemeReader::read()
00409 {
00410 Q_ASSERT( _device->openMode() == QIODevice::ReadOnly ||
00411 _device->openMode() == QIODevice::ReadWrite );
00412
00413 ColorScheme* scheme = new ColorScheme();
00414
00415 QRegExp comment("#.*$");
00416 while ( !_device->atEnd() )
00417 {
00418 QString line(_device->readLine());
00419 line.replace(comment,QString());
00420 line = line.simplified();
00421
00422 if ( line.isEmpty() )
00423 continue;
00424
00425 if ( line.startsWith("color") )
00426 {
00427 if (!readColorLine(line,scheme))
00428 kWarning() << "Failed to read KDE 3 color scheme line" << line;
00429 }
00430 else if ( line.startsWith("title") )
00431 {
00432 if (!readTitleLine(line,scheme))
00433 kWarning() << "Failed to read KDE 3 color scheme title line" << line;
00434 }
00435 else
00436 {
00437 kWarning() << "KDE 3 color scheme contains an unsupported feature, '" <<
00438 line << "'";
00439 }
00440 }
00441
00442 return scheme;
00443 }
00444 bool KDE3ColorSchemeReader::readColorLine(const QString& line,ColorScheme* scheme)
00445 {
00446 QStringList list = line.split(QChar(' '));
00447
00448 if (list.count() != 7)
00449 return false;
00450 if (list.first() != "color")
00451 return false;
00452
00453 int index = list[1].toInt();
00454 int red = list[2].toInt();
00455 int green = list[3].toInt();
00456 int blue = list[4].toInt();
00457 int transparent = list[5].toInt();
00458 int bold = list[6].toInt();
00459
00460 const int MAX_COLOR_VALUE = 255;
00461
00462 if( (index < 0 || index >= TABLE_COLORS )
00463 || (red < 0 || red > MAX_COLOR_VALUE )
00464 || (blue < 0 || blue > MAX_COLOR_VALUE )
00465 || (green < 0 || green > MAX_COLOR_VALUE )
00466 || (transparent != 0 && transparent != 1 )
00467 || (bold != 0 && bold != 1) )
00468 return false;
00469
00470 ColorEntry entry;
00471 entry.color = QColor(red,green,blue);
00472 entry.transparent = ( transparent != 0 );
00473 entry.bold = ( bold != 0 );
00474
00475 scheme->setColorTableEntry(index,entry);
00476 return true;
00477 }
00478 bool KDE3ColorSchemeReader::readTitleLine(const QString& line,ColorScheme* scheme)
00479 {
00480 if( !line.startsWith("title") )
00481 return false;
00482
00483 int spacePos = line.indexOf(' ');
00484 if( spacePos == -1 )
00485 return false;
00486
00487 QString description = line.mid(spacePos+1);
00488
00489 scheme->setDescription(i18n(description.toUtf8()));
00490 return true;
00491 }
00492 ColorSchemeManager::ColorSchemeManager()
00493 : _haveLoadedAll(false)
00494 {
00495 }
00496 ColorSchemeManager::~ColorSchemeManager()
00497 {
00498 QHashIterator<QString,const ColorScheme*> iter(_colorSchemes);
00499 while (iter.hasNext())
00500 {
00501 iter.next();
00502 delete iter.value();
00503 }
00504 }
00505 void ColorSchemeManager::loadAllColorSchemes()
00506 {
00507 int success = 0;
00508 int failed = 0;
00509
00510 QList<QString> nativeColorSchemes = listColorSchemes();
00511
00512 QListIterator<QString> nativeIter(nativeColorSchemes);
00513 while ( nativeIter.hasNext() )
00514 {
00515 if ( loadColorScheme( nativeIter.next() ) )
00516 success++;
00517 else
00518 failed++;
00519 }
00520
00521 QList<QString> kde3ColorSchemes = listKDE3ColorSchemes();
00522 QListIterator<QString> kde3Iter(kde3ColorSchemes);
00523 while ( kde3Iter.hasNext() )
00524 {
00525 if ( loadKDE3ColorScheme( kde3Iter.next() ) )
00526 success++;
00527 else
00528 failed++;
00529 }
00530
00531 if ( failed > 0 )
00532 kWarning() << "failed to load " << failed << " color schemes.";
00533
00534 _haveLoadedAll = true;
00535 }
00536 QList<const ColorScheme*> ColorSchemeManager::allColorSchemes()
00537 {
00538 if ( !_haveLoadedAll )
00539 {
00540 loadAllColorSchemes();
00541 }
00542
00543 return _colorSchemes.values();
00544 }
00545 bool ColorSchemeManager::loadKDE3ColorScheme(const QString& filePath)
00546 {
00547 QFile file(filePath);
00548 if (!filePath.endsWith(".schema") || !file.open(QIODevice::ReadOnly))
00549 return false;
00550
00551 KDE3ColorSchemeReader reader(&file);
00552 ColorScheme* scheme = reader.read();
00553 scheme->setName(QFileInfo(file).baseName());
00554 file.close();
00555
00556 if (scheme->name().isEmpty())
00557 {
00558 kWarning() << "color scheme name is not valid.";
00559 delete scheme;
00560 return false;
00561 }
00562
00563 QFileInfo info(filePath);
00564
00565 if ( !_colorSchemes.contains(info.baseName()) )
00566 _colorSchemes.insert(scheme->name(),scheme);
00567 else
00568 {
00569 kDebug() << "color scheme with name" << scheme->name() << "has already been" <<
00570 "found, ignoring.";
00571 delete scheme;
00572 }
00573
00574 return true;
00575 }
00576 void ColorSchemeManager::addColorScheme(ColorScheme* scheme)
00577 {
00578 _colorSchemes.insert(scheme->name(),scheme);
00579
00580
00581 QString path = KGlobal::dirs()->saveLocation("data","konsole/") + scheme->name() + ".colorscheme";
00582 KConfig config(path , KConfig::NoGlobals);
00583
00584 scheme->write(config);
00585 }
00586 bool ColorSchemeManager::loadColorScheme(const QString& filePath)
00587 {
00588 if ( !filePath.endsWith(".colorscheme") || !QFile::exists(filePath) )
00589 return false;
00590
00591 QFileInfo info(filePath);
00592
00593 KConfig config(filePath , KConfig::NoGlobals);
00594 ColorScheme* scheme = new ColorScheme();
00595 scheme->setName(info.baseName());
00596 scheme->read(config);
00597
00598 if (scheme->name().isEmpty())
00599 {
00600 kWarning() << "Color scheme in" << filePath << "does not have a valid name and was not loaded.";
00601 delete scheme;
00602 return false;
00603 }
00604
00605 if ( !_colorSchemes.contains(info.baseName()) )
00606 {
00607 _colorSchemes.insert(scheme->name(),scheme);
00608 }
00609 else
00610 {
00611 kDebug() << "color scheme with name" << scheme->name() << "has already been" <<
00612 "found, ignoring.";
00613
00614 delete scheme;
00615 }
00616
00617 return true;
00618 }
00619 QList<QString> ColorSchemeManager::listKDE3ColorSchemes()
00620 {
00621 return KGlobal::dirs()->findAllResources("data",
00622 "konsole/*.schema",
00623 KStandardDirs::NoDuplicates);
00624
00625 }
00626 QList<QString> ColorSchemeManager::listColorSchemes()
00627 {
00628 return KGlobal::dirs()->findAllResources("data",
00629 "konsole/*.colorscheme",
00630 KStandardDirs::NoDuplicates);
00631 }
00632 const ColorScheme ColorSchemeManager::_defaultColorScheme;
00633 const ColorScheme* ColorSchemeManager::defaultColorScheme() const
00634 {
00635 return &_defaultColorScheme;
00636 }
00637 bool ColorSchemeManager::deleteColorScheme(const QString& name)
00638 {
00639 Q_ASSERT( _colorSchemes.contains(name) );
00640
00641
00642 QString path = findColorSchemePath(name);
00643 if ( QFile::remove(path) )
00644 {
00645 _colorSchemes.remove(name);
00646 return true;
00647 }
00648 else
00649 {
00650 kWarning() << "Failed to remove color scheme -" << path;
00651 return false;
00652 }
00653 }
00654 QString ColorSchemeManager::findColorSchemePath(const QString& name) const
00655 {
00656 QString path = KStandardDirs::locate("data","konsole/"+name+".colorscheme");
00657
00658 if ( !path.isEmpty() )
00659 return path;
00660
00661 path = KStandardDirs::locate("data","konsole/"+name+".schema");
00662
00663 return path;
00664 }
00665 const ColorScheme* ColorSchemeManager::findColorScheme(const QString& name)
00666 {
00667 if ( name.isEmpty() )
00668 return defaultColorScheme();
00669
00670 if ( _colorSchemes.contains(name) )
00671 return _colorSchemes[name];
00672 else
00673 {
00674
00675 QString path = findColorSchemePath(name);
00676 if ( !path.isEmpty() && loadColorScheme(path) )
00677 {
00678 return findColorScheme(name);
00679 }
00680 else
00681 {
00682 if (!path.isEmpty() && loadKDE3ColorScheme(path))
00683 return findColorScheme(name);
00684 }
00685
00686 kWarning() << "Could not find color scheme - " << name;
00687
00688 return 0;
00689 }
00690 }
00691 K_GLOBAL_STATIC( ColorSchemeManager , theColorSchemeManager )
00692 ColorSchemeManager* ColorSchemeManager::instance()
00693 {
00694 return theColorSchemeManager;
00695 }