diff --git a/src/kcmoduleproxy.cpp b/src/kcmoduleproxy.cpp index c5e2656..0a9ff59 100644 --- a/src/kcmoduleproxy.cpp +++ b/src/kcmoduleproxy.cpp @@ -1,293 +1,312 @@ /* This file is part of the KDE project Copyright (C) 2004 Frans Englich Copyright (C) 2003 Matthias Kretz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcmoduleproxy.h" #include "kcmoduleproxy_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kcolorscheme.h" #include "ksettingswidgetadaptor.h" /* TODO: - Resizing horizontally is contrained; minimum size is set somewhere. It appears to be somehow derived from the module's size. - Prettify: set icon in KCMultiDialog. */ /***************************************************************/ KCModule *KCModuleProxy::realModule() const { Q_D(const KCModuleProxy); /* * Note, don't call any function that calls realModule() since * that leads to an infinite loop. */ /* Already loaded */ if (!d->kcm) { QApplication::setOverrideCursor(Qt::WaitCursor); const_cast(d)->loadModule(); QApplication::restoreOverrideCursor(); } return d->kcm; } void KCModuleProxyPrivate::loadModule() { if (!topLayout) { topLayout = new QVBoxLayout(parent); topLayout->setContentsMargins(0, 0, 0, 0); QString name = modInfo.handle(); name.replace(QLatin1Char('-'), QLatin1Char('_')); // hyphen is not allowed in dbus, only [A-Z][a-z][0-9]_ name.replace(QLatin1Char('/'), QLatin1Char('_')); // same goes for '/' dbusService = QLatin1String("org.kde.internal.KSettingsWidget_") + name; // for dbus path, we also need to convert '.' characters name.replace(QLatin1Char('.'), QLatin1Char('_')); dbusPath = QLatin1String("/internal/KSettingsWidget/") + name; } if (QDBusConnection::sessionBus().registerService(dbusService) || bogusOccupier) { /* We got the name we requested, because no one was before us, * or, it was an random application which had picked that name */ // qDebug() << "Module not already loaded, loading module " << modInfo.moduleName() << " from library " << modInfo.library() << " using symbol " << modInfo.handle(); kcm = KCModuleLoader::loadModule(modInfo, KCModuleLoader::Inline, parent, args); QObject::connect(kcm, SIGNAL(changed(bool)), parent, SLOT(_k_moduleChanged(bool))); + QObject::connect(kcm, SIGNAL(defaulted(bool)), parent, SLOT(_k_moduleDefaulted(bool))); QObject::connect(kcm, SIGNAL(destroyed()), parent, SLOT(_k_moduleDestroyed())); QObject::connect(kcm, &KCModule::quickHelpChanged, parent, &KCModuleProxy::quickHelpChanged); parent->setWhatsThis(kcm->quickHelp()); if (kcm->layout()) { kcm->layout()->setContentsMargins(0, 0, 0, 0); } topLayout->addWidget(kcm); if (!modInfo.handle().isEmpty()) { QDBusConnection::sessionBus().registerObject(dbusPath, new KSettingsWidgetAdaptor(parent), QDBusConnection::ExportAllSlots); } } else { // qDebug() << "Module already loaded, loading KCMError"; /* Figure out the name of where the module is already loaded */ QDBusInterface proxy(dbusService, dbusPath, QStringLiteral("org.kde.internal.KSettingsWidget")); QDBusReply reply = proxy.call(QStringLiteral("applicationName")); if (reply.isValid()) { QObject::connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)), parent, SLOT(_k_ownerChanged(QString,QString,QString))); kcm = KCModuleLoader::reportError(KCModuleLoader::Inline, i18nc("Argument is application name", "This configuration section is " "already opened in %1", reply.value()), QStringLiteral(" "), parent); topLayout->addWidget(kcm); } else { // qDebug() << "Calling KCModuleProxy's DBus interface for fetching the name failed."; bogusOccupier = true; loadModule(); } } } void KCModuleProxyPrivate::_k_ownerChanged(const QString &service, const QString &oldOwner, const QString &) { if (service == dbusService && !oldOwner.isEmpty()) { // Violence: Get rid of KCMError & CO, so that // realModule() attempts to reload the module delete kcm; kcm = nullptr; Q_Q(KCModuleProxy); q->realModule(); Q_ASSERT(kcm); kcm->show(); } } void KCModuleProxy::showEvent(QShowEvent *ev) { Q_D(KCModuleProxy); (void)realModule(); /* We have no kcm, if we're in root mode */ if (d->kcm) { d->kcm->showEvent(ev); } QWidget::showEvent(ev); } KCModuleProxy::~KCModuleProxy() { deleteClient(); KCModuleLoader::unloadModule(moduleInfo()); delete d_ptr; } void KCModuleProxy::deleteClient() { Q_D(KCModuleProxy); delete d->kcm; d->kcm = nullptr; } void KCModuleProxyPrivate::_k_moduleChanged(bool c) { if (changed == c) { return; } Q_Q(KCModuleProxy); changed = c; emit q->changed(c); emit q->changed(q); } +void KCModuleProxyPrivate::_k_moduleDefaulted(bool d) +{ + if (defaulted == d) { + return; + } + + Q_Q(KCModuleProxy); + defaulted = d; + emit q->changed(changed); + emit q->changed(q); +} + void KCModuleProxyPrivate::_k_moduleDestroyed() { kcm = nullptr; } KCModuleProxy::KCModuleProxy(const KService::Ptr &service, QWidget *parent, const QStringList &args) : QWidget(parent), d_ptr(new KCModuleProxyPrivate(this, KCModuleInfo(service), args)) { d_ptr->q_ptr = this; } KCModuleProxy::KCModuleProxy(const KCModuleInfo &info, QWidget *parent, const QStringList &args) : QWidget(parent), d_ptr(new KCModuleProxyPrivate(this, info, args)) { d_ptr->q_ptr = this; } KCModuleProxy::KCModuleProxy(const QString &serviceName, QWidget *parent, const QStringList &args) : QWidget(parent), d_ptr(new KCModuleProxyPrivate(this, KCModuleInfo(serviceName), args)) { d_ptr->q_ptr = this; } void KCModuleProxy::load() { Q_D(KCModuleProxy); if (realModule()) { d->kcm->load(); d->_k_moduleChanged(false); } } void KCModuleProxy::save() { Q_D(KCModuleProxy); if (d->changed && realModule()) { d->kcm->save(); d->_k_moduleChanged(false); } } void KCModuleProxy::defaults() { Q_D(KCModuleProxy); if (realModule()) { d->kcm->defaults(); } } QString KCModuleProxy::quickHelp() const { return realModule() ? realModule()->quickHelp() : QString(); } const KAboutData *KCModuleProxy::aboutData() const { return realModule() ? realModule()->aboutData() : nullptr; } KCModule::Buttons KCModuleProxy::buttons() const { if (realModule()) { return realModule()->buttons(); } return KCModule::Buttons(KCModule::Help | KCModule::Default | KCModule::Apply); } bool KCModuleProxy::changed() const { Q_D(const KCModuleProxy); return d->changed; } +bool KCModuleProxy::defaulted() const +{ + Q_D(const KCModuleProxy); + return d->defaulted; +} + KCModuleInfo KCModuleProxy::moduleInfo() const { Q_D(const KCModuleProxy); return d->modInfo; } QString KCModuleProxy::dbusService() const { Q_D(const KCModuleProxy); return d->dbusService; } QString KCModuleProxy::dbusPath() const { Q_D(const KCModuleProxy); return d->dbusPath; } QSize KCModuleProxy::minimumSizeHint() const { return QWidget::minimumSizeHint(); } //X void KCModuleProxy::emitQuickHelpChanged() //X { //X emit quickHelpChanged(); //X } /***************************************************************/ #include "moc_kcmoduleproxy.cpp" diff --git a/src/kcmoduleproxy.h b/src/kcmoduleproxy.h index 35c62fa..b5b62ed 100644 --- a/src/kcmoduleproxy.h +++ b/src/kcmoduleproxy.h @@ -1,231 +1,239 @@ /* This file is part of the KDE project Copyright (C) 2003 Matthias Kretz Copyright (C) 2004 Frans Englich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KCMUTILS_KCMODULEPROXY_H #define KCMUTILS_KCMODULEPROXY_H #include #include #include #include class KAboutData; class KCModuleInfo; class KCModuleProxyPrivate; /** * * @brief Encapsulates a KCModule for embedding. * * KCModuleProxy is a wrapper for KCModule intended for cases where * modules are to be displayed. It ensures layout is consistent * and in general takes care of the details * needed for making a module available in an interface. A KCModuleProxy * can be treated as a QWidget, without worrying about the details specific * for modules such as library loading. KCModuleProxy is not a sub class of KCModule * but its API closely resembles KCModule's.\n * Usually, an instance is created by passing one of the constructors a KService::Ptr, * KCModuleInfo or simply the name of the module and then added to the layout as any * other widget. \n * When the user has changed the module, changed(bool) as well as changed(KCModuleProxy *) * is emitted. KCModuleProxy does not take care of prompting for saving - if the object is deleted while * changes is not saved the changes will be lost. changed() returns true if changes are unsaved. \n * \n * KCModuleProxy does not take care of authorization of KCModules. \n * KCModuleProxy implements lazy loading, meaning the library will not be loaded or * any other initialization done before its show() function is called. This means * modules will only be loaded when they are actually needed as well as it is possible to * load many KCModuleProxy without any speed penalty. * * KCModuleProxy should be used in all cases where modules are embedded in order to * promote code efficiency and usability consistency. * * @author Frans Englich * @author Matthias Kretz * */ class KCMUTILS_EXPORT KCModuleProxy : public QWidget { Q_DECLARE_PRIVATE(KCModuleProxy) Q_OBJECT public: /** * Constructs a KCModuleProxy from a KCModuleInfo class. * * @param info The KCModuleInfo to construct the module from. * @param parent the parent QWidget. * @param args This is used in the implementation and is internal. * Use the default. */ explicit KCModuleProxy(const KCModuleInfo &info, QWidget *parent = nullptr, const QStringList &args = QStringList()); /** * Constructs a KCModuleProxy from a module's service name, which is * equivalent to the desktop file for the kcm without the ".desktop" part. * Otherwise equal to the one above. * * @param serviceName The module's service name to construct from. * @param parent the parent QWidget. * @param args This is used in the implementation and is internal. * Use the default. */ explicit KCModuleProxy(const QString &serviceName, QWidget *parent = nullptr, const QStringList &args = QStringList()); /** * Constructs a KCModuleProxy from KService. Otherwise equal to the one above. * * @param service The KService to construct from. * @param parent the parent QWidget. * @param args This is used in the implementation and is internal. * Use the default. */ explicit KCModuleProxy(const KService::Ptr &service, QWidget *parent = nullptr, const QStringList &args = QStringList()); /** * Default destructor */ ~KCModuleProxy() override; /** * Calling it will cause the contained module to * run its load() routine. */ void load(); /** * Calling it will cause the contained module to * run its save() routine. * * If the module was not modified, it will not be asked * to save. */ void save(); /** * @return the module's quickHelp(); */ QString quickHelp() const; /** * @return the module's aboutData() */ const KAboutData *aboutData() const; /** * @return what buttons the module * needs */ KCModule::Buttons buttons() const; /** * @return true if the module is modified * and needs to be saved. */ bool changed() const; + /** + * @return true if the module is matching default settings + * + * @since 5.65 + */ + bool defaulted() const; + /** * Access to the actual module. * It may return NULL if anything goes wrong. * * @return the encapsulated module. */ KCModule *realModule() const; /** * @return a KCModuleInfo for the encapsulated * module */ KCModuleInfo moduleInfo() const; /** * Returns the D-Bus Service name */ QString dbusService() const; /** * Returns the D-Bus Path */ QString dbusPath() const; /** * Returns the recommended minimum size for the widget */ QSize minimumSizeHint() const override; public Q_SLOTS: /** * Calling it will cause the contained module to * load its default values. */ void defaults(); /** * Calling this, results in deleting the contained * module, and unregistering from DCOP. A similar result is achieved * by deleting the KCModuleProxy itself. */ void deleteClient(); Q_SIGNALS: /* * This signal is emitted when the contained module is changed. */ void changed(bool state); /** * This is emitted in the same situations as in the one above. Practical * when several KCModuleProxys are loaded. */ void changed(KCModuleProxy *mod); /** * When a module running with root privileges and exits, returns to normal mode, the * childClosed() signal is emitted. */ void childClosed(); /* * This signal is relayed from the encapsulated module, and * is equivalent to the module's own quickHelpChanged() signal. */ void quickHelpChanged(); protected: /** * Reimplemented for internal purposes. Makes sure the encapsulated * module is loaded before the show event is taken care of. */ void showEvent(QShowEvent *) override; protected: KCModuleProxyPrivate *const d_ptr; private: Q_PRIVATE_SLOT(d_func(), void _k_moduleChanged(bool)) + Q_PRIVATE_SLOT(d_func(), void _k_moduleDefaulted(bool)) Q_PRIVATE_SLOT(d_func(), void _k_moduleDestroyed()) Q_PRIVATE_SLOT(d_func(), void _k_ownerChanged(const QString &service, const QString &oldOwner, const QString &newOwner)) }; #endif // KUTILS_KCMODULEPROXY_H diff --git a/src/kcmoduleproxy_p.h b/src/kcmoduleproxy_p.h index 690f75e..bc237ac 100644 --- a/src/kcmoduleproxy_p.h +++ b/src/kcmoduleproxy_p.h @@ -1,76 +1,82 @@ /* This file is part of the KDE project Copyright (C) 2007 Matthias Kretz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KCMUTILS_KCMODULEPROXY_P_H #define KCMUTILS_KCMODULEPROXY_P_H #include "kcmoduleinfo.h" #include "kcmoduleproxy.h" #include class QVBoxLayout; class KCModuleProxyPrivate { Q_DECLARE_PUBLIC(KCModuleProxy) protected: KCModuleProxyPrivate(KCModuleProxy *_parent, const KCModuleInfo &info, const QStringList &_args) : args(_args), kcm(nullptr), topLayout(nullptr), rootInfo(nullptr), modInfo(info), - changed(false), bogusOccupier(false), parent(_parent) + changed(false), defaulted(false), bogusOccupier(false), parent(_parent) { } ~KCModuleProxyPrivate() { delete rootInfo; // Delete before embedWidget! delete kcm; } void loadModule(); /** * Makes sure the proper variables is set and signals are emitted. */ void _k_moduleChanged(bool); + /** + * Makes sure the proper variables is set and signals are emitted. + */ + void _k_moduleDefaulted(bool); + /** * Zeroes d->kcm */ void _k_moduleDestroyed(); /** * Gets called by DCOP when an application closes. * Is used to (try to) reload a KCM which previously * was loaded. */ void _k_ownerChanged(const QString &service, const QString &oldOwner, const QString &newOwner); QStringList args; KCModule *kcm = nullptr; QVBoxLayout *topLayout = nullptr; /* Contains QScrollView view, and root stuff */ QLabel *rootInfo = nullptr; QString dbusService; QString dbusPath; KCModuleInfo modInfo; bool changed = false; + bool defaulted = false; bool bogusOccupier = false; KCModuleProxy *parent = nullptr; KCModuleProxy *q_ptr = nullptr; }; #endif // KCMUTILS_KCMODULEPROXY_P_H