File indexing completed on 2024-05-19 16:34:50

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "genericscriptedconfig.h"
0010 
0011 #include "config-kwin.h"
0012 
0013 #include <kwineffects_interface.h>
0014 
0015 #include <KAboutData>
0016 #define TRANSLATION_DOMAIN "kwin_scripting"
0017 #include <KLocalizedString>
0018 #include <KLocalizedTranslator>
0019 #include <kconfigloader.h>
0020 
0021 #include <QFile>
0022 #include <QLabel>
0023 #include <QStandardPaths>
0024 #include <QUiLoader>
0025 #include <QVBoxLayout>
0026 
0027 namespace KWin
0028 {
0029 
0030 QObject *GenericScriptedConfigFactory::create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args, const QString &keyword)
0031 {
0032     // the plugin id is in the args when created by desktop effects kcm or EffectsModel in general
0033     QString pluginId = args.isEmpty() ? QString() : args.first().toString();
0034 
0035     // If we do not get the id of the effect we want to load from the args, we have to check our metadata.
0036     // This can be the case if the factory gets loaded from a KPluginSelector
0037     // the plugin id is in plugin factory metadata when created by scripts kcm
0038     // (because it uses kpluginselector, which doesn't pass the plugin id as the first arg),
0039     // can be dropped once the scripts kcm is ported to qtquick (because then we could pass the plugin id via the args)
0040     if (pluginId.isEmpty()) {
0041         pluginId = metaData().pluginId();
0042     }
0043     if (pluginId.startsWith(QLatin1String("kwin4_effect_"))) {
0044         return new ScriptedEffectConfig(pluginId, parentWidget, args);
0045     } else {
0046         return new ScriptingConfig(pluginId, parentWidget, args);
0047     }
0048 }
0049 
0050 GenericScriptedConfig::GenericScriptedConfig(const QString &keyword, QWidget *parent, const QVariantList &args)
0051     : KCModule(parent, args)
0052     , m_packageName(keyword)
0053     , m_translator(new KLocalizedTranslator(this))
0054 {
0055     QCoreApplication::instance()->installTranslator(m_translator);
0056 }
0057 
0058 GenericScriptedConfig::~GenericScriptedConfig()
0059 {
0060 }
0061 
0062 void GenericScriptedConfig::createUi()
0063 {
0064     QVBoxLayout *layout = new QVBoxLayout(this);
0065 
0066     const QString packageRoot = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
0067                                                        QLatin1String("kwin/") + typeName() + QLatin1Char('/') + m_packageName,
0068                                                        QStandardPaths::LocateDirectory);
0069     if (packageRoot.isEmpty()) {
0070         layout->addWidget(new QLabel(i18nc("Error message", "Could not locate package metadata")));
0071         return;
0072     }
0073 
0074     KPluginMetaData metaData(packageRoot + QLatin1String("/metadata.json"));
0075 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0076     if (!metaData.isValid()) {
0077         metaData = KPluginMetaData::fromDesktopFile(packageRoot + QLatin1String("/metadata.desktop"));
0078         if (metaData.isValid()) {
0079             qWarning("metadata.desktop format is obsolete. Please convert %s to JSON metadata", qPrintable(metaData.fileName()));
0080         }
0081     }
0082 #endif
0083     if (!metaData.isValid()) {
0084         layout->addWidget(new QLabel(i18nc("Required file does not exist", "%1 does not contain a valid metadata.json file", qPrintable(packageRoot))));
0085         return;
0086     }
0087 
0088     const QString kconfigXTFile = packageRoot + QLatin1String("/contents/config/main.xml");
0089     if (!QFileInfo::exists(kconfigXTFile)) {
0090         layout->addWidget(new QLabel(i18nc("Required file does not exist", "%1 does not exist", qPrintable(kconfigXTFile))));
0091         return;
0092     }
0093 
0094     const QString uiPath = packageRoot + QLatin1String("/contents/ui/config.ui");
0095     if (!QFileInfo::exists(uiPath)) {
0096         layout->addWidget(new QLabel(i18nc("Required file does not exist", "%1 does not exist", qPrintable(uiPath))));
0097         return;
0098     }
0099 
0100     const QString localePath = packageRoot + QLatin1String("/contents/locale");
0101     if (QFileInfo::exists(localePath)) {
0102         KLocalizedString::addDomainLocaleDir(metaData.value("X-KWin-Config-TranslationDomain").toUtf8(), localePath);
0103     }
0104 
0105     QFile xmlFile(kconfigXTFile);
0106     KConfigGroup cg = configGroup();
0107     KConfigLoader *configLoader = new KConfigLoader(cg, &xmlFile, this);
0108     // load the ui file
0109     QUiLoader *loader = new QUiLoader(this);
0110     loader->setLanguageChangeEnabled(true);
0111     QFile uiFile(uiPath);
0112     m_translator->setTranslationDomain(metaData.value("X-KWin-Config-TranslationDomain"));
0113 
0114     uiFile.open(QFile::ReadOnly);
0115     QWidget *customConfigForm = loader->load(&uiFile, this);
0116     m_translator->addContextToMonitor(customConfigForm->objectName());
0117     uiFile.close();
0118 
0119     // send a custom event to the translator to retranslate using our translator
0120     QEvent le(QEvent::LanguageChange);
0121     QCoreApplication::sendEvent(customConfigForm, &le);
0122 
0123     layout->addWidget(customConfigForm);
0124     addConfig(configLoader, customConfigForm);
0125 }
0126 
0127 void GenericScriptedConfig::save()
0128 {
0129     KCModule::save();
0130     reload();
0131 }
0132 
0133 void GenericScriptedConfig::reload()
0134 {
0135 }
0136 
0137 ScriptedEffectConfig::ScriptedEffectConfig(const QString &keyword, QWidget *parent, const QVariantList &args)
0138     : GenericScriptedConfig(keyword, parent, args)
0139 {
0140     createUi();
0141 }
0142 
0143 ScriptedEffectConfig::~ScriptedEffectConfig()
0144 {
0145 }
0146 
0147 QString ScriptedEffectConfig::typeName() const
0148 {
0149     return QStringLiteral("effects");
0150 }
0151 
0152 KConfigGroup ScriptedEffectConfig::configGroup()
0153 {
0154     return KSharedConfig::openConfig(QStringLiteral(KWIN_CONFIG))->group(QLatin1String("Effect-") + packageName());
0155 }
0156 
0157 void ScriptedEffectConfig::reload()
0158 {
0159     OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
0160                                          QStringLiteral("/Effects"),
0161                                          QDBusConnection::sessionBus());
0162     interface.reconfigureEffect(packageName());
0163 }
0164 
0165 ScriptingConfig::ScriptingConfig(const QString &keyword, QWidget *parent, const QVariantList &args)
0166     : GenericScriptedConfig(keyword, parent, args)
0167 {
0168     createUi();
0169 }
0170 
0171 ScriptingConfig::~ScriptingConfig()
0172 {
0173 }
0174 
0175 KConfigGroup ScriptingConfig::configGroup()
0176 {
0177     return KSharedConfig::openConfig(QStringLiteral(KWIN_CONFIG))->group(QLatin1String("Script-") + packageName());
0178 }
0179 
0180 QString ScriptingConfig::typeName() const
0181 {
0182     return QStringLiteral("scripts");
0183 }
0184 
0185 void ScriptingConfig::reload()
0186 {
0187     // TODO: what to call
0188 }
0189 
0190 } // namespace