2034e7e875
KNewStuff is no longer hard-coded to Aurorae themes. Instead the availability of KNewStuff is derived from the available plugin metadata. If the section org.kde.kdecoration2 contains a key "KNewStuff" it's value is interpreted as the knsrc config file name. If there is at least one plugin with such a key KNS gets enabled. If there are multiple plugins providing KNS support the download button is turned into a button with a connected menu and each menu entry points to one of the available resources. Of course this is not optimal, but KNS doesn't allow the combining of multiple config files.
271 lines
11 KiB
C++
271 lines
11 KiB
C++
/*
|
|
* Copyright 2014 Martin Gräßlin <mgraesslin@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 the Free Software Foundation; either version 2 of
|
|
* the License or (at your option) version 3 or any later version
|
|
* accepted by the membership of KDE e.V. (or its successor approved
|
|
* by the membership of KDE e.V.), which shall act as a proxy
|
|
* defined in Section 14 of version 3 of the license.
|
|
*
|
|
* 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. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "kcm.h"
|
|
#include "decorationmodel.h"
|
|
|
|
// KDE
|
|
#include <KConfigGroup>
|
|
#include <KPluginFactory>
|
|
#include <KSharedConfig>
|
|
#include <KDecoration2/DecorationButton>
|
|
#include <KNewStuff3/KNS3/DownloadDialog>
|
|
// Qt
|
|
#include <QDBusConnection>
|
|
#include <QDBusMessage>
|
|
#include <QMenu>
|
|
#include <QQmlContext>
|
|
#include <QQmlEngine>
|
|
#include <QQuickItem>
|
|
#include <QSortFilterProxyModel>
|
|
#include <QStandardPaths>
|
|
#include <QVBoxLayout>
|
|
|
|
K_PLUGIN_FACTORY(KDecorationFactory,
|
|
registerPlugin<KDecoration2::Configuration::ConfigurationModule>();
|
|
)
|
|
|
|
Q_DECLARE_METATYPE(KDecoration2::BorderSize)
|
|
|
|
namespace KDecoration2
|
|
{
|
|
|
|
namespace Configuration
|
|
{
|
|
static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2");
|
|
static const QString s_defaultPlugin = QStringLiteral("org.kde.breeze");
|
|
static const QString s_borderSizeNormal = QStringLiteral("Normal");
|
|
static const QString s_ghnsIcon = QStringLiteral("get-hot-new-stuff");
|
|
|
|
ConfigurationForm::ConfigurationForm(QWidget *parent)
|
|
: QWidget(parent)
|
|
{
|
|
setupUi(this);
|
|
}
|
|
|
|
static bool s_loading = false;
|
|
|
|
ConfigurationModule::ConfigurationModule(QWidget *parent, const QVariantList &args)
|
|
: KCModule(parent, args)
|
|
, m_model(new DecorationsModel(this))
|
|
, m_proxyModel(new QSortFilterProxyModel(this))
|
|
, m_ui(new ConfigurationForm(this))
|
|
{
|
|
m_proxyModel->setSourceModel(m_model);
|
|
m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
connect(m_ui->filter, &QLineEdit::textChanged, m_proxyModel, &QSortFilterProxyModel::setFilterFixedString);
|
|
|
|
m_ui->view->rootContext()->setContextProperty(QStringLiteral("decorationsModel"), m_proxyModel);
|
|
m_ui->view->rootContext()->setContextProperty("highlightColor", QPalette().color(QPalette::Highlight));
|
|
m_ui->view->rootContext()->setContextProperty("_borderSizesIndex", 3); // 3 is normal
|
|
m_ui->view->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
|
m_ui->view->setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/kcm_kwindecoration/main.qml"))));
|
|
if (m_ui->view->status() == QQuickWidget::Ready) {
|
|
auto listView = m_ui->view->rootObject()->findChild<QQuickItem*>("listView");
|
|
if (listView) {
|
|
connect(listView, SIGNAL(currentIndexChanged()), this, SLOT(changed()));
|
|
}
|
|
}
|
|
m_ui->doubleClickMessage->setVisible(false);
|
|
m_ui->doubleClickMessage->setText(i18n("Close by double clicking:\n To open the menu, keep the button pressed until it appears."));
|
|
m_ui->doubleClickMessage->setCloseButtonVisible(true);
|
|
m_ui->borderSizesCombo->setItemData(0, QVariant::fromValue(BorderSize::None));
|
|
m_ui->borderSizesCombo->setItemData(1, QVariant::fromValue(BorderSize::NoSides));
|
|
m_ui->borderSizesCombo->setItemData(2, QVariant::fromValue(BorderSize::Tiny));
|
|
m_ui->borderSizesCombo->setItemData(3, QVariant::fromValue(BorderSize::Normal));
|
|
m_ui->borderSizesCombo->setItemData(4, QVariant::fromValue(BorderSize::Large));
|
|
m_ui->borderSizesCombo->setItemData(5, QVariant::fromValue(BorderSize::VeryLarge));
|
|
m_ui->borderSizesCombo->setItemData(6, QVariant::fromValue(BorderSize::Huge));
|
|
m_ui->borderSizesCombo->setItemData(7, QVariant::fromValue(BorderSize::VeryHuge));
|
|
m_ui->borderSizesCombo->setItemData(8, QVariant::fromValue(BorderSize::Oversized));
|
|
m_ui->knsButton->setIcon(QIcon::fromTheme(s_ghnsIcon));
|
|
|
|
connect(m_ui->closeWindowsDoubleClick, &QCheckBox::stateChanged, this,
|
|
static_cast<void (ConfigurationModule::*)()>(&ConfigurationModule::changed));
|
|
connect(m_ui->closeWindowsDoubleClick, &QCheckBox::toggled, this,
|
|
[this] (bool toggled) {
|
|
if (!toggled || s_loading) {
|
|
return;
|
|
}
|
|
m_ui->doubleClickMessage->animatedShow();
|
|
}
|
|
);
|
|
connect(m_ui->borderSizesCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
|
this, [this] (int index) {
|
|
auto listView = m_ui->view->rootObject()->findChild<QQuickItem*>("listView");
|
|
if (listView) {
|
|
listView->setProperty("borderSizesIndex", index);
|
|
}
|
|
changed();
|
|
}
|
|
);
|
|
connect(m_model, &QAbstractItemModel::modelReset, this,
|
|
[this] {
|
|
const auto &kns = m_model->knsProviders();
|
|
m_ui->knsButton->setEnabled(!kns.isEmpty());
|
|
if (kns.isEmpty()) {
|
|
return;
|
|
}
|
|
if (kns.count() > 1) {
|
|
QMenu *menu = new QMenu(m_ui->knsButton);
|
|
for (auto it = kns.begin(); it != kns.end(); ++it) {
|
|
QAction *action = menu->addAction(QIcon::fromTheme(s_ghnsIcon), it.value());
|
|
action->setData(it.key());
|
|
connect(action, &QAction::triggered, this, [this, action] { showKNS(action->data().toString());});
|
|
}
|
|
m_ui->knsButton->setMenu(menu);
|
|
}
|
|
}
|
|
);
|
|
connect(m_ui->knsButton, &QPushButton::clicked, this,
|
|
[this] {
|
|
const auto &kns = m_model->knsProviders();
|
|
if (kns.isEmpty()) {
|
|
return;
|
|
}
|
|
showKNS(kns.firstKey());
|
|
}
|
|
);
|
|
|
|
QVBoxLayout *l = new QVBoxLayout(this);
|
|
l->addWidget(m_ui);
|
|
QMetaObject::invokeMethod(m_model, "init", Qt::QueuedConnection);
|
|
}
|
|
|
|
ConfigurationModule::~ConfigurationModule() = default;
|
|
|
|
void ConfigurationModule::showEvent(QShowEvent *ev)
|
|
{
|
|
KCModule::showEvent(ev);
|
|
}
|
|
|
|
static const QMap<QString, KDecoration2::BorderSize> s_sizes = QMap<QString, KDecoration2::BorderSize>({
|
|
{QStringLiteral("None"), BorderSize::None},
|
|
{QStringLiteral("NoSides"), BorderSize::NoSides},
|
|
{QStringLiteral("Tiny"), BorderSize::Tiny},
|
|
{s_borderSizeNormal, BorderSize::Normal},
|
|
{QStringLiteral("Large"), BorderSize::Large},
|
|
{QStringLiteral("VeryLarge"), BorderSize::VeryLarge},
|
|
{QStringLiteral("Huge"), BorderSize::Huge},
|
|
{QStringLiteral("VeryHuge"), BorderSize::VeryHuge},
|
|
{QStringLiteral("Oversized"), BorderSize::Oversized}
|
|
});
|
|
|
|
static BorderSize stringToSize(const QString &name)
|
|
{
|
|
auto it = s_sizes.constFind(name);
|
|
if (it == s_sizes.constEnd()) {
|
|
// non sense values are interpreted just like normal
|
|
return BorderSize::Normal;
|
|
}
|
|
return it.value();
|
|
}
|
|
|
|
static QString sizeToString(BorderSize size)
|
|
{
|
|
return s_sizes.key(size, s_borderSizeNormal);
|
|
}
|
|
|
|
void ConfigurationModule::load()
|
|
{
|
|
s_loading = true;
|
|
const KConfigGroup config = KSharedConfig::openConfig("kwinrc")->group(s_pluginName);
|
|
const QString plugin = config.readEntry("library", s_defaultPlugin);
|
|
const QString theme = config.readEntry("theme", QString());
|
|
const QModelIndex index = m_proxyModel->mapFromSource(m_model->findDecoration(plugin, theme));
|
|
if (auto listView = m_ui->view->rootObject()->findChild<QQuickItem*>("listView")) {
|
|
listView->setProperty("currentIndex", index.isValid() ? index.row() : -1);
|
|
}
|
|
m_ui->closeWindowsDoubleClick->setChecked(config.readEntry("CloseOnDoubleClickOnMenu", false));
|
|
const QVariant border = QVariant::fromValue(stringToSize(config.readEntry("BorderSize", s_borderSizeNormal)));
|
|
m_ui->borderSizesCombo->setCurrentIndex(m_ui->borderSizesCombo->findData(border));
|
|
KCModule::load();
|
|
s_loading = false;
|
|
}
|
|
|
|
void ConfigurationModule::save()
|
|
{
|
|
KConfigGroup config = KSharedConfig::openConfig("kwinrc")->group(s_pluginName);
|
|
config.writeEntry("CloseOnDoubleClickOnMenu", m_ui->closeWindowsDoubleClick->isChecked());
|
|
config.writeEntry("BorderSize", sizeToString(m_ui->borderSizesCombo->currentData().value<BorderSize>()));
|
|
if (auto listView = m_ui->view->rootObject()->findChild<QQuickItem*>("listView")) {
|
|
const int currentIndex = listView->property("currentIndex").toInt();
|
|
if (currentIndex != -1) {
|
|
const QModelIndex index = m_proxyModel->index(currentIndex, 0);
|
|
if (index.isValid()) {
|
|
config.writeEntry("library", index.data(Qt::UserRole + 4).toString());
|
|
const QString theme = index.data(Qt::UserRole +5).toString();
|
|
if (theme.isEmpty()) {
|
|
config.deleteEntry("theme");
|
|
} else {
|
|
config.writeEntry("theme", theme);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
config.sync();
|
|
KCModule::save();
|
|
// Send signal to all kwin instances
|
|
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
|
|
QStringLiteral("org.kde.KWin"),
|
|
QStringLiteral("reloadConfig"));
|
|
QDBusConnection::sessionBus().send(message);
|
|
}
|
|
|
|
void ConfigurationModule::defaults()
|
|
{
|
|
if (auto listView = m_ui->view->rootObject()->findChild<QQuickItem*>("listView")) {
|
|
const QModelIndex index = m_proxyModel->mapFromSource(m_model->findDecoration(s_defaultPlugin));
|
|
listView->setProperty("currentIndex", index.isValid() ? index.row() : -1);
|
|
}
|
|
m_ui->borderSizesCombo->setCurrentIndex(m_ui->borderSizesCombo->findData(QVariant::fromValue(stringToSize(s_borderSizeNormal))));
|
|
m_ui->closeWindowsDoubleClick->setChecked(false);
|
|
KCModule::defaults();
|
|
}
|
|
|
|
void ConfigurationModule::showKNS(const QString &config)
|
|
{
|
|
QPointer<KNS3::DownloadDialog> downloadDialog = new KNS3::DownloadDialog(config, this);
|
|
if (downloadDialog->exec() == QDialog::Accepted && !downloadDialog->changedEntries().isEmpty()) {
|
|
auto listView = m_ui->view->rootObject()->findChild<QQuickItem*>("listView");
|
|
QString selectedPluginName;
|
|
QString selectedThemeName;
|
|
if (listView) {
|
|
const QModelIndex index = m_proxyModel->index(listView->property("currentIndex").toInt(), 0);
|
|
if (index.isValid()) {
|
|
selectedPluginName = index.data(Qt::UserRole + 4).toString();
|
|
selectedThemeName = index.data(Qt::UserRole + 5).toString();
|
|
}
|
|
}
|
|
m_model->init();
|
|
if (!selectedPluginName.isEmpty()) {
|
|
const QModelIndex index = m_model->findDecoration(selectedPluginName, selectedThemeName);
|
|
const QModelIndex proxyIndex = m_proxyModel->mapFromSource(index);
|
|
if (listView) {
|
|
listView->setProperty("currentIndex", proxyIndex.isValid() ? proxyIndex.row() : -1);
|
|
}
|
|
}
|
|
}
|
|
delete downloadDialog;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#include "kcm.moc"
|