KDeclarative

configmodule.cpp
1 /*
2  This file is part of the KDE libraries
3 
4  SPDX-FileCopyrightText: 1999 Matthias Hoelzer-Kluepfel <[email protected]>
5  SPDX-FileCopyrightText: 2001 Michael Goffioul <[email protected]>
6  SPDX-FileCopyrightText: 2004 Frans Englich <[email protected]>
7  SPDX-FileCopyrightText: 2009 Dario Freddi <[email protected]>
8  SPDX-FileCopyrightText: 2015 Marco Martin <[email protected]>
9 
10  SPDX-License-Identifier: LGPL-2.0-or-later
11 */
12 
13 #include "configmodule.h"
14 
15 #include <QDebug>
16 #include <QUrl>
17 #include <QQmlEngine>
18 #include <QQmlContext>
19 #include <QQuickItem>
20 #include <QQmlEngine>
21 #include <QQmlFileSelector>
22 
23 #include <KAboutData>
24 #include <KLocalizedString>
25 #include <kdeclarative/qmlobject.h>
26 #include <kdeclarative/qmlobjectsharedengine.h>
27 
28 #include <KPackage/Package>
29 #include <KPackage/PackageLoader>
30 
31 namespace KQuickAddons {
32 
33 class ConfigModulePrivate
34 {
35 public:
36  ConfigModulePrivate(ConfigModule *module):
37  _q(module),
38  _qmlObject(nullptr),
39  _buttons(ConfigModule::Help | ConfigModule::Default | ConfigModule::Apply),
40  _about(nullptr),
41  _useRootOnlyMessage(false),
42  _needsAuthorization(false),
43  _needsSave(false),
44  _representsDefaults(false),
45  _defaultsIndicatorVisible(false)
46  {
47  }
48 
49  void authStatusChanged(int status);
50 
51  ConfigModule *_q;
52  KDeclarative::QmlObject *_qmlObject;
53  ConfigModule::Buttons _buttons;
54  const KAboutData *_about;
55  QString _rootOnlyMessage;
56  QString _quickHelp;
57  QString _errorString;
58  QList<QQuickItem *> subPages;
59  int _columnWidth = -1;
60  int currentIndex = 0;
61  bool _useRootOnlyMessage : 1;
62 
63  bool _needsAuthorization : 1;
64  bool _needsSave :1;
65  bool _representsDefaults :1;
66  bool _defaultsIndicatorVisible :1;
67  QString _authActionName;
68 
69  static QHash<QObject *, ConfigModule *> s_rootObjects;
70 };
71 
72 QHash<QObject *, ConfigModule *> ConfigModulePrivate::s_rootObjects = QHash<QObject *, ConfigModule *>();
73 
74 
75 ConfigModule::ConfigModule(const KAboutData *aboutData, QObject *parent, const QVariantList &)
76  : QObject(parent), d(new ConfigModulePrivate(this))
77 {
78  setAboutData(aboutData);
79 }
80 
81 ConfigModule::ConfigModule(const KPluginMetaData &metaData, QObject *parent, const QVariantList &)
82  : QObject(parent), d(new ConfigModulePrivate(this))
83 {
84  KAboutData *aboutData = new KAboutData(metaData.pluginId(), metaData.name(), metaData.version(), metaData.description(), KAboutLicense::byKeyword(metaData.license()).key());
85 
86  const auto authors = metaData.authors();
87  for (auto& author : authors) {
88  aboutData->addAuthor(author.name(), author.task(), author.emailAddress(), author.webAddress(), author.ocsUsername());
89  }
90  setAboutData(aboutData);
91 }
92 
93 ConfigModule::ConfigModule(QObject *parent, const QVariantList &)
94  : QObject(parent), d(new ConfigModulePrivate(this))
95 {
96 }
97 
99 {
100  //in case mainUi was never called
101  if (d->_qmlObject) {
102  ConfigModulePrivate::s_rootObjects.remove(d->_qmlObject->rootContext());
103  }
104 
105  delete d->_qmlObject;
106  delete d->_about;
107  delete d;
108 }
109 
110 
111 
112 ConfigModule *ConfigModule::qmlAttachedProperties(QObject *object)
113 {
114  //at the moment of the attached object creation, the root item is the only one that hasn't a parent
115  //only way to avoid creation of this attached for everybody but the root item
116  const QQmlEngine *engine = QtQml::qmlEngine(object);
118 
119  //Search the qml context that is the "root" for the sharedqmlobject, which
120  //is an ancestor of QQmlEngine::contextForObject(object) and the direct child
121  //of the engine's root context: we can do this assumption on the internals as
122  //we are distributed on the same repo.
123  while (cont->parentContext() && cont->parentContext() != engine->rootContext()) {
124  cont = cont->parentContext();
125  }
126 
127  if (!object->parent() && ConfigModulePrivate::s_rootObjects.contains(cont)) {
128  return ConfigModulePrivate::s_rootObjects.value(cont);
129  } else {
130  return nullptr;
131  }
132 }
133 
135 {
136  if (d->_qmlObject) {
137  return qobject_cast<QQuickItem *>(d->_qmlObject->rootObject());
138  }
139 
140  d->_errorString.clear();
141 
142  // if we have a qml context, hook up to it and use its engine
143  // this ensure that in e.g. Plasma config dialogs that use a different engine
144  // so they can have different QtQuick Controls styles, we don't end up using
145  // the shared engine that is used by the rest of plasma
146 
148 
149  if (ctx && ctx->engine()) {
150  d->_qmlObject = new KDeclarative::QmlObject(ctx->engine(), ctx, this);
151  } else {
152  d->_qmlObject = new KDeclarative::QmlObjectSharedEngine(this);
153  }
154 
155  ConfigModulePrivate::s_rootObjects[d->_qmlObject->rootContext()] = this;
156  d->_qmlObject->setTranslationDomain(aboutData()->componentName());
157  d->_qmlObject->setInitializationDelayed(true);
158 
159  KPackage::Package package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/GenericQML"));
160  package.setDefaultPackageRoot(QStringLiteral("kpackage/kcms"));
161  package.setPath(aboutData()->componentName());
162 
163  if (!package.isValid()) {
164  d->_errorString = i18n("Invalid KPackage '%1'", aboutData()->componentName());
165  qWarning() << "Error loading the module" << aboutData()->componentName() << ": invalid KPackage";
166  return nullptr;
167  }
168 
169  if (package.filePath("mainscript").isEmpty()) {
170  d->_errorString = i18n("No QML file provided");
171  qWarning() << "Error loading the module" << aboutData()->componentName() << ": no QML file provided";
172  return nullptr;
173  }
174 
175  new QQmlFileSelector(d->_qmlObject->engine(), d->_qmlObject->engine());
176  d->_qmlObject->setSource(package.fileUrl("mainscript"));
177  d->_qmlObject->rootContext()->setContextProperty(QStringLiteral("kcm"), this);
178  d->_qmlObject->completeInitialization();
179 
180  if (d->_qmlObject->status() != QQmlComponent::Ready) {
181  d->_errorString = d->_qmlObject->mainComponent()->errorString();
182  return nullptr;
183  }
184 
185  return qobject_cast<QQuickItem *>(d->_qmlObject->rootObject());
186 }
187 
188 void ConfigModule::push(const QString &fileName, const QVariantMap &propertyMap)
189 {
190  //ensure main ui is created
191  if (!mainUi()) {
192  return;
193  }
194 
195  //TODO: package as member
196  KPackage::Package package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/GenericQML"));
197  package.setDefaultPackageRoot(QStringLiteral("kpackage/kcms"));
198  package.setPath(aboutData()->componentName());
199 
200  QVariantHash propertyHash;
201  for (auto it = propertyMap.begin(), end = propertyMap.end(); it != end; ++it) {
202  propertyHash.insert(it.key(), it.value());
203  }
204 
205  QObject *object = d->_qmlObject->createObjectFromSource(QUrl::fromLocalFile(package.filePath("ui", fileName)),
206  d->_qmlObject->rootContext(),
207  propertyHash);
208 
209  QQuickItem *item = qobject_cast<QQuickItem *>(object);
210  if (!item) {
211  object->deleteLater();
212  return;
213  }
214 
215  d->subPages << item;
216  Q_EMIT pagePushed(item);
218  setCurrentIndex(d->currentIndex + 1);
219 }
220 
221 void ConfigModule::push(QQuickItem *item)
222 {
223  //ensure main ui is created
224  if (!mainUi()) {
225  return;
226  }
227 
228  d->subPages << item;
229  Q_EMIT pagePushed(item);
231  setCurrentIndex(d->currentIndex + 1);
232 }
233 
235 {
236  if (d->subPages.isEmpty()) {
237  return;
238  }
239  QQuickItem *page = d->subPages.takeLast();
242  page->deleteLater();
243 
244  setCurrentIndex(qMin(d->currentIndex, depth() - 1));
245 }
246 
247 void ConfigModule::showPassiveNotification(const QString &message, const QVariant &timeout, const QString &actionText, const QJSValue &callBack)
248 {
249  Q_EMIT passiveNotificationRequested(message, timeout, actionText, callBack);
250 }
251 
253 {
254  return d->_buttons;
255 }
256 
258 {
259  if (d->_buttons == buttons) {
260  return;
261  }
262 
263  d->_buttons = buttons;
265 }
266 
268 {
269  if (d->_needsAuthorization == needsAuth) {
270  return;
271  }
272 
273  d->_needsAuthorization = needsAuth;
274  if (needsAuth && d->_about) {
275  d->_authActionName = QLatin1String("org.kde.kcontrol.") + d->_about->componentName() + QLatin1String(".save");
276  d->_needsAuthorization = true;
277 
278  } else {
279  d->_authActionName = QString();
280  }
281 
284 }
285 
287 {
288  return d->_needsAuthorization;
289 }
290 
292 {
293  return d->_about->displayName();
294 }
295 
297 {
298  return d->_about->shortDescription();
299 }
300 
301 int ConfigModule::columnWidth() const
302 {
303  return d->_columnWidth;
304 }
305 
307 {
308  if (d->_columnWidth == width) {
309  return;
310  }
311 
312  d->_columnWidth = width;
313  Q_EMIT columnWidthChanged(width);
314 }
315 
316 int ConfigModule::depth() const
317 {
318  return d->subPages.count() + 1;
319 }
320 
322 {
323  if (index < 0 || index > d->subPages.count() || index == d->currentIndex) {
324  return;
325  }
326 
327  d->currentIndex = index;
328 
330 }
331 
332 int ConfigModule::currentIndex() const
333 {
334  return d->currentIndex;
335 }
336 
338 {
339  if (d->_authActionName == name) {
340  return;
341  }
342 
343  d->_authActionName = name;
344  d->_needsAuthorization = true;
345 
348 }
349 
351 {
352  return d->_authActionName;
353 }
354 
356 {
357  return d->_qmlObject->engine();
358 }
359 
361 {
362  if (!d->_qmlObject) {
363  return QQmlComponent::Null;
364  }
365 
366  return d->_qmlObject->status();
367 }
368 
370 {
371  return d->_errorString;
372 }
373 
375 {
376  setNeedsSave(false);
377 }
378 
380 {
381  setNeedsSave(false);
382 }
383 
385 {
386 }
387 
389 {
390  return d->_about;
391 }
392 
394 {
395  if (about != d->_about) {
396  delete d->_about;
397  d->_about = about;
398  }
399 }
400 
402 {
403  if (d->_rootOnlyMessage == message) {
404  return;
405  }
406 
407  d->_rootOnlyMessage = message;
409 }
410 
412 {
413  return d->_rootOnlyMessage;
414 }
415 
417 {
418  if (d->_useRootOnlyMessage == on) {
419  return;
420  }
421 
422  d->_useRootOnlyMessage = on;
423 
425 }
426 
428 {
429  return d->_useRootOnlyMessage;
430 }
431 
432 QQuickItem *ConfigModule::subPage(int index) const
433 {
434  return d->subPages[index];
435 }
436 
438 {
439  if (d->_quickHelp == help) {
440  return;
441  }
442 
443  d->_quickHelp = help;
444 
446 }
447 
449 {
450  return d->_quickHelp;
451 }
452 
454 {
455  if (needs == d->_needsSave) {
456  return;
457  }
458 
459  d->_needsSave = needs;
461 }
462 
464 {
465  return d->_needsSave;
466 }
467 
469 {
470  if (defaults == d->_representsDefaults) {
471  return;
472  }
473 
474  d->_representsDefaults = defaults;
476 }
477 
479 {
480  return d->_representsDefaults;
481 }
482 
484 {
485  return d->_defaultsIndicatorVisible;
486 }
487 
489 {
490  if (d->_defaultsIndicatorVisible == visible) {
491  return;
492  }
493  d->_defaultsIndicatorVisible = visible;
495 }
496 }
497 
498 #include "moc_configmodule.cpp"
499 
void defaultsIndicatorsVisibleChanged()
Emitted when kcm need to display indicators for field with non default value.
const KAboutData * aboutData() const
This is generally only called for the KBugReport.
QString description() const
void setNeedsSave(bool needs)
Set this property to true when the user changes something in the module, signaling that a save (such ...
QList< KAboutPerson > authors() const
virtual void save()
Save the configuration data.
virtual void defaults()
Sets the configuration to sensible default values.
QString name() const
QString componentName() const
void representsDefaultsChanged()
Indicate that the state of the modules contents has changed in a way that it might represents the def...
QQmlEngine * engine() const
void setCurrentIndex(int index)
Sets the current page index this kcm should display.
void authActionNameChanged()
The auth action name has changed: this signal will relay it to the actual KCM.
int columnWidth() const
returns the width the kcm wants in column mode.
QQmlContext * parentContext() const const
void setUseRootOnlyMessage(bool on)
Change whether or not the RootOnly message should be shown.
void needsAuthorizationChanged()
Emits this signal whenever the need for root authorization to save changes.
An object that instantiates an entire QML context, with its own declarative engine.
Definition: qmlobject.h:38
An object that instantiates an entire QML context, with its own declarative engine.
void setColumnWidth(int width)
Sets the column width we want.
bool useRootOnlyMessage() const
Tell if KControl should show a RootOnly message when run as a normal user.
void setRepresentsDefaults(bool defaults)
Set this property to true when the user sets the state of the module to the default settings (e...
void showPassiveNotification(const QString &message, const QVariant &timeout=QVariant(), const QString &actionText=QString(), const QJSValue &callBack=QJSValue())
Ask the shell to show a passive notification.
QString rootOnlyMessage() const
Get the RootOnly message for this module.
void setDefaultPackageRoot(const QString &packageRoot)
KAboutData & addAuthor(const QString &name, const QString &task=QString(), const QString &emailAddress=QString(), const QString &webAddress=QString(), const QString &ocsUsername=QString())
void buttonsChanged()
Buttons to display changed.
void setAboutData(const KAboutData *about)
This sets the KAboutData returned by aboutData() The about data is now owned by ConfigModule.
void useRootOnlyMessageChanged()
Emits this signal whenever the root only message gets used or discarded.
void currentIndexChanged(int index)
Emitted when the current page changed.
void pagePushed(QQuickItem *page)
Emitted when a new sub page is pushed.
void columnWidthChanged(int width)
Emitted when the wanted column width of the kcm changes.
The base class for configuration modules.
Definition: configmodule.h:114
void quickHelpChanged()
Indicate that the module&#39;s quickhelp has changed.
~ConfigModule()
Destroys the module.
void deleteLater()
QQmlContext * rootContext() const const
int remove(const Key &key)
bool needsSave()
True when the module has something changed and needs save.
QQmlEngine * engine() const const
void setQuickHelp(const QString &help)
Sets the quick help.
const T value(const Key &key) const const
Buttons buttons() const
Indicate which buttons will be used.
void setAuthActionName(const QString &action)
Set if the module&#39;s save() method requires authorization to be executed.
QString license() const
QString i18n(const char *text, const TYPE &arg...)
QString authActionName() const
Returns the action previously set with setAuthActionName().
void setDefaultsIndicatorsVisible(bool visible)
Change defaultness indicator visibility.
ConfigModule(const KAboutData *aboutData, QObject *parent=nullptr, const QVariantList &args=QVariantList())
Base class for all KControlModules.
static KAboutLicense byKeyword(const QString &keyword)
void passiveNotificationRequested(const QString &message, const QVariant &timeout, const QString &actionText, const QJSValue &callBack)
Emitted when the kcm wants the shell to display a passive notification.
void pop()
pop the last page of the KCM hierarchy
void setRootOnlyMessage(const QString &message)
Sets the RootOnly message.
QQmlContext * contextForObject(const QObject *object)
void setButtons(const Buttons btn)
Sets the buttons to display.
bool representsDefaults()
True when the module state represents the default settings.
bool needsAuthorization() const
Returns the value previously set with setNeedsAuthorization() or setAuthActionName().
bool contains(const Key &key) const const
QString quickHelp() const
Return a quick-help text.
void depthChanged(int index)
Emitted when the number of pages changed.
void pageRemoved()
Emitted when a sub page is popped.
QString description() const
QString errorString() const
The error string in case the mainUi failed to load.
T qobject_cast(QObject *object)
QObject * parent() const const
void rootOnlyMessageChanged()
Indicate that the module&#39;s root message has changed.
bool defaultsIndicatorsVisible() const
void push(const QString &fileName, const QVariantMap &propertyMap=QVariantMap())
Push a new sub page in the KCM hierarchy: pages will be seen as a Kirigami PageRow.
Q_EMITQ_EMIT
QString pluginId() const
QUrl fromLocalFile(const QString &localFile)
QString version() const
virtual void load()
Load the configuration data into the module.
QQmlComponent::Status status() const
The status of the mainUi component.
void setNeedsAuthorization(bool needsAuth)
Set if the module&#39;s save() method requires authorization to be executed.
void needsSaveChanged()
Indicate that the state of the modules contents has changed.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Jan 25 2021 22:44:28 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.