add knewstuff support for color schemes

Summary:
schemes are supplied by `Konsole Color Scheme` category on store.kde.org

https://store.kde.org/p/1216368/

- new manager helpers to unload a theme and check a file's name validity
- new Get New.. button to start the KNS download dialog
- upon KNS completion we'll attempt to load all installed files as schemes
- for KNS entities which failed to load anything we'll show a warning as
  the theme is malformed
- for removal we'll first try to remove schemes through KNS to avoid its
  registry going out of sync with the on-disk "installedness" of an entity
- properly disable copying of the scheme manager (needs to be private)

FEATURE: 18.04.0
CHANGELOG: Support for downloading color schemes from the KDE store

Test Plan:
category is T8053 (can also use `KDE Color Scheme KDE4` for testing)

- get new -> install scheme -> close -> shows up in list
- remove from list -> get new -> not listed as installed
- install random stuff from kde color scheme category -> close ->
  warning should be displayed
- install scheme -> get new -> remove scheme via dialog -> close ->
  not listed as installed

Reviewers: hindenburg

Subscribers: #konsole

Tags: #konsole

Differential Revision: https://phabricator.kde.org/D10766
This commit is contained in:
Harald Sitter
2018-02-28 10:49:10 +01:00
parent 18014c75f2
commit 97d9ed9436
9 changed files with 219 additions and 58 deletions

View File

@@ -43,7 +43,7 @@ find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED
Bookmarks Completion Config ConfigWidgets
CoreAddons Crash GuiAddons DBusAddons
I18n IconThemes Init KIO Notifications NotifyConfig
I18n IconThemes Init KIO NewStuff NewStuffCore Notifications NotifyConfig
Parts Pty Service TextWidgets WidgetsAddons
WindowSystem XmlGui DBusAddons GlobalAccel
)

View File

@@ -1,3 +1,5 @@
add_subdirectory( color-schemes )
add_subdirectory( keyboard-layouts )
install( FILES konsole.knsrc DESTINATION ${CONFIG_INSTALL_DIR})

5
data/konsole.knsrc Normal file
View File

@@ -0,0 +1,5 @@
[KNewStuff3]
ProvidersUrl=https://download.kde.org/ocs/providers.xml
Categories=Konsole Color Schemes
TargetDir=konsole
AcceptHtmlDownloads=false

View File

@@ -124,6 +124,7 @@ set(konsole_LIBS
KF5::KIOWidgets
KF5::DBusAddons
KF5::GlobalAccel
KF5::NewStuff
)
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")

View File

@@ -2,6 +2,7 @@
This source file is part of Konsole, a terminal emulator.
Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
Copyright 2018 by Harald Sitter <sitter@kde.org>
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
@@ -85,15 +86,15 @@ QList<const ColorScheme *> ColorSchemeManager::allColorSchemes()
bool ColorSchemeManager::loadColorScheme(const QString &filePath)
{
if (!filePath.endsWith(QLatin1String(".colorscheme")) || !QFile::exists(filePath)) {
if (!pathIsColorScheme(filePath) || !QFile::exists(filePath)) {
return false;
}
QFileInfo info(filePath);
auto name = colorSchemeNameFromPath(filePath);
KConfig config(filePath, KConfig::NoGlobals);
auto scheme = new ColorScheme();
scheme->setName(info.completeBaseName());
scheme->setName(name);
scheme->read(config);
if (scheme->name().isEmpty()) {
@@ -103,7 +104,7 @@ bool ColorSchemeManager::loadColorScheme(const QString &filePath)
return false;
}
if (!_colorSchemes.contains(info.completeBaseName())) {
if (!_colorSchemes.contains(name)) {
_colorSchemes.insert(scheme->name(), scheme);
} else {
//qDebug() << "color scheme with name" << scheme->name() << "has already been" <<
@@ -115,6 +116,24 @@ bool ColorSchemeManager::loadColorScheme(const QString &filePath)
return true;
}
bool ColorSchemeManager::unloadColorScheme(const QString &filePath)
{
if (!pathIsColorScheme(filePath)) {
return false;
}
auto name = colorSchemeNameFromPath(filePath);
delete _colorSchemes.take(name);
return true;
}
QString ColorSchemeManager::colorSchemeNameFromPath(const QString &path)
{
if (!pathIsColorScheme(path)) {
return QString();
}
return QFileInfo(path).completeBaseName();
}
QStringList ColorSchemeManager::listColorSchemes()
{
QStringList colorschemes;
@@ -141,8 +160,7 @@ void ColorSchemeManager::addColorScheme(ColorScheme *scheme)
{
// remove existing colorscheme with the same name
if (_colorSchemes.contains(scheme->name())) {
delete _colorSchemes[scheme->name()];
_colorSchemes.remove(scheme->name());
delete _colorSchemes.take(scheme->name());
}
_colorSchemes.insert(scheme->name(), scheme);
@@ -165,8 +183,7 @@ bool ColorSchemeManager::deleteColorScheme(const QString &name)
// look up the path and delete
QString path = findColorSchemePath(name);
if (QFile::remove(path)) {
delete _colorSchemes[name];
_colorSchemes.remove(name);
delete _colorSchemes.take(name);
return true;
} else {
qCDebug(KonsoleDebug)<<"Failed to remove color scheme -"<<path;
@@ -214,6 +231,11 @@ QString ColorSchemeManager::findColorSchemePath(const QString &name) const
return QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("konsole/") + name + QStringLiteral(".schema"));
}
bool ColorSchemeManager::pathIsColorScheme(const QString &path)
{
return path.endsWith(QLatin1String(".colorscheme"));
}
bool ColorSchemeManager::isColorSchemeDeletable(const QString &name)
{
const QString path = findColorSchemePath(name);

View File

@@ -2,6 +2,7 @@
This source file is part of Konsole, a terminal emulator.
Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
Copyright 2018 by Harald Sitter <sitter@kde.org>
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
@@ -100,23 +101,33 @@ public:
*/
bool isColorSchemeDeletable(const QString &name);
private:
Q_DISABLE_COPY(ColorSchemeManager)
// loads a color scheme from a KDE 4+ .colorscheme file
bool loadColorScheme(const QString &path);
// unloads a color scheme by it's file path (doesn't delete!)
bool unloadColorScheme(const QString &path);
// @returns the scheme name of a given file or a null string if the file is
// no theme
static QString colorSchemeNameFromPath(const QString &path);
private:
// returns a list of paths of color schemes in the KDE 4+ .colorscheme file format
QStringList listColorSchemes();
// loads all of the color schemes
void loadAllColorSchemes();
// finds the path of a color scheme
QString findColorSchemePath(const QString &name) const;
// @returns whether a path is a valid color scheme name
static bool pathIsColorScheme(const QString &path);
QHash<QString, const ColorScheme *> _colorSchemes;
bool _haveLoadedAll;
static const ColorScheme _defaultColorScheme;
Q_DISABLE_COPY(ColorSchemeManager)
};
}

View File

@@ -1,5 +1,6 @@
/*
Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
Copyright 2018 by Harald Sitter <sitter@kde.org>
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
@@ -37,13 +38,14 @@
#include <QFileDialog>
#include <QInputDialog>
#include <QDialog>
// KDE
#include <KCodecAction>
#include <KIconDialog>
#include <KWindowSystem>
#include <KMessageBox>
#include <KLocalizedString>
#include <KNSCore/DownloadManager>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
@@ -537,10 +539,17 @@ void EditProfileDialog::setupAppearancePage(const Profile::Ptr profile)
_ui->transparencyWarningWidget->setCloseButtonVisible(false);
_ui->transparencyWarningWidget->setMessageType(KMessageWidget::Warning);
_ui->colorSchemeMessageWidget->setVisible(false);
_ui->colorSchemeMessageWidget->setWordWrap(true);
_ui->colorSchemeMessageWidget->setCloseButtonVisible(false);
_ui->colorSchemeMessageWidget->setMessageType(KMessageWidget::Warning);
_ui->editColorSchemeButton->setEnabled(false);
_ui->removeColorSchemeButton->setEnabled(false);
_ui->resetColorSchemeButton->setEnabled(false);
_ui->downloadColorSchemeButton->setConfigFile(QStringLiteral("konsole.knsrc"));
// setup color list
// select the colorScheme used in the current profile
updateColorSchemeList(currentColorSchemeName());
@@ -563,6 +572,8 @@ void EditProfileDialog::setupAppearancePage(const Profile::Ptr profile)
&Konsole::EditProfileDialog::removeColorScheme);
connect(_ui->newColorSchemeButton, &QPushButton::clicked, this,
&Konsole::EditProfileDialog::newColorScheme);
connect(_ui->downloadColorSchemeButton, &KNS3::Button::dialogFinished, this,
&Konsole::EditProfileDialog::gotNewColorSchemes);
connect(_ui->resetColorSchemeButton, &QPushButton::clicked, this,
&Konsole::EditProfileDialog::resetColorScheme);
@@ -842,14 +853,98 @@ void EditProfileDialog::previewColorScheme(const QModelIndex &index)
void EditProfileDialog::removeColorScheme()
{
QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();
if (selected.isEmpty()) {
return;
}
if (!selected.isEmpty()) {
// The actual delete runs async because we need to on-demand query
// files managed by KNS. Deleting files managed by KNS screws up the
// KNS states (entry gets shown as installed when in fact we deleted it).
auto *manager = new KNSCore::DownloadManager(QStringLiteral("konsole.knsrc"), this);
connect(manager, &KNSCore::DownloadManager::searchResult,
[=](const KNSCore::EntryInternal::List &entries) {
const QString &name = selected.first().data(Qt::UserRole + 1).value<const ColorScheme *>()->name();
Q_ASSERT(!name.isEmpty());
bool uninstalled = false;
// Check if the theme was installed by KNS, if so uninstall it through
// there and unload it.
for (auto entry : entries) {
for (const auto &file : entry.installedFiles()) {
if (ColorSchemeManager::colorSchemeNameFromPath(file) != name) {
continue;
}
// Make sure the manager can unload it before uninstalling it.
if (ColorSchemeManager::instance()->unloadColorScheme(file)) {
manager->uninstallEntry(entry);
uninstalled = true;
}
}
if (uninstalled) {
break;
}
}
if (ColorSchemeManager::instance()->deleteColorScheme(name)) {
// If KNS wasn't able to remove it is a custom theme and we'll drop
// it manually.
if (!uninstalled) {
uninstalled = ColorSchemeManager::instance()->deleteColorScheme(name);
}
if (uninstalled) {
_ui->colorSchemeList->model()->removeRow(selected.first().row());
}
manager->deleteLater();
});
manager->checkForInstalled();
return;
}
void EditProfileDialog::gotNewColorSchemes(const KNS3::Entry::List &changedEntries)
{
int failures = 0;
for (auto entry : changedEntries) {
switch (entry.status()) {
case KNS3::Entry::Installed:
for (const auto &file : entry.installedFiles()) {
if (ColorSchemeManager::instance()->loadColorScheme(file)) {
continue;
}
qWarning() << "Failed to load file" << file;
++failures;
}
if (failures == entry.installedFiles().size()) {
_ui->colorSchemeMessageWidget->setText(
xi18nc("@info",
"Scheme <resource>%1</resource> failed to load.",
entry.name()));
_ui->colorSchemeMessageWidget->animatedShow();
QTimer::singleShot(8000,
_ui->colorSchemeMessageWidget,
&KMessageWidget::animatedHide);
}
break;
case KNS3::Entry::Deleted:
for (const auto &file : entry.uninstalledFiles()) {
if (ColorSchemeManager::instance()->unloadColorScheme(file)) {
continue;
}
qWarning() << "Failed to unload file" << file;
// If unloading fails we do not care. Iff the scheme failed here
// it either wasn't loaded or was invalid to begin with.
}
break;
case KNS3::Entry::Invalid:
case KNS3::Entry::Installing:
case KNS3::Entry::Downloadable:
case KNS3::Entry::Updateable:
case KNS3::Entry::Updating:
// Not interesting.
break;
}
}
updateColorSchemeList(currentColorSchemeName());
}
void EditProfileDialog::resetColorScheme()

View File

@@ -1,5 +1,6 @@
/*
Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
Copyright 2018 by Harald Sitter <sitter@kde.org>
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
@@ -22,11 +23,12 @@
// Qt
#include <QAbstractItemDelegate>
#include <QDialog>
#include <QHash>
#include <QPointer>
// KDE
#include <QDialog>
// KDe
#include <KNS3/Entry>
// Konsole
#include "Profile.h"
@@ -132,6 +134,7 @@ private Q_SLOTS:
void editColorScheme();
void saveColorScheme(const ColorScheme &scheme, bool isNewScheme);
void removeColorScheme();
void gotNewColorSchemes(const KNS3::Entry::List &changedEntries);
/**
* Deletes the selected colorscheme from the user's home dir location

View File

@@ -467,44 +467,7 @@
<bool>true</bool>
</property>
<layout class="QGridLayout">
<item row="0" column="0" rowspan="5">
<widget class="QListView" name="colorSchemeList">
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="newColorSchemeButton">
<property name="toolTip">
<string>Create a new color scheme based upon the selected scheme</string>
</property>
<property name="text">
<string comment="@action:button Create an alternate color scheme">New...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="editColorSchemeButton">
<property name="toolTip">
<string>Edit the selected color scheme</string>
</property>
<property name="text">
<string>Edit...</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="removeColorSchemeButton">
<property name="toolTip">
<string>Delete the selected color scheme</string>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QPushButton" name="resetColorSchemeButton">
<property name="toolTip">
<string>Reset the selected color scheme settings to the default values</string>
@@ -514,7 +477,41 @@
</property>
</widget>
</item>
<item row="4" column="1">
<item row="3" column="1">
<widget class="QPushButton" name="removeColorSchemeButton">
<property name="toolTip">
<string>Delete the selected color scheme</string>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="6">
<widget class="QListView" name="colorSchemeList">
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="KNS3::Button" name="downloadColorSchemeButton">
<property name="text">
<string>Get New...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="newColorSchemeButton">
<property name="toolTip">
<string>Create a new color scheme based upon the selected scheme</string>
</property>
<property name="text">
<string comment="@action:button Create an alternate color scheme">New...</string>
</property>
</widget>
</item>
<item row="6" column="1">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -527,9 +524,29 @@
</property>
</spacer>
</item>
<item row="5" column="0">
<item row="7" column="0">
<widget class="KMessageWidget" name="transparencyWarningWidget"/>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="editColorSchemeButton">
<property name="toolTip">
<string>Edit the selected color scheme</string>
</property>
<property name="text">
<string>Edit...</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="KMessageWidget" name="colorSchemeMessageWidget">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -1489,6 +1506,11 @@
<extends>QComboBox</extends>
<header>kcombobox.h</header>
</customwidget>
<customwidget>
<class>KNS3::Button</class>
<extends>QPushButton</extends>
<header location="global">KNS3/Button</header>
</customwidget>
<customwidget>
<class>KPluralHandlingSpinBox</class>
<extends>QSpinBox</extends>
@@ -1507,7 +1529,7 @@
<customwidget>
<class>KMessageWidget</class>
<extends>QFrame</extends>
<header>kmessagewidget.h</header>
<header location="global">kmessagewidget.h</header>
<container>1</container>
</customwidget>
<customwidget>