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
00180
00181
00182
00183
00184 if ( randomSeed != 0 &&
00185 _randomTable != 0 &&
00186 !_randomTable[index].isNull() )
00187 {
00188 const RandomizationRange& range = _randomTable[index];
00189
00190
00191 int hueDifference = range.hue ? (qrand() % range.hue) - range.hue/2 : 0;
00192 int saturationDifference = range.saturation ? (qrand() % range.saturation) - range.saturation/2 : 0;
00193 int valueDifference = range.value ? (qrand() % range.value) - range.value/2 : 0;
00194
00195 QColor& color = entry.color;
00196
00197
00198 int newHue = qAbs( (color.hue() + hueDifference) % MAX_HUE );
00199 int newValue = qMin( qAbs(color.value() + valueDifference) , 255 );
00200 int newSaturation = qMin( qAbs(color.saturation() + saturationDifference) , 255 );
00201
00202
00203
00204 color.setHsv(newHue,newSaturation,newValue);
00205 }
00206
00207
00208
00209 return entry;
00210 }
00211 void ColorScheme::getColorTable(ColorEntry* table , uint randomSeed) const
00212 {
00213 for ( int i = 0 ; i < TABLE_COLORS ; i++ )
00214 table[i] = colorEntry(i,randomSeed);
00215 }
00216 bool ColorScheme::randomizedBackgroundColor() const
00217 {
00218 return _randomTable == 0 ? false : !_randomTable[1].isNull();
00219 }
00220 void ColorScheme::setRandomizedBackgroundColor(bool randomize)
00221 {
00222
00223
00224
00225
00226 if ( randomize )
00227 {
00228 setRandomizationRange( 1 , MAX_HUE , 255 , 0 );
00229 }
00230 else
00231 {
00232 if ( _randomTable )
00233 setRandomizationRange( 1 , 0 , 0 , 0 );
00234 }
00235 }
00236
00237 void ColorScheme::setRandomizationRange( int index , quint16 hue , quint8 saturation ,
00238 quint8 value )
00239 {
00240 Q_ASSERT( hue <= MAX_HUE );
00241 Q_ASSERT( index >= 0 && index < TABLE_COLORS );
00242
00243 if ( _randomTable == 0 )
00244 _randomTable = new RandomizationRange[TABLE_COLORS];
00245
00246 _randomTable[index].hue = hue;
00247 _randomTable[index].value = value;
00248 _randomTable[index].saturation = saturation;
00249 }
00250
00251 const ColorEntry* ColorScheme::colorTable() const
00252 {
00253 if ( _table )
00254 return _table;
00255 else
00256 return defaultTable;
00257 }
00258 QColor ColorScheme::foregroundColor() const
00259 {
00260 return colorTable()[0].color;
00261 }
00262 QColor ColorScheme::backgroundColor() const
00263 {
00264 return colorTable()[1].color;
00265 }
00266 bool ColorScheme::hasDarkBackground() const
00267 {
00268
00269
00270 return backgroundColor().value() < 127;
00271 }
00272 void ColorScheme::setOpacity(qreal opacity) { _opacity = opacity; }
00273 qreal ColorScheme::opacity() const { return _opacity; }
00274
00275 void ColorScheme::read(KConfig& config)
00276 {
00277 KConfigGroup configGroup = config.group("General");
00278
00279 QString description = configGroup.readEntry("Description", I18N_NOOP("Un-named Color Scheme"));
00280
00281 _description = i18n(description.toUtf8());
00282 _opacity = configGroup.readEntry("Opacity",qreal(1.0));
00283
00284 for (int i=0 ; i < TABLE_COLORS ; i++)
00285 {
00286 readColorEntry(config,i);
00287 }
00288 }
00289 void ColorScheme::write(KConfig& config) const
00290 {
00291 KConfigGroup configGroup = config.group("General");
00292
00293 configGroup.writeEntry("Description",_description);
00294 configGroup.writeEntry("Opacity",_opacity);
00295
00296 for (int i=0 ; i < TABLE_COLORS ; i++)
00297 {
00298 RandomizationRange random = _randomTable != 0 ? _randomTable[i] : RandomizationRange();
00299 writeColorEntry(config,colorNameForIndex(i),colorTable()[i],random);
00300 }
00301 }
00302
00303 QString ColorScheme::colorNameForIndex(int index)
00304 {
00305 Q_ASSERT( index >= 0 && index < TABLE_COLORS );
00306
00307 return QString(colorNames[index]);
00308 }
00309 QString ColorScheme::translatedColorNameForIndex(int index)
00310 {
00311 Q_ASSERT( index >= 0 && index < TABLE_COLORS );
00312
00313 return i18n(translatedColorNames[index]);
00314 }
00315 void ColorScheme::readColorEntry(KConfig& config , int index)
00316 {
00317 KConfigGroup configGroup(&config,colorNameForIndex(index));
00318
00319 ColorEntry entry;
00320
00321 entry.color = configGroup.readEntry("Color",QColor());
00322 entry.transparent = configGroup.readEntry("Transparent",false);
00323 entry.bold = configGroup.readEntry("Bold",false);
00324
00325 quint16 hue = configGroup.readEntry("MaxRandomHue",0);
00326 quint8 value = configGroup.readEntry("MaxRandomValue",0);
00327 quint8 saturation = configGroup.readEntry("MaxRandomSaturation",0);
00328
00329 setColorTableEntry( index , entry );
00330
00331 if ( hue != 0 || value != 0 || saturation != 0 )
00332 setRandomizationRange( index , hue , saturation , value );
00333 }
00334 void ColorScheme::writeColorEntry(KConfig& config , const QString& colorName, const ColorEntry& entry , const RandomizationRange& random) const
00335 {
00336 KConfigGroup configGroup(&config,colorName);
00337
00338 configGroup.writeEntry("Color",entry.color);
00339 configGroup.writeEntry("Transparency",(bool)entry.transparent);
00340 configGroup.writeEntry("Bold",(bool)entry.bold);
00341
00342
00343
00344 if ( !random.isNull() || configGroup.hasKey("MaxRandomHue") )
00345 {
00346 configGroup.writeEntry("MaxRandomHue",(int)random.hue);
00347 configGroup.writeEntry("MaxRandomValue",(int)random.value);
00348 configGroup.writeEntry("MaxRandomSaturation",(int)random.saturation);
00349 }
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 AccessibleColorScheme::AccessibleColorScheme()
00381 : ColorScheme()
00382 {
00383
00384 setName("accessible");
00385 setDescription(i18n("Accessible Color Scheme"));
00386
00387
00388 const int ColorRoleCount = 8;
00389
00390 const KColorScheme colorScheme(QPalette::Active);
00391
00392 QBrush colors[ColorRoleCount] =
00393 {
00394 colorScheme.foreground( colorScheme.NormalText ),
00395 colorScheme.background( colorScheme.NormalBackground ),
00396
00397 colorScheme.foreground( colorScheme.InactiveText ),
00398 colorScheme.foreground( colorScheme.ActiveText ),
00399 colorScheme.foreground( colorScheme.LinkText ),
00400 colorScheme.foreground( colorScheme.VisitedText ),
00401 colorScheme.foreground( colorScheme.NegativeText ),
00402 colorScheme.foreground( colorScheme.NeutralText )
00403 };
00404
00405 for ( int i = 0 ; i < TABLE_COLORS ; i++ )
00406 {
00407 ColorEntry entry;
00408 entry.color = colors[ i % ColorRoleCount ].color();
00409
00410 setColorTableEntry( i , entry );
00411 }
00412 }
00413
00414 KDE3ColorSchemeReader::KDE3ColorSchemeReader( QIODevice* device ) :
00415 _device(device)
00416 {
00417 }
00418 ColorScheme* KDE3ColorSchemeReader::read()
00419 {
00420 Q_ASSERT( _device->openMode() == QIODevice::ReadOnly ||
00421 _device->openMode() == QIODevice::ReadWrite );
00422
00423 ColorScheme* scheme = new ColorScheme();
00424
00425 QRegExp comment("#.*$");
00426 while ( !_device->atEnd() )
00427 {
00428 QString line(_device->readLine());
00429 line.replace(comment,QString());
00430 line = line.simplified();
00431
00432 if ( line.isEmpty() )
00433 continue;
00434
00435 if ( line.startsWith("color") )
00436 {
00437 readColorLine(line,scheme);
00438 }
00439 else if ( line.startsWith("title") )
00440 {
00441 readTitleLine(line,scheme);
00442 }
00443 else
00444 {
00445 kWarning() << "KDE 3 color scheme contains an unsupported feature, '" <<
00446 line << "'";
00447 }
00448 }
00449
00450 return scheme;
00451 }
00452 void KDE3ColorSchemeReader::readColorLine(const QString& line,ColorScheme* scheme)
00453 {
00454 QStringList list = line.split(QChar(' '));
00455
00456 Q_ASSERT(list.count() == 7);
00457 Q_ASSERT(list.first() == "color");
00458
00459 int index = list[1].toInt();
00460 int red = list[2].toInt();
00461 int green = list[3].toInt();
00462 int blue = list[4].toInt();
00463 int transparent = list[5].toInt();
00464 int bold = list[6].toInt();
00465
00466 const int MAX_COLOR_VALUE = 255;
00467
00468 Q_ASSERT( index >= 0 && index < TABLE_COLORS );
00469 Q_ASSERT( red >= 0 && red <= MAX_COLOR_VALUE );
00470 Q_ASSERT( blue >= 0 && blue <= MAX_COLOR_VALUE );
00471 Q_ASSERT( green >= 0 && green <= MAX_COLOR_VALUE );
00472 Q_ASSERT( transparent == 0 || transparent == 1 );
00473 Q_ASSERT( bold == 0 || bold == 1 );
00474
00475 ColorEntry entry;
00476 entry.color = QColor(red,green,blue);
00477 entry.transparent = ( transparent != 0 );
00478 entry.bold = ( bold != 0 );
00479
00480 scheme->setColorTableEntry(index,entry);
00481 }
00482 void KDE3ColorSchemeReader::readTitleLine(const QString& line,ColorScheme* scheme)
00483 {
00484 Q_ASSERT( line.startsWith("title") );
00485
00486 int spacePos = line.indexOf(' ');
00487 Q_ASSERT( spacePos != -1 );
00488
00489 QString description = line.mid(spacePos+1);
00490
00491 scheme->setDescription(i18n(description.toUtf8()));
00492 }
00493 ColorSchemeManager::ColorSchemeManager()
00494 : _haveLoadedAll(false)
00495 {
00496 }
00497 ColorSchemeManager::~ColorSchemeManager()
00498 {
00499 QHashIterator<QString,const ColorScheme*> iter(_colorSchemes);
00500 while (iter.hasNext())
00501 {
00502 iter.next();
00503 delete iter.value();
00504 }
00505 }
00506 void ColorSchemeManager::loadAllColorSchemes()
00507 {
00508 int success = 0;
00509 int failed = 0;
00510
00511 QList<QString> nativeColorSchemes = listColorSchemes();
00512
00513 QListIterator<QString> nativeIter(nativeColorSchemes);
00514 while ( nativeIter.hasNext() )
00515 {
00516 if ( loadColorScheme( nativeIter.next() ) )
00517 success++;
00518 else
00519 failed++;
00520 }
00521
00522 QList<QString> kde3ColorSchemes = listKDE3ColorSchemes();
00523 QListIterator<QString> kde3Iter(kde3ColorSchemes);
00524 while ( kde3Iter.hasNext() )
00525 {
00526 if ( loadKDE3ColorScheme( kde3Iter.next() ) )
00527 success++;
00528 else
00529 failed++;
00530 }
00531
00532
00533
00534 if ( failed > 0 )
00535 kDebug() << "failed to load " << failed << " color schemes.";
00536
00537 _haveLoadedAll = true;
00538 }
00539 QList<const ColorScheme*> ColorSchemeManager::allColorSchemes()
00540 {
00541 if ( !_haveLoadedAll )
00542 {
00543 loadAllColorSchemes();
00544 }
00545
00546 return _colorSchemes.values();
00547 }
00548 bool ColorSchemeManager::loadKDE3ColorScheme(const QString& filePath)
00549 {
00550
00551
00552 QFile file(filePath);
00553 if (!filePath.endsWith(".schema") || !file.open(QIODevice::ReadOnly))
00554 return false;
00555
00556 KDE3ColorSchemeReader reader(&file);
00557 ColorScheme* scheme = reader.read();
00558 scheme->setName(QFileInfo(file).baseName());
00559 file.close();
00560
00561 Q_ASSERT( !scheme->name().isEmpty() );
00562
00563
00564
00565 QFileInfo info(filePath);
00566
00567 if ( !_colorSchemes.contains(info.baseName()) )
00568 {
00569
00570
00571 _colorSchemes.insert(scheme->name(),scheme);
00572 }
00573 else
00574 {
00575 kDebug() << "color scheme with name" << scheme->name() << "has already been" <<
00576 "found, ignoring.";
00577 delete scheme;
00578 }
00579
00580 return true;
00581 }
00582 void ColorSchemeManager::addColorScheme(ColorScheme* scheme)
00583 {
00584 _colorSchemes.insert(scheme->name(),scheme);
00585
00586
00587 QString path = KGlobal::dirs()->saveLocation("data","konsole/") + scheme->name() + ".colorscheme";
00588 KConfig config(path , KConfig::NoGlobals);
00589
00590 scheme->write(config);
00591 }
00592 bool ColorSchemeManager::loadColorScheme(const QString& filePath)
00593 {
00594 if ( !filePath.endsWith(".colorscheme") || !QFile::exists(filePath) )
00595 return false;
00596
00597 QFileInfo info(filePath);
00598
00599 KConfig config(filePath , KConfig::NoGlobals);
00600 ColorScheme* scheme = new ColorScheme();
00601 scheme->setName(info.baseName());
00602 scheme->read(config);
00603
00604 if (scheme->name().isEmpty())
00605 {
00606 kWarning() << "Color scheme in" << filePath << "does not have a valid name and was not loaded.";
00607 delete scheme;
00608 return false;
00609 }
00610
00611 if ( !_colorSchemes.contains(info.baseName()) )
00612 {
00613 _colorSchemes.insert(scheme->name(),scheme);
00614 }
00615 else
00616 {
00617 kDebug() << "color scheme with name" << scheme->name() << "has already been" <<
00618 "found, ignoring.";
00619
00620 delete scheme;
00621 }
00622
00623 return true;
00624 }
00625 QList<QString> ColorSchemeManager::listKDE3ColorSchemes()
00626 {
00627 return KGlobal::dirs()->findAllResources("data",
00628 "konsole/*.schema",
00629 KStandardDirs::NoDuplicates);
00630
00631 }
00632 QList<QString> ColorSchemeManager::listColorSchemes()
00633 {
00634 return KGlobal::dirs()->findAllResources("data",
00635 "konsole/*.colorscheme",
00636 KStandardDirs::NoDuplicates);
00637 }
00638 const ColorScheme ColorSchemeManager::_defaultColorScheme;
00639 const ColorScheme* ColorSchemeManager::defaultColorScheme() const
00640 {
00641 return &_defaultColorScheme;
00642 }
00643 bool ColorSchemeManager::deleteColorScheme(const QString& name)
00644 {
00645 Q_ASSERT( _colorSchemes.contains(name) );
00646
00647
00648 QString path = findColorSchemePath(name);
00649 if ( QFile::remove(path) )
00650 {
00651 _colorSchemes.remove(name);
00652 return true;
00653 }
00654 else
00655 {
00656 kWarning() << "Failed to remove color scheme -" << path;
00657 return false;
00658 }
00659 }
00660 QString ColorSchemeManager::findColorSchemePath(const QString& name) const
00661 {
00662 QString path = KStandardDirs::locate("data","konsole/"+name+".colorscheme");
00663
00664 if ( !path.isEmpty() )
00665 return path;
00666
00667 path = KStandardDirs::locate("data","konsole/"+name+".schema");
00668
00669 return path;
00670 }
00671 const ColorScheme* ColorSchemeManager::findColorScheme(const QString& name)
00672 {
00673
00674
00675 if ( name.isEmpty() )
00676 return defaultColorScheme();
00677
00678 if ( _colorSchemes.contains(name) )
00679 return _colorSchemes[name];
00680 else
00681 {
00682
00683 QString path = findColorSchemePath(name);
00684 if ( !path.isEmpty() && loadColorScheme(path) )
00685 {
00686 return findColorScheme(name);
00687 }
00688 else
00689 {
00690 if (!path.isEmpty() && loadKDE3ColorScheme(path))
00691 return findColorScheme(name);
00692 }
00693
00694 kDebug() << "Could not find color scheme - " << name;
00695
00696 return 0;
00697 }
00698 }
00699 K_GLOBAL_STATIC( ColorSchemeManager , theColorSchemeManager )
00700 ColorSchemeManager* ColorSchemeManager::instance()
00701 {
00702 return theColorSchemeManager;
00703 }