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"