* Copyright (C) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
* Copyright (C) 2007 Jeremy Whiting <jpwhiting@kde.org>
* Copyright (C) 2016 Olivier Churlaud <olivier@churlaud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "colorscm.h"
#include "../krdb/krdb.h"
#include "scmeditordialog.h"
#include <QFileInfo>
#include <QFileDialog>
#include <QHeaderView>
#include <QInputDialog>
#include <QStackedWidget>
#include <QStandardPaths>
#include <QPainter>
#include <QBitmap>
#include <QtDBus/QtDBus>
#include <KAboutData>
#include <KColorButton>
#include <KConfigGroup>
#include <KColorUtils>
#include <KColorScheme>
#include <KMessageBox>
#include <KPluginFactory>
#include <KJobUiDelegate>
#include <KIO/DeleteJob>
#include <KNS3/DownloadDialog>
K_PLUGIN_FACTORY( KolorFactory, registerPlugin<KColorCm>(); )
K_EXPORT_PLUGIN( KolorFactory("kcmcolors") )
KColorCm::KColorCm(QWidget *parent, const QVariantList &)
: KCModule( parent ),
m_dontLoadSelectedScheme(false),
m_previousSchemeItem(0)
{
KAboutData* about = new KAboutData(
QStringLiteral("kcmcolors"), i18n("Colors"), QStringLiteral("1.0"), QString(),
KAboutLicense::GPL,
i18n("(c) 2007 Matthew Woehlke")
);
about->addAuthor( i18n("Matthew Woehlke"), QString(),
QStringLiteral("mw_triad@users.sourceforge.net") );
about->addAuthor( i18n("Jeremy Whiting"), QString(), QStringLiteral("jpwhiting@kde.org"));
setAboutData( about );
m_config = KSharedConfig::openConfig(QStringLiteral("kdeglobals"));
setupUi(this);
connect(applyToAlien, &QCheckBox::toggled, [=](){ emit changed(true); });
connect(schemeList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(loadScheme(QListWidgetItem*,QListWidgetItem*)));
schemeKnsButton->setIcon( QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")) );
}
KColorCm::~KColorCm()
{
m_config->markAsClean();
}
void KColorCm::populateSchemeList()
{
schemeList->clear();
QIcon icon;
QStringList schemeFiles;
const QStringList schemeDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("color-schemes"), QStandardPaths::LocateDirectory);
Q_FOREACH (const QString &dir, schemeDirs)
{
const QStringList fileNames = QDir(dir).entryList(QStringList()<<QStringLiteral("*.colors"));
Q_FOREACH (const QString &file, fileNames)
{
if( !schemeFiles.contains("color-schemes/"+file))
{
schemeFiles.append("color-schemes/"+file);
}
}
}
for (QStringList::Iterator it = schemeFiles.begin(); it != schemeFiles.end(); ++it )
{
*it = QStandardPaths::locate(QStandardPaths::GenericDataLocation, *it);
}
for (int i = 0; i < schemeFiles.size(); ++i)
{
const QString filename = schemeFiles.at(i);
const QFileInfo info(filename);
KSharedConfigPtr config = KSharedConfig::openConfig(filename);
icon = createSchemePreviewIcon(config);
KConfigGroup group(config, "General");
const QString name = group.readEntry("Name", info.baseName());
QListWidgetItem * newItem = new QListWidgetItem(icon, name);
newItem->setData(Qt::UserRole, info.baseName());
schemeList->addItem(newItem);
}
schemeList->sortItems();
m_config->setReadDefaults(true);
icon = createSchemePreviewIcon(m_config);
schemeList->insertItem(0, new QListWidgetItem(icon, i18nc("Default color scheme", "Default")));
m_config->setReadDefaults(false);
}
void KColorCm::loadScheme(KSharedConfigPtr config)
{
schemePreview->setPalette(config);
updateConfig(config);
}
void KColorCm::selectPreviousSchemeAgain()
{
m_dontLoadSelectedScheme = true;
schemeList->setCurrentItem(m_previousSchemeItem);
m_dontLoadSelectedScheme = false;
}
void KColorCm::loadScheme(QListWidgetItem *currentItem, QListWidgetItem *previousItem)
{
m_previousSchemeItem = previousItem;
if (m_dontLoadSelectedScheme)
{
qDebug() << "dontload";
return;
}
if (currentItem != NULL)
{
const QString name = currentItem->text();
m_currentColorScheme = name;
const QString fileBaseName = currentItem->data(Qt::UserRole).toString();
if (name == i18nc("Default color scheme", "Default"))
{
schemeRemoveButton->setEnabled(false);
KSharedConfigPtr config = m_config;
config->setReadDefaults(true);
loadScheme(config);
config->setReadDefaults(false);
emit changed(true);
}
else
{
const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
"color-schemes/" + fileBaseName + ".colors");
const int permissions = QFile(path).permissions();
const bool canWrite = (permissions & QFile::WriteUser);
qDebug() << "checking permissions of " << path;
schemeRemoveButton->setEnabled(canWrite);
schemeEditButton->setEnabled(true);
KSharedConfigPtr config = KSharedConfig::openConfig(path);
loadScheme(config);
emit changed(true);
}
} else {
schemeEditButton->setEnabled(false);
schemeRemoveButton->setEnabled(false);
}
}
void KColorCm::on_schemeRemoveButton_clicked()
{
if (schemeList->currentItem() != NULL)
{
const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
"color-schemes/" + schemeList->currentItem()->data(Qt::UserRole).toString() +
".colors");
KIO::DeleteJob *job = KIO::del(QUrl::fromLocalFile(path));
job->uiDelegate()->setParent(this);
if (job->exec())
{
delete schemeList->takeItem(schemeList->currentRow());
}
else
{
KMessageBox::error(this, i18n("You do not have permission to delete that scheme"), i18n("Error"));
}
}
}
void KColorCm::on_schemeImportButton_clicked()
{
QUrl url = QUrl::fromLocalFile(QFileDialog::getOpenFileName(this, i18n("Import Color Scheme")));
if(!url.isValid())
{
return;
}
KSharedConfigPtr config = KSharedConfig::openConfig(url.path());
if (config->groupList().contains(QStringLiteral("Color Scheme")))
{
KMessageBox::sorry(this,
i18n("The scheme you have selected appears to be a KDE3 scheme.\n\n"
"This is not supported anymore."),
i18n("Notice"));
return;
}
KConfigGroup group(config, "General");
QString name = group.readEntry("Name");
int increment = 0;
QString newName = name;
QString testpath = "";
do
{
if (increment) {
newName = name + QString::number(increment);
}
testpath = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
"color-schemes/" + newName + ".colors");
increment++;
} while (!testpath.isEmpty());
QString newpath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
+ "/color-schemes/";
QDir dir;
dir.mkpath(newpath);
newpath += newName + ".colors";
QFile::copy(url.toLocalFile(), newpath);
KSharedConfigPtr config2 = KSharedConfig::openConfig(newpath);
KConfigGroup group2(config2, "General");
group2.writeEntry("Name", newName);
config2->sync();
this->populateSchemeList();
QList<QListWidgetItem*> itemList = schemeList->findItems(newName, Qt::MatchExactly);
if (!itemList.isEmpty())
{
schemeList->setCurrentItem(itemList.first());
}
}
void KColorCm::on_schemeKnsButton_clicked()
{
KNS3::DownloadDialog dialog(QStringLiteral("colorschemes.knsrc"), this);
dialog.exec();
if ( ! dialog.changedEntries().isEmpty() )
{
populateSchemeList();
}
}
QPixmap KColorCm::createSchemePreviewIcon(const KSharedConfigPtr &config)
{
const uchar bits1[] = { 0xff, 0xff, 0xff, 0x2c, 0x16, 0x0b };
const uchar bits2[] = { 0x68, 0x34, 0x1a, 0xff, 0xff, 0xff };
const QSize bitsSize(24,2);
const QBitmap b1 = QBitmap::fromData(bitsSize, bits1);
const QBitmap b2 = QBitmap::fromData(bitsSize, bits2);
QPixmap pixmap(23, 16);
pixmap.fill(Qt::black);
QPainter p(&pixmap);
KConfigGroup group(config, "WM");
QColor activeBackground = group.readEntry("activeBackground", QColor(48, 174, 232));
QColor activeForeground = group.readEntry("activeForeground", QColor(255, 255, 255));
QColor inactiveBackground = group.readEntry("inactiveBackground", QColor(224, 223, 222));
QColor inactiveForeground = group.readEntry("inactiveForeground", QColor(75, 71, 67));
KColorScheme windowScheme(QPalette::Active, KColorScheme::Window, config);
p.fillRect( 1, 1, 7, 7, windowScheme.background());
p.fillRect( 2, 2, 5, 2, QBrush(windowScheme.foreground().color(), b1));
KColorScheme buttonScheme(QPalette::Active, KColorScheme::Button, config);
p.fillRect( 8, 1, 7, 7, buttonScheme.background());
p.fillRect( 9, 2, 5, 2, QBrush(buttonScheme.foreground().color(), b1));
p.fillRect(15, 1, 7, 7, activeBackground);
p.fillRect(16, 2, 5, 2, QBrush(activeForeground, b1));
KColorScheme viewScheme(QPalette::Active, KColorScheme::View, config);
p.fillRect( 1, 8, 7, 7, viewScheme.background());
p.fillRect( 2, 12, 5, 2, QBrush(viewScheme.foreground().color(), b2));
KColorScheme selectionScheme(QPalette::Active, KColorScheme::Selection, config);
p.fillRect( 8, 8, 7, 7, selectionScheme.background());
p.fillRect( 9, 12, 5, 2, QBrush(selectionScheme.foreground().color(), b2));
p.fillRect(15, 8, 7, 7, inactiveBackground);
p.fillRect(16, 12, 5, 2, QBrush(inactiveForeground, b2));
p.end();
return pixmap;
}
void KColorCm::load()
{
loadInternal();
KConfigGroup group(m_config, "General");
m_currentColorScheme = group.readEntry("ColorScheme");
QList<QListWidgetItem*> itemList = schemeList->findItems(m_currentColorScheme, Qt::MatchExactly);
if(!itemList.isEmpty())
schemeList->setCurrentItem(itemList.at(0));
KConfig cfg(QStringLiteral("kcmdisplayrc"), KConfig::NoGlobals);
group = KConfigGroup(&cfg, "X11");
applyToAlien->blockSignals(true);
applyToAlien->setChecked(group.readEntry("exportKDEColors", true));
applyToAlien->blockSignals(false);
}
void KColorCm::loadInternal()
{
m_config->markAsClean();
m_config->reparseConfiguration();
populateSchemeList();
schemePreview->setPalette(m_config);
emit changed(false);
}
void KColorCm::save()
{
m_config->sync();
KConfig cfg(QStringLiteral("kcmdisplayrc"), KConfig::NoGlobals);
KConfigGroup displayGroup(&cfg, "X11");
displayGroup.writeEntry("exportKDEColors", applyToAlien->isChecked());
cfg.sync();
runRdb(KRdbExportQtColors | KRdbExportGtkTheme | ( applyToAlien->isChecked() ? KRdbExportColors : 0 ) );
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"), QStringLiteral("notifyChange") );
QList<QVariant> args;
args.append(0);
args.append(0);
message.setArguments(args);
QDBusConnection::sessionBus().send(message);
if (qApp->platformName() == QStringLiteral("xcb")) {
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"));
QDBusConnection::sessionBus().send(message);
}
emit changed(false);
}
void KColorCm::defaults()
{
for(int i = 0; i < schemeList->count(); ++i) {
QListWidgetItem *item = schemeList->item(i);
if(item->text() == i18nc("Default color scheme", "Default")) {
if(schemeList->currentItem() == item)
loadScheme(item, item);
else
schemeList->setCurrentItem(item);
m_currentColorScheme = item->text();
break;
}
}
KCModule::defaults();
emit changed(true);
}
void KColorCm::on_schemeEditButton_clicked()
{
QListWidgetItem *currentItem = schemeList->currentItem();
if (!currentItem) {
return;
}
const QString fileBaseName = currentItem->data(Qt::UserRole).toString();
const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
"color-schemes/" + fileBaseName + ".colors");
SchemeEditorDialog* dialog = new SchemeEditorDialog(path, this);
dialog->setModal(true);
dialog->show();
connect(dialog, &SchemeEditorDialog::accepted, [=](){ this->populateSchemeList(); });
connect(dialog, &SchemeEditorDialog::rejected, [=](){ this->populateSchemeList(); });
}
void KColorCm::updateConfig(KSharedConfigPtr config)
{
KConfigGroup groupOut(m_config, "General");
groupOut.writeEntry("ColorScheme", m_currentColorScheme);
QStringList colorItemList;
colorItemList << "BackgroundNormal"
<< "BackgroundAlternate"
<< "ForegroundNormal"
<< "ForegroundInactive"
<< "ForegroundActive"
<< "ForegroundLink"
<< "ForegroundVisited"
<< "ForegroundNegative"
<< "ForegroundNeutral"
<< "ForegroundPositive"
<< "DecorationFocus"
<< "DecorationHover";
QStringList colorSetGroupList;
colorSetGroupList << "Colors:View"
<< "Colors:Window"
<< "Colors:Button"
<< "Colors:Selection"
<< "Colors:Tooltip"
<< "Colors:Complementary";
QList <KColorScheme> colorSchemes;
colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::View, config));
colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Window, config));
colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Button, config));
colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Selection, config));
colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Tooltip, config));
colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Complementary, config));
for (int i = 0; i < colorSchemes.length(); ++i)
{
KConfigGroup group(m_config, colorSetGroupList.value(i));
group.writeEntry("BackgroundNormal", colorSchemes[i].background(KColorScheme::NormalBackground).color());
group.writeEntry("BackgroundAlternate", colorSchemes[i].background(KColorScheme::AlternateBackground).color());
group.writeEntry("ForegroundNormal", colorSchemes[i].foreground(KColorScheme::NormalText).color());
group.writeEntry("ForegroundInactive", colorSchemes[i].foreground(KColorScheme::InactiveText).color());
group.writeEntry("ForegroundActive", colorSchemes[i].foreground(KColorScheme::ActiveText).color());
group.writeEntry("ForegroundLink", colorSchemes[i].foreground(KColorScheme::LinkText).color());
group.writeEntry("ForegroundVisited", colorSchemes[i].foreground(KColorScheme::VisitedText).color());
group.writeEntry("ForegroundNegative", colorSchemes[i].foreground(KColorScheme::NegativeText).color());
group.writeEntry("ForegroundNeutral", colorSchemes[i].foreground(KColorScheme::NeutralText).color());
group.writeEntry("ForegroundPositive", colorSchemes[i].foreground(KColorScheme::PositiveText).color());
group.writeEntry("DecorationFocus", colorSchemes[i].decoration(KColorScheme::FocusColor).color());
group.writeEntry("DecorationHover", colorSchemes[i].decoration(KColorScheme::HoverColor).color());
}
KConfigGroup groupWMTheme(config, "WM");
KConfigGroup groupWMOut(m_config, "WM");
QStringList colorItemListWM;
colorItemListWM << "activeBackground"
<< "activeForeground"
<< "inactiveBackground"
<< "inactiveForeground"
<< "activeBlend"
<< "inactiveBlend";
QVector<QColor> defaultWMColors;
defaultWMColors << QColor(71,80,87)
<< QColor(239,240,241)
<< QColor(239,240,241)
<< QColor(189,195,199)
<< QColor(255,255,255)
<< QColor(75,71,67);
int i = 0;
for (const QString &coloritem : colorItemListWM)
{
groupWMOut.writeEntry(coloritem, groupWMTheme.readEntry(coloritem, defaultWMColors.value(i)));
++i;
}
QStringList groupNameList;
groupNameList << "ColorEffects:Inactive" << "ColorEffects:Disabled";
QStringList effectList;
effectList << "IntensityEffect"
<< "IntensityAmount"
<< "ColorEffect"
<< "ColorAmount"
<< "Color"
<< "ContrastEffect"
<< "ContrastAmount";
for (const QString &groupName : groupNameList)
{
KConfigGroup groupEffectOut(m_config, groupName);
KConfigGroup groupEffectTheme(config, groupName);
for (const QString &effect : effectList) {
groupEffectOut.writeEntry(effect, groupEffectTheme.readEntry("effect"));
}
}
}
#include "colorscm.moc"