Warning, file /frameworks/kdeclarative/src/quickaddons/configmodule.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     This file is part of the KDE libraries
0003 
0004     SPDX-FileCopyrightText: 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
0005     SPDX-FileCopyrightText: 2001 Michael Goffioul <kdeprint@swing.be>
0006     SPDX-FileCopyrightText: 2004 Frans Englich <frans.englich@telia.com>
0007     SPDX-FileCopyrightText: 2009 Dario Freddi <drf@kde.org>
0008     SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
0009 
0010     SPDX-License-Identifier: LGPL-2.0-or-later
0011 */
0012 
0013 #include "configmodule.h"
0014 
0015 #include <QDebug>
0016 #include <QQmlContext>
0017 #include <QQmlEngine>
0018 #include <QQmlFileSelector>
0019 #include <QQuickItem>
0020 #include <QUrl>
0021 
0022 #include <KAboutData>
0023 #include <KLocalizedString>
0024 #include <kdeclarative/qmlobject.h>
0025 #include <kdeclarative/qmlobjectsharedengine.h>
0026 
0027 #include <KPackage/Package>
0028 #include <KPackage/PackageLoader>
0029 
0030 #include <memory>
0031 
0032 namespace KQuickAddons
0033 {
0034 class ConfigModulePrivate
0035 {
0036 public:
0037     ConfigModulePrivate(ConfigModule *module)
0038         : _q(module)
0039         , _qmlObject(nullptr)
0040         , _buttons(ConfigModule::Help | ConfigModule::Default | ConfigModule::Apply)
0041         , _useRootOnlyMessage(false)
0042         , _needsAuthorization(false)
0043         , _needsSave(false)
0044         , _representsDefaults(false)
0045         , _defaultsIndicatorVisible(false)
0046     {
0047     }
0048 
0049     void authStatusChanged(int status);
0050     QString componentName() const;
0051 
0052     ConfigModule *_q;
0053     KDeclarative::QmlObject *_qmlObject;
0054     ConfigModule::Buttons _buttons;
0055     std::unique_ptr<const KAboutData> _about;
0056     KPluginMetaData _metaData;
0057     QString _rootOnlyMessage;
0058     QString _quickHelp;
0059     QString _errorString;
0060     QList<QQuickItem *> subPages;
0061     int _columnWidth = -1;
0062     int currentIndex = 0;
0063     bool _useRootOnlyMessage : 1;
0064 
0065     bool _needsAuthorization : 1;
0066     bool _needsSave : 1;
0067     bool _representsDefaults : 1;
0068     bool _defaultsIndicatorVisible : 1;
0069     QString _authActionName;
0070 
0071     static QHash<QObject *, ConfigModule *> s_rootObjects;
0072 };
0073 
0074 QHash<QObject *, ConfigModule *> ConfigModulePrivate::s_rootObjects = QHash<QObject *, ConfigModule *>();
0075 
0076 QString ConfigModulePrivate::componentName() const
0077 {
0078     if (_about) {
0079         return _about->componentName();
0080     } else {
0081         return _metaData.pluginId();
0082     }
0083 }
0084 
0085 #if QUICKADDONS_BUILD_DEPRECATED_SINCE(5, 88)
0086 ConfigModule::ConfigModule(const KAboutData *aboutData, QObject *parent, const QVariantList &)
0087     : QObject(parent)
0088     , d(new ConfigModulePrivate(this))
0089 {
0090     setAboutData(aboutData);
0091 }
0092 #endif
0093 
0094 #if QUICKADDONS_BUILD_DEPRECATED_SINCE(5, 88)
0095 ConfigModule::ConfigModule(const KPluginMetaData &metaData, QObject *parent, const QVariantList &)
0096     : QObject(parent)
0097     , d(new ConfigModulePrivate(this))
0098 {
0099     KAboutData *aboutData =
0100         new KAboutData(metaData.pluginId(), metaData.name(), metaData.version(), metaData.description(), KAboutLicense::byKeyword(metaData.license()).key());
0101 
0102     const auto authors = metaData.authors();
0103     for (auto &author : authors) {
0104         aboutData->addAuthor(author.name(), author.task(), author.emailAddress(), author.webAddress(), author.ocsUsername());
0105     }
0106     setAboutData(aboutData);
0107 }
0108 #endif
0109 
0110 #if QUICKADDONS_BUILD_DEPRECATED_SINCE(5, 104)
0111 ConfigModule::ConfigModule(QObject *parent, const QVariantList &)
0112     : QObject(parent)
0113     , d(new ConfigModulePrivate(this))
0114 {
0115 }
0116 #endif
0117 
0118 ConfigModule::ConfigModule(QObject *parent, const KPluginMetaData &metaData, const QVariantList &)
0119     : QObject(parent)
0120     , d(new ConfigModulePrivate(this))
0121 {
0122     d->_metaData = metaData;
0123 }
0124 
0125 ConfigModule::~ConfigModule()
0126 {
0127     // in case mainUi was never called
0128     if (d->_qmlObject) {
0129         ConfigModulePrivate::s_rootObjects.remove(d->_qmlObject->rootContext());
0130     }
0131 
0132     delete d->_qmlObject;
0133     delete d;
0134 }
0135 
0136 ConfigModule *ConfigModule::qmlAttachedProperties(QObject *object)
0137 {
0138     // at the moment of the attached object creation, the root item is the only one that hasn't a parent
0139     // only way to avoid creation of this attached for everybody but the root item
0140     const QQmlEngine *engine = qmlEngine(object);
0141     QQmlContext *cont = QQmlEngine::contextForObject(object);
0142 
0143     // Search the qml context that is the "root" for the sharedqmlobject, which
0144     // is an ancestor of QQmlEngine::contextForObject(object) and the direct child
0145     // of the engine's root context: we can do this assumption on the internals as
0146     // we are distributed on the same repo.
0147     while (cont->parentContext() && cont->parentContext() != engine->rootContext()) {
0148         cont = cont->parentContext();
0149     }
0150 
0151     if (!object->parent() && ConfigModulePrivate::s_rootObjects.contains(cont)) {
0152         return ConfigModulePrivate::s_rootObjects.value(cont);
0153     } else {
0154         return nullptr;
0155     }
0156 }
0157 
0158 QQuickItem *ConfigModule::mainUi()
0159 {
0160     if (d->_qmlObject) {
0161         return qobject_cast<QQuickItem *>(d->_qmlObject->rootObject());
0162     }
0163 
0164     d->_errorString.clear();
0165 
0166     // if we have a qml context, hook up to it and use its engine
0167     // this ensure that in e.g. Plasma config dialogs that use a different engine
0168     // so they can have different QtQuick Controls styles, we don't end up using
0169     // the shared engine that is used by the rest of plasma
0170 
0171     QQmlContext *ctx = QQmlEngine::contextForObject(this);
0172 
0173     if (ctx && ctx->engine()) {
0174         d->_qmlObject = new KDeclarative::QmlObject(std::shared_ptr<QQmlEngine>(ctx->engine()), ctx, this);
0175     } else {
0176         d->_qmlObject = new KDeclarative::QmlObjectSharedEngine(this);
0177     }
0178 
0179     ConfigModulePrivate::s_rootObjects[d->_qmlObject->rootContext()] = this;
0180     d->_qmlObject->setTranslationDomain(d->componentName());
0181     d->_qmlObject->setInitializationDelayed(true);
0182 
0183     KPackage::Package package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/GenericQML"));
0184     package.setDefaultPackageRoot(QStringLiteral("kpackage/kcms"));
0185     package.setPath(d->componentName());
0186     if (d->_metaData.isValid() && !package.metadata().isValid()) {
0187         package.setMetadata(d->_metaData);
0188     }
0189 
0190     if (!package.isValid()) {
0191         d->_errorString = i18n("Invalid KPackage '%1'", d->componentName());
0192         qWarning() << "Error loading the module" << d->componentName() << ": invalid KPackage";
0193         return nullptr;
0194     }
0195 
0196     if (package.filePath("mainscript").isEmpty()) {
0197         d->_errorString = i18n("No QML file provided");
0198         qWarning() << "Error loading the module" << d->componentName() << ": no QML file provided";
0199         return nullptr;
0200     }
0201 
0202     new QQmlFileSelector(d->_qmlObject->engine(), d->_qmlObject->engine());
0203     d->_qmlObject->setSource(package.fileUrl("mainscript"));
0204     d->_qmlObject->rootContext()->setContextProperty(QStringLiteral("kcm"), this);
0205     d->_qmlObject->completeInitialization();
0206 
0207     if (d->_qmlObject->status() != QQmlComponent::Ready) {
0208         d->_errorString = d->_qmlObject->mainComponent()->errorString();
0209         return nullptr;
0210     }
0211 
0212     return qobject_cast<QQuickItem *>(d->_qmlObject->rootObject());
0213 }
0214 
0215 void ConfigModule::push(const QString &fileName, const QVariantMap &propertyMap)
0216 {
0217     // ensure main ui is created
0218     if (!mainUi()) {
0219         return;
0220     }
0221 
0222     // TODO: package as member
0223     KPackage::Package package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/GenericQML"));
0224     package.setDefaultPackageRoot(QStringLiteral("kpackage/kcms"));
0225     package.setPath(d->componentName());
0226 
0227     QVariantHash propertyHash;
0228     for (auto it = propertyMap.begin(), end = propertyMap.end(); it != end; ++it) {
0229         propertyHash.insert(it.key(), it.value());
0230     }
0231 
0232     QObject *object = d->_qmlObject->createObjectFromSource(QUrl::fromLocalFile(package.filePath("ui", fileName)), d->_qmlObject->rootContext(), propertyHash);
0233 
0234     QQuickItem *item = qobject_cast<QQuickItem *>(object);
0235     if (!item) {
0236         object->deleteLater();
0237         return;
0238     }
0239 
0240     d->subPages << item;
0241     Q_EMIT pagePushed(item);
0242     Q_EMIT depthChanged(depth());
0243     setCurrentIndex(d->currentIndex + 1);
0244 }
0245 
0246 void ConfigModule::push(QQuickItem *item)
0247 {
0248     // ensure main ui is created
0249     if (!mainUi()) {
0250         return;
0251     }
0252 
0253     d->subPages << item;
0254     Q_EMIT pagePushed(item);
0255     Q_EMIT depthChanged(depth());
0256     setCurrentIndex(d->currentIndex + 1);
0257 }
0258 
0259 void ConfigModule::pop()
0260 {
0261     if (QQuickItem *page = takeLast()) {
0262         page->deleteLater();
0263     }
0264 }
0265 
0266 QQuickItem *ConfigModule::takeLast()
0267 {
0268     if (d->subPages.isEmpty()) {
0269         return nullptr;
0270     }
0271     QQuickItem *page = d->subPages.takeLast();
0272     Q_EMIT pageRemoved();
0273     Q_EMIT depthChanged(depth());
0274     setCurrentIndex(qMin(d->currentIndex, depth() - 1));
0275     return page;
0276 }
0277 
0278 void ConfigModule::showPassiveNotification(const QString &message, const QVariant &timeout, const QString &actionText, const QJSValue &callBack)
0279 {
0280     Q_EMIT passiveNotificationRequested(message, timeout, actionText, callBack);
0281 }
0282 
0283 ConfigModule::Buttons ConfigModule::buttons() const
0284 {
0285     return d->_buttons;
0286 }
0287 
0288 void ConfigModule::setButtons(const KQuickAddons::ConfigModule::Buttons buttons)
0289 {
0290     if (d->_buttons == buttons) {
0291         return;
0292     }
0293 
0294     d->_buttons = buttons;
0295     Q_EMIT buttonsChanged();
0296 }
0297 
0298 void ConfigModule::setNeedsAuthorization(bool needsAuth)
0299 {
0300     if (d->_needsAuthorization == needsAuth) {
0301         return;
0302     }
0303 
0304     d->_needsAuthorization = needsAuth;
0305     if (needsAuth) {
0306         d->_authActionName = QLatin1String("org.kde.kcontrol.") + d->componentName() + QLatin1String(".save");
0307         d->_needsAuthorization = true;
0308 
0309     } else {
0310         d->_authActionName = QString();
0311     }
0312 
0313     Q_EMIT needsAuthorizationChanged();
0314     Q_EMIT authActionNameChanged();
0315 }
0316 
0317 bool ConfigModule::needsAuthorization() const
0318 {
0319     return d->_needsAuthorization;
0320 }
0321 
0322 QString ConfigModule::name() const
0323 {
0324     if (d->_metaData.isValid()) {
0325         return d->_metaData.name();
0326     }
0327     return d->_about->displayName();
0328 }
0329 
0330 QString ConfigModule::description() const
0331 {
0332     if (d->_metaData.isValid()) {
0333         return d->_metaData.description();
0334     }
0335     return d->_about->shortDescription();
0336 }
0337 
0338 int ConfigModule::columnWidth() const
0339 {
0340     return d->_columnWidth;
0341 }
0342 
0343 void ConfigModule::setColumnWidth(int width)
0344 {
0345     if (d->_columnWidth == width) {
0346         return;
0347     }
0348 
0349     d->_columnWidth = width;
0350     Q_EMIT columnWidthChanged(width);
0351 }
0352 
0353 int ConfigModule::depth() const
0354 {
0355     return d->subPages.count() + 1;
0356 }
0357 
0358 void ConfigModule::setCurrentIndex(int index)
0359 {
0360     if (index < 0 || index > d->subPages.count() || index == d->currentIndex) {
0361         return;
0362     }
0363 
0364     d->currentIndex = index;
0365 
0366     Q_EMIT currentIndexChanged(index);
0367 }
0368 
0369 int ConfigModule::currentIndex() const
0370 {
0371     return d->currentIndex;
0372 }
0373 
0374 void ConfigModule::setAuthActionName(const QString &name)
0375 {
0376     if (d->_authActionName == name) {
0377         return;
0378     }
0379 
0380     d->_authActionName = name;
0381     d->_needsAuthorization = true;
0382 
0383     Q_EMIT needsAuthorizationChanged();
0384     Q_EMIT authActionNameChanged();
0385 }
0386 
0387 QString ConfigModule::authActionName() const
0388 {
0389     return d->_authActionName;
0390 }
0391 
0392 QQmlEngine *ConfigModule::engine() const
0393 {
0394     return d->_qmlObject->engine();
0395 }
0396 
0397 QQmlComponent::Status ConfigModule::status() const
0398 {
0399     if (!d->_qmlObject) {
0400         return QQmlComponent::Null;
0401     }
0402 
0403     return d->_qmlObject->status();
0404 }
0405 
0406 QString ConfigModule::errorString() const
0407 {
0408     return d->_errorString;
0409 }
0410 
0411 void ConfigModule::load()
0412 {
0413     setNeedsSave(false);
0414 }
0415 
0416 void ConfigModule::save()
0417 {
0418     setNeedsSave(false);
0419 }
0420 
0421 void ConfigModule::defaults()
0422 {
0423 }
0424 
0425 #if QUICKADDONS_BUILD_DEPRECATED_SINCE(5, 88)
0426 const KAboutData *ConfigModule::aboutData() const
0427 {
0428     // If the ConfigModule was created from a KPluginMetaData lazily create a KAboutData from it
0429     if (d->_metaData.isValid() && !d->_about) {
0430         KAboutData *aboutData = new KAboutData(d->_metaData.pluginId(),
0431                                                d->_metaData.name(),
0432                                                d->_metaData.version(),
0433                                                d->_metaData.description(),
0434                                                KAboutLicense::byKeyword(d->_metaData.license()).key());
0435 
0436         const auto authors = d->_metaData.authors();
0437         for (auto &author : authors) {
0438             aboutData->addAuthor(author.name(), author.task(), author.emailAddress(), author.webAddress(), author.ocsUsername());
0439         }
0440 
0441         d->_about.reset(aboutData);
0442     }
0443 
0444     return d->_about.get();
0445 }
0446 #endif
0447 
0448 #if QUICKADDONS_ENABLE_DEPRECATED_SINCE(5, 104)
0449 void ConfigModule::setAboutData(const KAboutData *about)
0450 {
0451     d->_about.reset(about);
0452 }
0453 #endif
0454 
0455 void ConfigModule::setRootOnlyMessage(const QString &message)
0456 {
0457     if (d->_rootOnlyMessage == message) {
0458         return;
0459     }
0460 
0461     d->_rootOnlyMessage = message;
0462     Q_EMIT rootOnlyMessageChanged();
0463 }
0464 
0465 QString ConfigModule::rootOnlyMessage() const
0466 {
0467     return d->_rootOnlyMessage;
0468 }
0469 
0470 void ConfigModule::setUseRootOnlyMessage(bool on)
0471 {
0472     if (d->_useRootOnlyMessage == on) {
0473         return;
0474     }
0475 
0476     d->_useRootOnlyMessage = on;
0477 
0478     Q_EMIT useRootOnlyMessageChanged();
0479 }
0480 
0481 bool ConfigModule::useRootOnlyMessage() const
0482 {
0483     return d->_useRootOnlyMessage;
0484 }
0485 
0486 QQuickItem *ConfigModule::subPage(int index) const
0487 {
0488     return d->subPages[index];
0489 }
0490 
0491 void ConfigModule::setQuickHelp(const QString &help)
0492 {
0493     if (d->_quickHelp == help) {
0494         return;
0495     }
0496 
0497     d->_quickHelp = help;
0498 
0499     Q_EMIT quickHelpChanged();
0500 }
0501 
0502 QString ConfigModule::quickHelp() const
0503 {
0504     return d->_quickHelp;
0505 }
0506 
0507 void ConfigModule::setNeedsSave(bool needs)
0508 {
0509     if (needs == d->_needsSave) {
0510         return;
0511     }
0512 
0513     d->_needsSave = needs;
0514     Q_EMIT needsSaveChanged();
0515 }
0516 
0517 bool ConfigModule::needsSave()
0518 {
0519     return d->_needsSave;
0520 }
0521 
0522 void ConfigModule::setRepresentsDefaults(bool defaults)
0523 {
0524     if (defaults == d->_representsDefaults) {
0525         return;
0526     }
0527 
0528     d->_representsDefaults = defaults;
0529     Q_EMIT representsDefaultsChanged();
0530 }
0531 
0532 bool ConfigModule::representsDefaults()
0533 {
0534     return d->_representsDefaults;
0535 }
0536 
0537 bool ConfigModule::defaultsIndicatorsVisible() const
0538 {
0539     return d->_defaultsIndicatorVisible;
0540 }
0541 
0542 void ConfigModule::setDefaultsIndicatorsVisible(bool visible)
0543 {
0544     if (d->_defaultsIndicatorVisible == visible) {
0545         return;
0546     }
0547     d->_defaultsIndicatorVisible = visible;
0548     Q_EMIT defaultsIndicatorsVisibleChanged();
0549 }
0550 }
0551 
0552 #include "moc_configmodule.cpp"