diff --git a/CMakeLists.txt b/CMakeLists.txt index a843eb5..afdc4d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,93 +1,93 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.57.0") # handled by release scripts set(KF5_DEP_VERSION "5.56.0") # handled by release scripts project(KCMUtils VERSION ${KF5_VERSION}) include(FeatureSummary) find_package(ECM 5.56.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) set(REQUIRED_QT_VERSION 5.10.0) find_package(Qt5 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED Widgets DBus Qml Quick QuickWidgets) set(KCMUtils_AUTOMOC_MACRO_NAMES "KCMODULECONTAINER") if(NOT CMAKE_VERSION VERSION_LESS "3.10.0") # CMake 3.9+ warns about automoc on files without Q_OBJECT, and doesn't know about other macros. # 3.10+ lets us provide more macro names that require automoc. list(APPEND CMAKE_AUTOMOC_MACRO_NAMES ${KCMUtils_AUTOMOC_MACRO_NAMES}) endif() include(GenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(CMakePackageConfigHelpers) include(ECMAddQch) option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") ecm_setup_version(PROJECT VARIABLE_PREFIX KCMUTILS VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kcmutils_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5KCMUtilsConfigVersion.cmake" SOVERSION 5) find_package(KF5ItemViews ${KF5_DEP_VERSION} REQUIRED) find_package(KF5ConfigWidgets ${KF5_DEP_VERSION} REQUIRED) find_package(KF5CoreAddons ${KF5_DEP_VERSION} REQUIRED) find_package(KF5I18n ${KF5_DEP_VERSION} REQUIRED) find_package(KF5IconThemes ${KF5_DEP_VERSION} REQUIRED) find_package(KF5Service ${KF5_DEP_VERSION} REQUIRED) find_package(KF5XmlGui ${KF5_DEP_VERSION} REQUIRED) find_package(KF5Declarative ${KF5_DEP_VERSION} REQUIRED) add_definitions(-DTRANSLATION_DOMAIN=\"kcmutils5\") if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ki18n_install(po) endif() - +add_definitions(-DQT_NO_FOREACH) add_subdirectory(src) # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5KCMUtils") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5KCMUtils_QCH FILE KF5KCMUtilsQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5KCMUtilsQchTargets.cmake\")") endif() configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5KCMUtilsConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5KCMUtilsConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5KCMUtilsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5KCMUtilsConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5KCMUtilsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5KCMUtilsTargets.cmake NAMESPACE KF5:: ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kcmutils_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/kcmultidialog.cpp b/src/kcmultidialog.cpp index b689f27..7a476d1 100644 --- a/src/kcmultidialog.cpp +++ b/src/kcmultidialog.cpp @@ -1,598 +1,598 @@ /* Copyright (c) 2000 Matthias Elter Copyright (c) 2003 Daniel Molkentin Copyright (c) 2003,2006 Matthias Kretz Copyright (c) 2004 Frans Englich Copyright (c) 2006 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 "kcmultidialog.h" #include "kcmultidialog_p.h" #include "kcmoduleqml_p.h" #include "kcmoduleproxy.h" #include #include #include #include #include #include #include #include #include #include #include #ifndef KCONFIGWIDGETS_NO_KAUTH #include #include #endif #include #include #include #include #include bool KCMultiDialogPrivate::resolveChanges(KCModuleProxy *currentProxy) { Q_Q(KCMultiDialog); if (!currentProxy || !currentProxy->changed()) { return true; } // Let the user decide const int queryUser = KMessageBox::warningYesNoCancel( q, i18n("The settings of the current module have changed.\n" "Do you want to apply the changes or discard them?"), i18n("Apply Settings"), KStandardGuiItem::apply(), KStandardGuiItem::discard(), KStandardGuiItem::cancel()); switch (queryUser) { case KMessageBox::Yes: return moduleSave(currentProxy); case KMessageBox::No: currentProxy->load(); return true; case KMessageBox::Cancel: return false; default: Q_ASSERT(false); return false; } } void KCMultiDialogPrivate::_k_slotCurrentPageChanged(KPageWidgetItem *current, KPageWidgetItem *previous) { Q_Q(KCMultiDialog); KCModuleProxy *currentModule = nullptr; KCModuleProxy *previousModule = nullptr; for (int i = 0; i < modules.count(); ++i) { if (modules[i].item == previous) { previousModule = modules[i].kcm; } if (modules[i].item == current) { currentModule = modules[i].kcm; } } // For some reason the KCModuleQml modules handle their own margin internally // to match that we need to adjust the spacing of our page widget // by removing the spacing between the left pane and the edge, and the layout on the right // when we reduce the layout on the right we need to pad the buttons back to match // TODO KF6 Fix this situation. if (currentModule && currentModule->realModule() && currentModule->realModule()->inherits("KCModuleQml")) { bool padHackLeft = false; bool padHackRight = false; if (q->pageWidget()->model()->rowCount() < 2) { padHackLeft = true; padHackRight = true; } else if (qApp->isRightToLeft()) { padHackLeft = true; } else { padHackRight = true; } q->layout()->setContentsMargins(padHackLeft ? 0: q->style()->pixelMetric(QStyle::PM_LayoutLeftMargin), q->style()->pixelMetric(QStyle::PM_LayoutTopMargin), padHackRight ? 0 : q->style()->pixelMetric(QStyle::PM_LayoutRightMargin), q->style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); q->pageWidget()->layout()->setSpacing(0); q->buttonBox()->setContentsMargins(padHackLeft ? q->style()->pixelMetric(QStyle::PM_LayoutLeftMargin) : 0, 0, padHackRight ? q->style()->pixelMetric(QStyle::PM_LayoutRightMargin) : 0, 0); } else { q->buttonBox()->setContentsMargins(0, 0, 0, 0); q->pageWidget()->layout()->setSpacing(q->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing)); q->layout()->setContentsMargins( q->style()->pixelMetric(QStyle::PM_LayoutLeftMargin), q->style()->pixelMetric(QStyle::PM_LayoutTopMargin), q->style()->pixelMetric(QStyle::PM_LayoutRightMargin), q->style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); } q->blockSignals(true); q->setCurrentPage(previous); if (resolveChanges(previousModule)) { q->setCurrentPage(current); } q->blockSignals(false); // We need to get the state of the now active module _k_clientChanged(); } void KCMultiDialogPrivate::_k_clientChanged() { Q_Q(KCMultiDialog); // qDebug(); // Get the current module KCModuleProxy *activeModule = nullptr; for (int i = 0; i < modules.count(); ++i) { if (modules[ i ].item == q->currentPage()) { activeModule = modules[ i ].kcm; break; } } bool change = false; if (activeModule) { change = activeModule->changed(); QPushButton *applyButton = q->buttonBox()->button(QDialogButtonBox::Apply); if (applyButton) { q->disconnect(applyButton, &QAbstractButton::clicked, q, &KCMultiDialog::slotApplyClicked); #ifndef KCONFIGWIDGETS_NO_KAUTH delete applyButton->findChild(); #endif applyButton->setEnabled(change); } QPushButton *okButton = q->buttonBox()->button(QDialogButtonBox::Ok); if (okButton) { q->disconnect(okButton, &QAbstractButton::clicked, q, &KCMultiDialog::slotOkClicked); #ifndef KCONFIGWIDGETS_NO_KAUTH delete okButton->findChild(); #endif } #ifndef KCONFIGWIDGETS_NO_KAUTH if (activeModule->realModule()->needsAuthorization()) { if (applyButton) { KAuth::ObjectDecorator *decorator = new KAuth::ObjectDecorator(applyButton); decorator->setAuthAction(activeModule->realModule()->authAction()); activeModule->realModule()->authAction().setParentWidget(activeModule->realModule()); q->connect(decorator, &KAuth::ObjectDecorator::authorized, q, &KCMultiDialog::slotApplyClicked); } if (okButton) { KAuth::ObjectDecorator *decorator = new KAuth::ObjectDecorator(okButton); decorator->setAuthAction(activeModule->realModule()->authAction()); activeModule->realModule()->authAction().setParentWidget(activeModule->realModule()); q->connect(decorator, &KAuth::ObjectDecorator::authorized, q, &KCMultiDialog::slotOkClicked); } } else { if (applyButton) { q->connect(applyButton, &QAbstractButton::clicked, q, &KCMultiDialog::slotApplyClicked); delete applyButton->findChild(); } if (okButton) { q->connect(okButton, &QAbstractButton::clicked, q, &KCMultiDialog::slotOkClicked); delete okButton->findChild(); } } #endif } QPushButton *resetButton = q->buttonBox()->button(QDialogButtonBox::Reset); if (resetButton) { resetButton->setEnabled(change); } QPushButton *applyButton = q->buttonBox()->button(QDialogButtonBox::Apply); if (applyButton) { applyButton->setEnabled(change); } if (activeModule) { QPushButton *helpButton = q->buttonBox()->button(QDialogButtonBox::Help); if (helpButton) { helpButton->setEnabled(activeModule->buttons() & KCModule::Help); } QPushButton *defaultButton = q->buttonBox()->button(QDialogButtonBox::RestoreDefaults); if (defaultButton) { defaultButton->setEnabled(activeModule->buttons() & KCModule::Default); } } } void KCMultiDialogPrivate::_k_updateHeader(bool use, const QString &message) { Q_Q(KCMultiDialog); KPageWidgetItem *item = q->currentPage(); KCModuleProxy *kcm = qobject_cast(item->widget()); if (use) { item->setHeader(QStringLiteral("") + kcm->moduleInfo().moduleName() + QStringLiteral("
") + message + QStringLiteral("")); item->setIcon(KDE::icon(kcm->moduleInfo().icon(), QStringList() << QStringLiteral("dialog-warning"))); } else { item->setHeader(kcm->moduleInfo().moduleName()); item->setIcon(QIcon::fromTheme(kcm->moduleInfo().icon())); } } void KCMultiDialogPrivate::init() { Q_Q(KCMultiDialog); q->setFaceType(KPageDialog::Auto); q->setWindowTitle(i18n("Configure")); q->setModal(false); QDialogButtonBox *buttonBox = new QDialogButtonBox(q); buttonBox->setStandardButtons(QDialogButtonBox::Help | QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Cancel | QDialogButtonBox::Apply | QDialogButtonBox::Ok | QDialogButtonBox::Reset); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::RestoreDefaults), KStandardGuiItem::defaults()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Apply), KStandardGuiItem::apply()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Reset), KStandardGuiItem::reset()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Help), KStandardGuiItem::help()); buttonBox->button(QDialogButtonBox::Reset)->setEnabled(false); buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); q->connect(buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, q, &KCMultiDialog::slotApplyClicked); q->connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, q, &KCMultiDialog::slotOkClicked); q->connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, q, &KCMultiDialog::slotDefaultClicked); q->connect(buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, q, &KCMultiDialog::slotHelpClicked); q->connect(buttonBox->button(QDialogButtonBox::Reset), &QAbstractButton::clicked, q, &KCMultiDialog::slotUser1Clicked); q->setButtonBox(buttonBox); q->connect(q, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), SLOT(_k_slotCurrentPageChanged(KPageWidgetItem*,KPageWidgetItem*))); } KCMultiDialog::KCMultiDialog(QWidget *parent) : KPageDialog(parent) , d_ptr(new KCMultiDialogPrivate(this)) { d_func()->init(); } KCMultiDialog::KCMultiDialog(KPageWidget *pageWidget, QWidget *parent, Qt::WindowFlags flags) : KPageDialog(pageWidget, parent, flags) , d_ptr(new KCMultiDialogPrivate(this)) { d_func()->init(); } KCMultiDialog::KCMultiDialog(KCMultiDialogPrivate &dd, KPageWidget *pageWidget, QWidget *parent, Qt::WindowFlags flags) : KPageDialog(pageWidget, parent, flags) , d_ptr(&dd) { d_func()->init(); } KCMultiDialog::~KCMultiDialog() { delete d_ptr; } void KCMultiDialog::showEvent(QShowEvent *ev) { KPageDialog::showEvent(ev); adjustSize(); /** * adjustSize() relies on sizeHint but is limited to 2/3 of the desktop size * Workaround for https://bugreports.qt.io/browse/QTBUG-3459 * * We adjust the size after passing the show event * because otherwise window pos is set to (0,0) */ const QSize maxSize = QApplication::desktop()->availableGeometry(pos()).size(); resize(qMin(sizeHint().width(), maxSize.width()), qMin(sizeHint().height(), maxSize.height())); } void KCMultiDialog::slotDefaultClicked() { Q_D(KCMultiDialog); const KPageWidgetItem *item = currentPage(); if (!item) { return; } for (int i = 0; i < d->modules.count(); ++i) { if (d->modules[ i ].item == item) { d->modules[ i ].kcm->defaults(); d->_k_clientChanged(); return; } } } void KCMultiDialog::slotUser1Clicked() { const KPageWidgetItem *item = currentPage(); if (!item) { return; } Q_D(KCMultiDialog); for (int i = 0; i < d->modules.count(); ++i) { if (d->modules[ i ].item == item) { d->modules[ i ].kcm->load(); d->_k_clientChanged(); return; } } } bool KCMultiDialogPrivate::moduleSave(KCModuleProxy *module) { if (!module) { return false; } module->save(); return true; } void KCMultiDialogPrivate::apply() { Q_Q(KCMultiDialog); QStringList updatedComponents; - foreach (const CreatedModule &module, modules) { + for (const CreatedModule &module : qAsConst(modules)) { KCModuleProxy *proxy = module.kcm; if (proxy->changed()) { proxy->save(); /** * Add name of the components the kcm belongs to the list * of updated components. */ const QStringList componentNames = module.componentNames; - foreach (const QString &componentName, module.componentNames) { + for (const QString &componentName : componentNames) { if (!updatedComponents.contains(componentName)) { updatedComponents.append(componentName); } } } } // Send the configCommitted signal for every updated component. - foreach (const QString &name, updatedComponents) { + for (const QString &name : qAsConst(updatedComponents)) { emit q->configCommitted(name.toLatin1()); } emit q->configCommitted(); } void KCMultiDialog::slotApplyClicked() { QPushButton *applyButton = buttonBox()->button(QDialogButtonBox::Apply); applyButton->setFocus(); d_func()->apply(); } void KCMultiDialog::slotOkClicked() { QPushButton *okButton = buttonBox()->button(QDialogButtonBox::Ok); okButton->setFocus(); d_func()->apply(); accept(); } void KCMultiDialog::slotHelpClicked() { const KPageWidgetItem *item = currentPage(); if (!item) { return; } Q_D(KCMultiDialog); QString docPath; for (int i = 0; i < d->modules.count(); ++i) { if (d->modules[ i ].item == item) { docPath = d->modules[ i ].kcm->moduleInfo().docPath(); break; } } const QUrl docUrl = QUrl(QStringLiteral("help:/")).resolved(QUrl(docPath)); // same code as in KHelpClient::invokeHelp const QString docUrlScheme = docUrl.scheme(); if (docUrlScheme == QLatin1String("help") || docUrlScheme == QLatin1String("man") || docUrlScheme == QLatin1String("info")) { QProcess::startDetached(QStringLiteral("khelpcenter"), QStringList() << docUrl.toString()); } else { QDesktopServices::openUrl(docUrl); } } void KCMultiDialog::closeEvent(QCloseEvent *event) { Q_D(KCMultiDialog); KPageDialog::closeEvent(event); /** * If we don't delete them, the DBUS registration stays, and trying to load the KCMs * in other situations will lead to "module already loaded in Foo," while to the user * doesn't appear so(the dialog is hidden) */ - Q_FOREACH(auto &proxy, d->modules) { + for(auto &proxy : qAsConst(d->modules)) { proxy.kcm->deleteClient(); } } KPageWidgetItem *KCMultiDialog::addModule(const QString &path, const QStringList &args) { QString complete = path; if (!path.endsWith(QLatin1String(".desktop"))) { complete += QStringLiteral(".desktop"); } KService::Ptr service = KService::serviceByStorageId(complete); return addModule(KCModuleInfo(service), nullptr, args); } KPageWidgetItem *KCMultiDialog::addModule(const KCModuleInfo &moduleInfo, KPageWidgetItem *parentItem, const QStringList &args) { Q_D(KCMultiDialog); if (!moduleInfo.service()) { return nullptr; } //KAuthorized::authorizeControlModule( moduleInfo.service()->menuId() ) is //checked in noDisplay already if (moduleInfo.service()->noDisplay()) { return nullptr; } // Create the scroller auto *moduleScroll = new UnboundScrollArea(this); // Prepare the scroll area moduleScroll->setWidgetResizable(true); moduleScroll->setFrameStyle(QFrame::NoFrame); moduleScroll->viewport()->setAutoFillBackground(false); KCModuleProxy *kcm = new KCModuleProxy(moduleInfo, moduleScroll, args); moduleScroll->setWidget(kcm); // qDebug() << moduleInfo.moduleName(); KPageWidgetItem *item = new KPageWidgetItem(moduleScroll, moduleInfo.moduleName()); KCMultiDialogPrivate::CreatedModule cm; cm.kcm = kcm; cm.item = item; cm.componentNames = moduleInfo.service()->property(QStringLiteral("X-KDE-ParentComponents")).toStringList(); d->modules.append(cm); if (qobject_cast(kcm->realModule())) { item->setHeaderVisible(false); } if (kcm->realModule() && kcm->realModule()->useRootOnlyMessage()) { item->setHeader(QStringLiteral("") + moduleInfo.moduleName() + QStringLiteral("
") + kcm->realModule()->rootOnlyMessage() + QStringLiteral("")); item->setIcon(KDE::icon(moduleInfo.icon(), QStringList() << QStringLiteral("dialog-warning"))); } else { item->setHeader(moduleInfo.moduleName()); item->setIcon(QIcon::fromTheme(moduleInfo.icon())); } item->setProperty("_k_weight", moduleInfo.weight()); bool updateCurrentPage = false; const KPageWidgetModel *model = qobject_cast(pageWidget()->model()); Q_ASSERT(model); if (parentItem) { const QModelIndex parentIndex = model->index(parentItem); const int siblingCount = model->rowCount(parentIndex); int row = 0; for (; row < siblingCount; ++row) { KPageWidgetItem *siblingItem = model->item(parentIndex.child(row, 0)); if (siblingItem->property("_k_weight").toInt() > moduleInfo.weight()) { // the item we found is heavier than the new module // qDebug() << "adding KCM " << item->name() << " before " << siblingItem->name(); insertPage(siblingItem, item); break; } } if (row >= siblingCount) { // the new module is either the first or the heaviest item // qDebug() << "adding KCM " << item->name() << " with parent " << parentItem->name(); addSubPage(parentItem, item); } } else { const int siblingCount = model->rowCount(); int row = 0; for (; row < siblingCount; ++row) { KPageWidgetItem *siblingItem = model->item(model->index(row, 0)); if (siblingItem->property("_k_weight").toInt() > moduleInfo.weight()) { // the item we found is heavier than the new module // qDebug() << "adding KCM " << item->name() << " before " << siblingItem->name(); insertPage(siblingItem, item); if (siblingItem == currentPage()) { updateCurrentPage = true; } break; } } if (row == siblingCount) { // the new module is either the first or the heaviest item // qDebug() << "adding KCM " << item->name() << " at the top level"; addPage(item); } } connect(kcm, SIGNAL(changed(bool)), this, SLOT(_k_clientChanged())); connect(kcm->realModule(), SIGNAL(rootOnlyMessageChanged(bool,QString)), this, SLOT(_k_updateHeader(bool,QString))); if (d->modules.count() == 1 || updateCurrentPage) { setCurrentPage(item); d->_k_clientChanged(); } return item; } void KCMultiDialog::clear() { Q_D(KCMultiDialog); // qDebug() ; for (int i = 0; i < d->modules.count(); ++i) { removePage(d->modules[ i ].item); delete d->modules[ i ].kcm; } d->modules.clear(); d->_k_clientChanged(); } #include "moc_kcmultidialog.cpp" diff --git a/src/kpluginselector.cpp b/src/kpluginselector.cpp index e771656..27e0ba4 100644 --- a/src/kpluginselector.cpp +++ b/src/kpluginselector.cpp @@ -1,930 +1,932 @@ /** * This file is part of the KDE project * Copyright (C) 2007, 2006 Rafael Fernández López * Copyright (C) 2002-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 "kpluginselector.h" #include "kpluginselector_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MARGIN 5 KPluginSelector::Private::Private(KPluginSelector *parent) : QObject(parent) , parent(parent) , listView(nullptr) , categoryDrawer(nullptr) , showIcons(false) { } KPluginSelector::Private::~Private() { } void KPluginSelector::Private::updateDependencies(PluginEntry *pluginEntry, bool added) { if (added) { QStringList dependencyList = pluginEntry->pluginInfo.dependencies(); if (dependencyList.isEmpty()) { return; } for (int i = 0; i < pluginModel->rowCount(); i++) { const QModelIndex index = pluginModel->index(i, 0); PluginEntry *pe = static_cast(index.internalPointer()); if ((pe->pluginInfo.pluginName() != pluginEntry->pluginInfo.pluginName()) && dependencyList.contains(pe->pluginInfo.pluginName()) && !pe->checked) { dependenciesWidget->addDependency(pe->pluginInfo.name(), pluginEntry->pluginInfo.name(), added); const_cast(index.model())->setData(index, added, Qt::CheckStateRole); updateDependencies(pe, added); } } } else { for (int i = 0; i < pluginModel->rowCount(); i++) { const QModelIndex index = pluginModel->index(i, 0); PluginEntry *pe = static_cast(index.internalPointer()); if ((pe->pluginInfo.pluginName() != pluginEntry->pluginInfo.pluginName()) && pe->pluginInfo.dependencies().contains(pluginEntry->pluginInfo.pluginName()) && pe->checked) { dependenciesWidget->addDependency(pe->pluginInfo.name(), pluginEntry->pluginInfo.name(), added); const_cast(index.model())->setData(index, added, Qt::CheckStateRole); updateDependencies(pe, added); } } } } int KPluginSelector::Private::dependantLayoutValue(int value, int width, int totalWidth) const { if (listView->layoutDirection() == Qt::LeftToRight) { return value; } return totalWidth - width - value; } KPluginSelector::Private::DependenciesWidget::DependenciesWidget(QWidget *parent) : QWidget(parent) , addedByDependencies(0) , removedByDependencies(0) { setVisible(false); details = new QLabel(); QHBoxLayout *layout = new QHBoxLayout(this); QVBoxLayout *dataLayout = new QVBoxLayout; dataLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); layout->setAlignment(Qt::AlignLeft); QLabel *label = new QLabel(); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); label->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-information")).pixmap(style()->pixelMetric(QStyle::PM_MessageBoxIconSize))); label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); layout->addWidget(label); KUrlLabel *link = new KUrlLabel(); link->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); link->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); link->setGlowEnabled(false); link->setUnderline(false); link->setFloatEnabled(true); link->setUseCursor(true); link->setHighlightedColor(palette().color(QPalette::Link)); link->setSelectedColor(palette().color(QPalette::Link)); link->setText(i18n("Automatic changes have been performed due to plugin dependencies. Click here for further information")); dataLayout->addWidget(link); dataLayout->addWidget(details); layout->addLayout(dataLayout); QObject::connect(link, SIGNAL(leftClickedUrl()), this, SLOT(showDependencyDetails())); } KPluginSelector::Private::DependenciesWidget::~DependenciesWidget() { } void KPluginSelector::Private::DependenciesWidget::addDependency(const QString &dependency, const QString &pluginCausant, bool added) { if (!isVisible()) { setVisible(true); } struct FurtherInfo furtherInfo; furtherInfo.added = added; furtherInfo.pluginCausant = pluginCausant; if (dependencyMap.contains(dependency)) { // The dependency moved from added to removed or vice-versa if (added && removedByDependencies) { removedByDependencies--; } else if (addedByDependencies) { addedByDependencies--; } dependencyMap[dependency] = furtherInfo; } else { dependencyMap.insert(dependency, furtherInfo); } if (added) { addedByDependencies++; } else { removedByDependencies++; } updateDetails(); } void KPluginSelector::Private::DependenciesWidget::userOverrideDependency(const QString &dependency) { if (dependencyMap.contains(dependency)) { if (addedByDependencies && dependencyMap[dependency].added) { addedByDependencies--; } else if (removedByDependencies) { removedByDependencies--; } dependencyMap.remove(dependency); } updateDetails(); } void KPluginSelector::Private::DependenciesWidget::clearDependencies() { addedByDependencies = 0; removedByDependencies = 0; dependencyMap.clear(); updateDetails(); } void KPluginSelector::Private::DependenciesWidget::showDependencyDetails() { QString message = i18n("Automatic changes have been performed in order to satisfy plugin dependencies:\n"); - foreach (const QString &dependency, dependencyMap.keys()) { + const auto lstKeys = dependencyMap.keys(); + for (const QString &dependency : lstKeys) { if (dependencyMap[dependency].added) { message += i18n("\n %1 plugin has been automatically checked because of the dependency of %2 plugin", dependency, dependencyMap[dependency].pluginCausant); } else { message += i18n("\n %1 plugin has been automatically unchecked because of its dependency on %2 plugin", dependency, dependencyMap[dependency].pluginCausant); } } KMessageBox::information(this, message, i18n("Dependency Check")); addedByDependencies = 0; removedByDependencies = 0; updateDetails(); } void KPluginSelector::Private::DependenciesWidget::updateDetails() { if (dependencyMap.isEmpty()) { setVisible(false); return; } QString message; if (addedByDependencies) { message += i18np("%1 plugin automatically added due to plugin dependencies", "%1 plugins automatically added due to plugin dependencies", addedByDependencies); } if (removedByDependencies && !message.isEmpty()) { message += i18n(", "); } if (removedByDependencies) { message += i18np("%1 plugin automatically removed due to plugin dependencies", "%1 plugins automatically removed due to plugin dependencies", removedByDependencies); } if (message.isEmpty()) { details->setVisible(false); } else { details->setVisible(true); details->setText(message); } } KPluginSelector::KPluginSelector(QWidget *parent) : QWidget(parent) , d(new Private(this)) { QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); d->lineEdit = new QLineEdit(this); d->lineEdit->setClearButtonEnabled(true); d->lineEdit->setPlaceholderText(i18n("Search...")); d->listView = new KCategorizedView(this); d->categoryDrawer = new KCategoryDrawer(d->listView); d->listView->setVerticalScrollMode(QListView::ScrollPerPixel); d->listView->setAlternatingRowColors(true); d->listView->setCategoryDrawer(d->categoryDrawer); d->dependenciesWidget = new Private::DependenciesWidget(this); d->pluginModel = new Private::PluginModel(d, this); d->proxyModel = new Private::ProxyModel(d, this); d->proxyModel->setCategorizedModel(true); d->proxyModel->setSourceModel(d->pluginModel); d->listView->setModel(d->proxyModel); d->listView->setAlternatingRowColors(true); Private::PluginDelegate *pluginDelegate = new Private::PluginDelegate(d, this); d->listView->setItemDelegate(pluginDelegate); d->listView->setMouseTracking(true); d->listView->viewport()->setAttribute(Qt::WA_Hover); connect(d->lineEdit, &QLineEdit::textChanged, d->proxyModel, &QSortFilterProxyModel::invalidate); connect(pluginDelegate, &Private::PluginDelegate::changed, this, &KPluginSelector::changed); connect(pluginDelegate, &Private::PluginDelegate::configCommitted, this, &KPluginSelector::configCommitted); layout->addWidget(d->lineEdit); layout->addWidget(d->listView); layout->addWidget(d->dependenciesWidget); } KPluginSelector::~KPluginSelector() { delete d->listView->itemDelegate(); delete d->listView; // depends on some other things in d, make sure this dies first. delete d; } void KPluginSelector::addPlugins(const QString &componentName, const QString &categoryName, const QString &categoryKey, KSharedConfig::Ptr config) { QStringList desktopFileNames; const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, componentName + QStringLiteral("/kpartplugins"), QStandardPaths::LocateDirectory); for (const QString &dir : dirs) { QDirIterator it(dir, QStringList() << QStringLiteral("*.desktop"), QDir::NoFilter, QDirIterator::Subdirectories); while (it.hasNext()) { desktopFileNames.append(it.next()); } } QList pluginInfoList = KPluginInfo::fromFiles(desktopFileNames); if (pluginInfoList.isEmpty()) { return; } if (!config) { config = KSharedConfig::openConfig(componentName + QStringLiteral("rc")); } Q_ASSERT(config); KConfigGroup cfgGroup(config, "KParts Plugins"); // qDebug() << "cfgGroup = " << &cfgGroup; d->pluginModel->addPlugins(pluginInfoList, categoryName, categoryKey, cfgGroup); d->proxyModel->sort(0); } void KPluginSelector::addPlugins(const QList &pluginInfoList, PluginLoadMethod pluginLoadMethod, const QString &categoryName, const QString &categoryKey, const KSharedConfig::Ptr &config) { if (pluginInfoList.isEmpty()) { return; } KConfigGroup cfgGroup(config ? config : KSharedConfig::openConfig(), "Plugins"); // qDebug() << "cfgGroup = " << &cfgGroup; d->pluginModel->addPlugins(pluginInfoList, categoryName, categoryKey, cfgGroup, pluginLoadMethod, true /* manually added */); d->proxyModel->sort(0); } void KPluginSelector::load() { for (int i = 0; i < d->pluginModel->rowCount(); i++) { const QModelIndex index = d->pluginModel->index(i, 0); PluginEntry *pluginEntry = static_cast(index.internalPointer()); pluginEntry->pluginInfo.load(pluginEntry->cfgGroup); d->pluginModel->setData(index, pluginEntry->pluginInfo.isPluginEnabled(), Qt::CheckStateRole); } emit changed(false); } void KPluginSelector::save() { for (int i = 0; i < d->pluginModel->rowCount(); i++) { const QModelIndex index = d->pluginModel->index(i, 0); PluginEntry *pluginEntry = static_cast(index.internalPointer()); pluginEntry->pluginInfo.setPluginEnabled(pluginEntry->checked); pluginEntry->pluginInfo.save(pluginEntry->cfgGroup); pluginEntry->cfgGroup.sync(); } emit changed(false); } void KPluginSelector::defaults() { for (int i = 0; i < d->pluginModel->rowCount(); i++) { const QModelIndex index = d->pluginModel->index(i, 0); PluginEntry *pluginEntry = static_cast(index.internalPointer()); d->pluginModel->setData(index, pluginEntry->pluginInfo.isPluginEnabledByDefault(), Qt::CheckStateRole); } emit changed(true); } bool KPluginSelector::isDefault() const { for (int i = 0; i < d->pluginModel->rowCount(); i++) { const QModelIndex index = d->pluginModel->index(i, 0); PluginEntry *pluginEntry = static_cast(index.internalPointer()); if (d->pluginModel->data(index, Qt::CheckStateRole).toBool() != pluginEntry->pluginInfo.isPluginEnabledByDefault()) { return false; } } return true; } void KPluginSelector::updatePluginsState() { for (int i = 0; i < d->pluginModel->rowCount(); i++) { const QModelIndex index = d->pluginModel->index(i, 0); PluginEntry *pluginEntry = static_cast(index.internalPointer()); if (pluginEntry->manuallyAdded) { pluginEntry->pluginInfo.setPluginEnabled(pluginEntry->checked); } } } void KPluginSelector::setConfigurationArguments(const QStringList& arguments) { d->kcmArguments = arguments; } QStringList KPluginSelector::configurationArguments() const { return d->kcmArguments; } void KPluginSelector::showConfiguration(const QString& componentName) { QModelIndex idx; for (int i = 0, c = d->proxyModel->rowCount(); iproxyModel->index(i, 0); const auto entry = currentIndex.data(KPluginSelector::Private::PluginEntryRole).value(); if (entry->pluginInfo.pluginName() == componentName) { idx = currentIndex; break; } } if (idx.isValid()) { auto delegate = static_cast(d->listView->itemDelegate()); delegate->configure(idx); } else { qWarning() << "Could not find plugin" << componentName; } } KPluginSelector::Private::PluginModel::PluginModel(KPluginSelector::Private *pluginSelector_d, QObject *parent) : QAbstractListModel(parent) , pluginSelector_d(pluginSelector_d) { } KPluginSelector::Private::PluginModel::~PluginModel() { } void KPluginSelector::Private::PluginModel::addPlugins(const QList &pluginList, const QString &categoryName, const QString &categoryKey, const KConfigGroup &cfgGroup, PluginLoadMethod pluginLoadMethod, bool manuallyAdded) { QList listToAdd; - foreach (const KPluginInfo &pluginInfo, pluginList) { + for (const KPluginInfo &pluginInfo : pluginList) { PluginEntry pluginEntry; pluginEntry.category = categoryName; pluginEntry.pluginInfo = pluginInfo; if (pluginLoadMethod == ReadConfigFile) { pluginEntry.pluginInfo.load(cfgGroup); } pluginEntry.checked = pluginInfo.isPluginEnabled(); pluginEntry.manuallyAdded = manuallyAdded; if (cfgGroup.isValid()) { pluginEntry.cfgGroup = cfgGroup; } else { pluginEntry.cfgGroup = pluginInfo.config(); } // this is where kiosk will set if a plugin is checkable or not (pluginName + "Enabled") pluginEntry.isCheckable = !pluginInfo.isValid() || !pluginEntry.cfgGroup.isEntryImmutable(pluginInfo.pluginName() + QLatin1String("Enabled")); if (!pluginEntryList.contains(pluginEntry) && !listToAdd.contains(pluginEntry) && (categoryKey.isEmpty() || !pluginInfo.category().compare(categoryKey, Qt::CaseInsensitive)) && (!pluginInfo.service() || !pluginInfo.service()->noDisplay())) { listToAdd << pluginEntry; if (!pluginSelector_d->showIcons && !pluginInfo.icon().isEmpty()) { pluginSelector_d->showIcons = true; } } } if (!listToAdd.isEmpty()) { beginInsertRows(QModelIndex(), pluginEntryList.count(), pluginEntryList.count() + listToAdd.count() - 1); pluginEntryList << listToAdd; endInsertRows(); } } QList KPluginSelector::Private::PluginModel::pluginServices(const QModelIndex &index) const { return static_cast(index.internalPointer())->pluginInfo.kcmServices(); } QModelIndex KPluginSelector::Private::PluginModel::index(int row, int column, const QModelIndex &parent) const { Q_UNUSED(parent) return createIndex(row, column, (row < pluginEntryList.count()) ? (void *) &pluginEntryList.at(row) : nullptr); } QVariant KPluginSelector::Private::PluginModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !index.internalPointer()) { return QVariant(); } PluginEntry *pluginEntry = static_cast(index.internalPointer()); switch (role) { case Qt::DisplayRole: return pluginEntry->pluginInfo.name(); case PluginEntryRole: return QVariant::fromValue(pluginEntry); case ServicesCountRole: return pluginEntry->pluginInfo.kcmServices().count(); case NameRole: return pluginEntry->pluginInfo.name(); case CommentRole: return pluginEntry->pluginInfo.comment(); case AuthorRole: return pluginEntry->pluginInfo.author(); case EmailRole: return pluginEntry->pluginInfo.email(); case WebsiteRole: return pluginEntry->pluginInfo.website(); case VersionRole: return pluginEntry->pluginInfo.version(); case LicenseRole: return pluginEntry->pluginInfo.license(); case DependenciesRole: return pluginEntry->pluginInfo.dependencies(); case IsCheckableRole: return pluginEntry->isCheckable; case Qt::DecorationRole: return pluginEntry->pluginInfo.icon(); case Qt::CheckStateRole: return pluginEntry->checked; case KCategorizedSortFilterProxyModel::CategoryDisplayRole: // fall through case KCategorizedSortFilterProxyModel::CategorySortRole: return pluginEntry->category; default: return QVariant(); } } bool KPluginSelector::Private::PluginModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) { return false; } bool ret = false; if (role == Qt::CheckStateRole) { static_cast(index.internalPointer())->checked = value.toBool(); ret = true; } if (ret) { emit dataChanged(index, index); } return ret; } int KPluginSelector::Private::PluginModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return pluginEntryList.count(); } KPluginSelector::Private::ProxyModel::ProxyModel(KPluginSelector::Private *pluginSelector_d, QObject *parent) : KCategorizedSortFilterProxyModel(parent) , pluginSelector_d(pluginSelector_d) { sort(0); } KPluginSelector::Private::ProxyModel::~ProxyModel() { } bool KPluginSelector::Private::ProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { Q_UNUSED(sourceParent) if (!pluginSelector_d->lineEdit->text().isEmpty()) { const QModelIndex index = sourceModel()->index(sourceRow, 0); const KPluginInfo pluginInfo = static_cast(index.internalPointer())->pluginInfo; return pluginInfo.name().contains(pluginSelector_d->lineEdit->text(), Qt::CaseInsensitive) || pluginInfo.comment().contains(pluginSelector_d->lineEdit->text(), Qt::CaseInsensitive); } return true; } bool KPluginSelector::Private::ProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const { return static_cast(left.internalPointer())->pluginInfo.name().compare(static_cast(right.internalPointer())->pluginInfo.name(), Qt::CaseInsensitive) < 0; } KPluginSelector::Private::PluginDelegate::PluginDelegate(KPluginSelector::Private *pluginSelector_d, QObject *parent) : KWidgetItemDelegate(pluginSelector_d->listView, parent) , checkBox(new QCheckBox) , pushButton(new QPushButton) , pluginSelector_d(pluginSelector_d) { pushButton->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); // only for getting size matters } KPluginSelector::Private::PluginDelegate::~PluginDelegate() { delete checkBox; delete pushButton; } void KPluginSelector::Private::PluginDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (!index.isValid()) { return; } int xOffset = checkBox->sizeHint().width(); bool disabled = !index.model()->data(index, IsCheckableRole).toBool(); painter->save(); QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, nullptr); int iconSize = option.rect.height() - MARGIN * 2; if (pluginSelector_d->showIcons) { QIcon icon = QIcon::fromTheme(index.model()->data(index, Qt::DecorationRole).toString()); icon.paint(painter, QRect(pluginSelector_d->dependantLayoutValue(MARGIN + option.rect.left() + xOffset, iconSize, option.rect.width()), MARGIN + option.rect.top(), iconSize, iconSize)); } else { iconSize = -MARGIN; } QRect contentsRect(pluginSelector_d->dependantLayoutValue(MARGIN * 2 + iconSize + option.rect.left() + xOffset, option.rect.width() - MARGIN * 3 - iconSize - xOffset, option.rect.width()), MARGIN + option.rect.top(), option.rect.width() - MARGIN * 3 - iconSize - xOffset, option.rect.height() - MARGIN * 2); int lessHorizontalSpace = MARGIN * 2 + pushButton->sizeHint().width(); if (index.model()->data(index, ServicesCountRole).toBool()) { lessHorizontalSpace += MARGIN + pushButton->sizeHint().width(); } contentsRect.setWidth(contentsRect.width() - lessHorizontalSpace); if (option.state & QStyle::State_Selected) { painter->setPen(option.palette.highlightedText().color()); } if (pluginSelector_d->listView->layoutDirection() == Qt::RightToLeft) { contentsRect.translate(lessHorizontalSpace, 0); } painter->save(); if (disabled) { QPalette pal(option.palette); pal.setCurrentColorGroup(QPalette::Disabled); painter->setPen(pal.text().color()); } painter->save(); QFont font = titleFont(option.font); QFontMetrics fmTitle(font); painter->setFont(font); painter->drawText(contentsRect, Qt::AlignLeft | Qt::AlignTop, fmTitle.elidedText(index.model()->data(index, Qt::DisplayRole).toString(), Qt::ElideRight, contentsRect.width())); painter->restore(); painter->drawText(contentsRect, Qt::AlignLeft | Qt::AlignBottom, option.fontMetrics.elidedText(index.model()->data(index, CommentRole).toString(), Qt::ElideRight, contentsRect.width())); painter->restore(); painter->restore(); } QSize KPluginSelector::Private::PluginDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { int i = 5; int j = 1; if (index.model()->data(index, ServicesCountRole).toBool()) { i = 6; j = 2; } if (!pluginSelector_d->showIcons) { i--; } QFont font = titleFont(option.font); QFontMetrics fmTitle(font); return QSize(qMax(fmTitle.width(index.model()->data(index, Qt::DisplayRole).toString()), option.fontMetrics.width(index.model()->data(index, CommentRole).toString())) + (pluginSelector_d->showIcons ? KIconLoader::SizeMedium : 0) + MARGIN * i + pushButton->sizeHint().width() * j, qMax(KIconLoader::SizeMedium + MARGIN * 2, fmTitle.height() + option.fontMetrics.height() + MARGIN * 2)); } QList KPluginSelector::Private::PluginDelegate::createItemWidgets(const QModelIndex &index) const { Q_UNUSED(index); QList widgetList; QCheckBox *enabledCheckBox = new QCheckBox; connect(enabledCheckBox, &QAbstractButton::clicked, this, &PluginDelegate::slotStateChanged); connect(enabledCheckBox, &QAbstractButton::clicked, this, &PluginDelegate::emitChanged); QPushButton *aboutPushButton = new QPushButton; aboutPushButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-information"))); aboutPushButton->setToolTip(i18n("About")); connect(aboutPushButton, &QAbstractButton::clicked, this, &PluginDelegate::slotAboutClicked); QPushButton *configurePushButton = new QPushButton; configurePushButton->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); configurePushButton->setToolTip(i18n("Configure")); connect(configurePushButton, &QAbstractButton::clicked, this, &PluginDelegate::slotConfigureClicked); setBlockedEventTypes(enabledCheckBox, QList() << QEvent::MouseButtonPress << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick << QEvent::KeyPress << QEvent::KeyRelease); setBlockedEventTypes(aboutPushButton, QList() << QEvent::MouseButtonPress << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick << QEvent::KeyPress << QEvent::KeyRelease); setBlockedEventTypes(configurePushButton, QList() << QEvent::MouseButtonPress << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick << QEvent::KeyPress << QEvent::KeyRelease); widgetList << enabledCheckBox << configurePushButton << aboutPushButton; return widgetList; } void KPluginSelector::Private::PluginDelegate::updateItemWidgets(const QList widgets, const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const { QCheckBox *checkBox = static_cast(widgets[0]); checkBox->resize(checkBox->sizeHint()); checkBox->move(pluginSelector_d->dependantLayoutValue(MARGIN, checkBox->sizeHint().width(), option.rect.width()), option.rect.height() / 2 - checkBox->sizeHint().height() / 2); QPushButton *aboutPushButton = static_cast(widgets[2]); QSize aboutPushButtonSizeHint = aboutPushButton->sizeHint(); aboutPushButton->resize(aboutPushButtonSizeHint); aboutPushButton->move(pluginSelector_d->dependantLayoutValue(option.rect.width() - MARGIN - aboutPushButtonSizeHint.width(), aboutPushButtonSizeHint.width(), option.rect.width()), option.rect.height() / 2 - aboutPushButtonSizeHint.height() / 2); QPushButton *configurePushButton = static_cast(widgets[1]); QSize configurePushButtonSizeHint = configurePushButton->sizeHint(); configurePushButton->resize(configurePushButtonSizeHint); configurePushButton->move(pluginSelector_d->dependantLayoutValue(option.rect.width() - MARGIN * 2 - configurePushButtonSizeHint.width() - aboutPushButtonSizeHint.width(), configurePushButtonSizeHint.width(), option.rect.width()), option.rect.height() / 2 - configurePushButtonSizeHint.height() / 2); if (!index.isValid() || !index.internalPointer()) { checkBox->setVisible(false); aboutPushButton->setVisible(false); configurePushButton->setVisible(false); } else { checkBox->setChecked(index.model()->data(index, Qt::CheckStateRole).toBool()); checkBox->setEnabled(index.model()->data(index, IsCheckableRole).toBool()); configurePushButton->setVisible(index.model()->data(index, ServicesCountRole).toBool()); configurePushButton->setEnabled(index.model()->data(index, Qt::CheckStateRole).toBool()); } } void KPluginSelector::Private::PluginDelegate::slotStateChanged(bool state) { if (!focusedIndex().isValid()) { return; } const QModelIndex index = focusedIndex(); pluginSelector_d->dependenciesWidget->clearDependencies(); PluginEntry *pluginEntry = index.model()->data(index, PluginEntryRole).value(); pluginSelector_d->updateDependencies(pluginEntry, state); const_cast(index.model())->setData(index, state, Qt::CheckStateRole); } void KPluginSelector::Private::PluginDelegate::emitChanged() { emit changed(true); } void KPluginSelector::Private::PluginDelegate::slotAboutClicked() { const QModelIndex index = focusedIndex(); const QAbstractItemModel *model = index.model(); const QString name = model->data(index, NameRole).toString(); const QString comment = model->data(index, CommentRole).toString(); const QString author = model->data(index, AuthorRole).toString(); const QString email = model->data(index, EmailRole).toString(); const QString website = model->data(index, WebsiteRole).toString(); const QString version = model->data(index, VersionRole).toString(); const QString license = model->data(index, LicenseRole).toString(); KAboutData aboutData(name, name, version, comment, KAboutLicense::byKeyword(license).key(), QString(), QString(), website); aboutData.setProgramIconName(index.model()->data(index, Qt::DecorationRole).toString()); const QStringList authors = author.split(QLatin1Char(',')); const QStringList emails = email.split(QLatin1Char(',')); if (authors.count() == emails.count()) { int i = 0; - foreach (const QString &author, authors) { + for (const QString &author : authors) { if (!author.isEmpty()) { aboutData.addAuthor(author, QString(), emails[i]); } i++; } } KAboutApplicationDialog aboutPlugin(aboutData, itemView()); aboutPlugin.setWindowTitle(i18nc("Used only for plugins", "About %1", aboutData.displayName())); aboutPlugin.exec(); } void KPluginSelector::Private::PluginDelegate::slotConfigureClicked() { configure(focusedIndex()); } void KPluginSelector::Private::PluginDelegate::configure(const QModelIndex& index) { const QAbstractItemModel *model = index.model(); PluginEntry *pluginEntry = model->data(index, PluginEntryRole).value(); KPluginInfo pluginInfo = pluginEntry->pluginInfo; QDialog configDialog(itemView()); configDialog.setWindowTitle(model->data(index, NameRole).toString()); // The number of KCModuleProxies in use determines whether to use a tabwidget QTabWidget *newTabWidget = nullptr; // Widget to use for the setting dialog's main widget, // either a QTabWidget or a KCModuleProxy QWidget *mainWidget = nullptr; // Widget to use as the KCModuleProxy's parent. // The first proxy is owned by the dialog itself QWidget *moduleProxyParentWidget = &configDialog; - foreach (const KService::Ptr &servicePtr, pluginInfo.kcmServices()) { + const auto lstServices = pluginInfo.kcmServices(); + for (const KService::Ptr &servicePtr : lstServices) { if (!servicePtr->noDisplay()) { KCModuleInfo moduleInfo(servicePtr); KCModuleProxy *currentModuleProxy = new KCModuleProxy(moduleInfo, moduleProxyParentWidget, pluginSelector_d->kcmArguments); if (currentModuleProxy->realModule()) { moduleProxyList << currentModuleProxy; if (mainWidget && !newTabWidget) { // we already created one KCModuleProxy, so we need a tab widget. // Move the first proxy into the tab widget and ensure this and subsequent // proxies are in the tab widget newTabWidget = new QTabWidget(&configDialog); moduleProxyParentWidget = newTabWidget; mainWidget->setParent(newTabWidget); KCModuleProxy *moduleProxy = qobject_cast(mainWidget); if (moduleProxy) { newTabWidget->addTab(mainWidget, moduleProxy->moduleInfo().moduleName()); mainWidget = newTabWidget; } else { delete newTabWidget; newTabWidget = nullptr; moduleProxyParentWidget = &configDialog; mainWidget->setParent(nullptr); } } if (newTabWidget) { newTabWidget->addTab(currentModuleProxy, servicePtr->name()); } else { mainWidget = currentModuleProxy; } } else { delete currentModuleProxy; } } } // it could happen that we had services to show, but none of them were real modules. if (!moduleProxyList.isEmpty()) { QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(mainWidget); const int marginHint = configDialog.style()->pixelMetric(QStyle::PM_DefaultChildMargin); layout->insertSpacing(-1, marginHint); QDialogButtonBox *buttonBox = new QDialogButtonBox(&configDialog); buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::RestoreDefaults), KStandardGuiItem::defaults()); connect(buttonBox, &QDialogButtonBox::accepted, &configDialog, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, &configDialog, &QDialog::reject); connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, this, &PluginDelegate::slotDefaultClicked); layout->addWidget(buttonBox); configDialog.setLayout(layout); if (configDialog.exec() == QDialog::Accepted) { - foreach (KCModuleProxy *moduleProxy, moduleProxyList) { - QStringList parentComponents = moduleProxy->moduleInfo().service()->property(QStringLiteral("X-KDE-ParentComponents")).toStringList(); + for (KCModuleProxy *moduleProxy : qAsConst(moduleProxyList)) { + const QStringList parentComponents = moduleProxy->moduleInfo().service()->property(QStringLiteral("X-KDE-ParentComponents")).toStringList(); moduleProxy->save(); - foreach (const QString &parentComponent, parentComponents) { + for (const QString &parentComponent : parentComponents) { emit configCommitted(parentComponent.toLatin1()); } } } else { - foreach (KCModuleProxy *moduleProxy, moduleProxyList) { + for (KCModuleProxy *moduleProxy : qAsConst(moduleProxyList)) { moduleProxy->load(); } } qDeleteAll(moduleProxyList); moduleProxyList.clear(); } } void KPluginSelector::Private::PluginDelegate::slotDefaultClicked() { - foreach (KCModuleProxy *moduleProxy, moduleProxyList) { + for (KCModuleProxy *moduleProxy : qAsConst(moduleProxyList)) { moduleProxy->defaults(); } } QFont KPluginSelector::Private::PluginDelegate::titleFont(const QFont &baseFont) const { QFont retFont(baseFont); retFont.setBold(true); return retFont; } #include "moc_kpluginselector_p.cpp" #include "moc_kpluginselector.cpp" diff --git a/src/ksettings/dialog.cpp b/src/ksettings/dialog.cpp index 934921b..97ac34c 100644 --- a/src/ksettings/dialog.cpp +++ b/src/ksettings/dialog.cpp @@ -1,562 +1,563 @@ /* This file is part of the KDE project 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 "dialog.h" #include "dialog_p.h" #include "dispatcher.h" #include #include #include #include #include #include #include #include #include #include #include #include #include uint qHash(const KCModuleInfo &info) { return qHash(info.fileName()); } namespace KSettings { Dialog::Dialog(QWidget *parent) : KCMultiDialog(*new DialogPrivate(this), new KPageWidget, parent) { } Dialog::Dialog(const QStringList &components, QWidget *parent) : KCMultiDialog(*new DialogPrivate(this), new KPageWidget, parent) { Q_D(Dialog); d->components = components; } Dialog::~Dialog() { } void Dialog::setAllowComponentSelection(bool selection) { d_func()->staticlistview = !selection; } bool Dialog::allowComponentSelection() const { return !d_func()->staticlistview; } void Dialog::setKCMArguments(const QStringList &arguments) { Q_D(Dialog); d->arguments = arguments; } void Dialog::setComponentBlacklist(const QStringList &blacklist) { Q_D(Dialog); d->componentBlacklist = blacklist; } void Dialog::addPluginInfos(const KPluginInfo::List &plugininfos) { Q_D(Dialog); for (KPluginInfo::List::ConstIterator it = plugininfos.begin(); it != plugininfos.end(); ++it) { d->registeredComponents.append(it->pluginName()); if (it->kcmServices().isEmpty()) { // this plugin has no kcm services, still we want to show the disable/enable stuff // so add a dummy kcm KService::Ptr service = it->service(); d->kcmInfos << KCModuleInfo(service); continue; } - foreach (const KService::Ptr &service, it->kcmServices()) { + const auto lst = it->kcmServices(); + for (const KService::Ptr &service : lst) { d->kcmInfos << KCModuleInfo(service); } } // The plugin, when disabled, disables all the KCMs described by kcmServices(). // - Normally they are grouped using a .setdlg file so that the group parent can get a // checkbox to enable/disable the plugin. // - If the plugin does not belong to a group and has only one KCM the checkbox can be // used with this KCM. // - If the plugin belongs to a group but there are other modules in the group that do not // belong to this plugin we give a kError and show no checkbox // - If the plugin belongs to multiple groups we give a kError and show no checkbox d->plugininfos = plugininfos; } KPluginInfo::List Dialog::pluginInfos() const { return d_func()->plugininfos; } void Dialog::showEvent(QShowEvent *) { Q_D(Dialog); if (d->firstshow) { setUpdatesEnabled(false); d->kcmInfos += d->instanceServices(); if (!d->components.isEmpty()) { d->kcmInfos += d->parentComponentsServices(d->components); } d->createDialogFromServices(); d->firstshow = false; setUpdatesEnabled(true); } Dispatcher::syncConfiguration(); } DialogPrivate::DialogPrivate(Dialog *parent) : KCMultiDialogPrivate(parent), staticlistview(true), firstshow(true), pluginStateDirty(0) { } QSet DialogPrivate::instanceServices() { //qDebug() ; QString componentName = QCoreApplication::instance()->applicationName(); registeredComponents.append(componentName); //qDebug() << "calling KServiceGroup::childGroup( " << componentName << " )"; KServiceGroup::Ptr service = KServiceGroup::childGroup(componentName); QSet ret; if (service && service->isValid()) { //qDebug() << "call was successful"; const KServiceGroup::List list = service->entries(); for (KServiceGroup::List::ConstIterator it = list.begin(); it != list.end(); ++it) { KSycocaEntry::Ptr p = (*it); if (p->isType(KST_KService)) { //qDebug() << "found service"; const KService::Ptr service(static_cast(p.data())); ret << KCModuleInfo(service); } else qWarning() << "KServiceGroup::childGroup returned" " something else than a KService" << endl; } } return ret; } QSet DialogPrivate::parentComponentsServices(const QStringList &kcdparents) { registeredComponents += kcdparents; QString constraint = kcdparents.join(QStringLiteral("' in [X-KDE-ParentComponents]) or ('")); constraint = QStringLiteral("('") + constraint + QStringLiteral("' in [X-KDE-ParentComponents])"); //qDebug() << "constraint = " << constraint; const QList services = KServiceTypeTrader::self()->query(QStringLiteral("KCModule"), constraint); QSet ret; ret.reserve(services.count()); - foreach (const KService::Ptr &service, services) { + for (const KService::Ptr &service : services) { ret << KCModuleInfo(service); } return ret; } bool DialogPrivate::isPluginForKCMEnabled(const KCModuleInfo *moduleinfo, KPluginInfo &pinfo) const { // if the user of this class requested to hide disabled modules // we check whether it should be enabled or not bool enabled = true; //qDebug() << "check whether the '" << moduleinfo->moduleName() << "' KCM should be shown"; // for all parent components const QStringList parentComponents = moduleinfo->service()->property( QStringLiteral("X-KDE-ParentComponents")).toStringList(); for (QStringList::ConstIterator pcit = parentComponents.begin(); pcit != parentComponents.end(); ++pcit) { // if the parentComponent is not registered ignore it if (!registeredComponents.contains(*pcit)) { continue; } // we check if the parent component is a plugin // if not the KCModule must be enabled enabled = true; if (pinfo.pluginName() == *pcit) { // it is a plugin: we check whether the plugin is enabled pinfo.load(); enabled = pinfo.isPluginEnabled(); //qDebug() << "parent " << *pcit << " is " << (enabled ? "enabled" : "disabled"); } // if it is enabled we're done for this KCModuleInfo if (enabled) { return true; } } return enabled; } bool DialogPrivate::isPluginImmutable(const KPluginInfo &pinfo) const { return pinfo.property(QStringLiteral("X-KDE-PluginInfo-Immutable")).toBool(); } KPageWidgetItem *DialogPrivate::createPageItem(KPageWidgetItem *parentItem, const QString &name, const QString &comment, const QString &iconName, int weight) { Q_Q(Dialog); QWidget *page = new QWidget(q); QCheckBox *checkBox = new QCheckBox(i18n("Enable component"), page); QLabel *iconLabel = new QLabel(page); QLabel *commentLabel = new QLabel(comment, page); commentLabel->setTextFormat(Qt::RichText); QVBoxLayout *layout = new QVBoxLayout(page); layout->addWidget(checkBox); layout->addWidget(iconLabel); layout->addWidget(commentLabel); layout->addStretch(); page->setLayout(layout); KPageWidgetItem *item = new KPageWidgetItem(page, name); item->setIcon(QIcon::fromTheme(iconName)); iconLabel->setPixmap(item->icon().pixmap(128, 128)); item->setProperty("_k_weight", weight); checkBoxForItem.insert(item, checkBox); const KPageWidgetModel *model = qobject_cast(q->pageWidget()->model()); Q_ASSERT(model); if (parentItem) { const QModelIndex parentIndex = model->index(parentItem); const int siblingCount = model->rowCount(parentIndex); int row = 0; for (; row < siblingCount; ++row) { KPageWidgetItem *siblingItem = model->item(parentIndex.child(row, 0)); if (siblingItem->property("_k_weight").toInt() > weight) { // the item we found is heavier than the new module q->insertPage(siblingItem, item); break; } } if (row == siblingCount) { // the new module is either the first or the heaviest item q->addSubPage(parentItem, item); } } else { const int siblingCount = model->rowCount(); int row = 0; for (; row < siblingCount; ++row) { KPageWidgetItem *siblingItem = model->item(model->index(row, 0)); if (siblingItem->property("_k_weight").toInt() > weight) { // the item we found is heavier than the new module q->insertPage(siblingItem, item); break; } } if (row == siblingCount) { // the new module is either the first or the heaviest item q->addPage(item); } } return (item); } void DialogPrivate::parseGroupFile(const QString &filename) { KConfig file(filename, KConfig::SimpleConfig); const QStringList groups = file.groupList(); for (const QString &group : groups) { if (group.isEmpty()) { continue; } KConfigGroup conf(&file, group); const QString parentId = conf.readEntry("Parent"); KPageWidgetItem *parentItem = pageItemForGroupId.value(parentId); KPageWidgetItem *item = createPageItem(parentItem, conf.readEntry("Name"), conf.readEntry("Comment"), conf.readEntry("Icon"), conf.readEntry("Weight", 100)); pageItemForGroupId.insert(group, item); } } void DialogPrivate::createDialogFromServices() { Q_Q(Dialog); // read .setdlg files (eg: share/kapp/kapp.setdlg) const QString setdlgpath = QStandardPaths::locate(QStandardPaths::DataLocation /*includes appname, too*/, QCoreApplication::instance()->applicationName() + QStringLiteral(".setdlg")); if (!setdlgpath.isEmpty()) { parseGroupFile(setdlgpath); } const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::DataLocation, QStringLiteral("ksettingsdialog"), QStandardPaths::LocateDirectory); for (const QString &dir : dirs) { const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.setdlg")); for (const QString &file : fileNames) { parseGroupFile(dir + QLatin1Char('/') + file); } } //qDebug() << kcmInfos.count(); - foreach (const KCModuleInfo &info, kcmInfos) { + for (const KCModuleInfo &info : qAsConst(kcmInfos)) { const QStringList parentComponents = info.service()->property(QStringLiteral("X-KDE-ParentComponents")).toStringList(); bool blacklisted = false; - foreach (const QString &parentComponent, parentComponents) { + for (const QString &parentComponent : parentComponents) { if (componentBlacklist.contains(parentComponent)) { blacklisted = true; break; } } if (blacklisted) { continue; } const QString parentId = info.service()->property(QStringLiteral("X-KDE-CfgDlgHierarchy"), QVariant::String).toString(); KPageWidgetItem *parent = pageItemForGroupId.value(parentId); if (!parent) { // dummy kcm bool foundPlugin = false; - foreach (const KPluginInfo &pinfo, plugininfos) { + for (KPluginInfo pinfo : qAsConst(plugininfos)) { if (pinfo.service() == info.service()) { if (pinfo.kcmServices().isEmpty()) { const KService::Ptr service = info.service(); // FIXME get weight from service or plugin info const int weight = 1000; KPageWidgetItem *item = createPageItem(nullptr, service->name(), service->comment(), service->icon(), weight); connectItemCheckBox(item, pinfo, pinfo.isPluginEnabled()); foundPlugin = true; break; } } } if (foundPlugin) { continue; } } KPageWidgetItem *item = q->addModule(info, parent, arguments); // qDebug() << "added KCM '" << info.moduleName() << "'"; - foreach (KPluginInfo pinfo, plugininfos) { + for (KPluginInfo pinfo : qAsConst(plugininfos)) { // qDebug() << pinfo.pluginName(); if (pinfo.kcmServices().contains(info.service())) { const bool isEnabled = isPluginForKCMEnabled(&info, pinfo); // qDebug() << "correct KPluginInfo for this KCM"; // this KCM belongs to a plugin if (parent && pinfo.kcmServices().count() >= 1) { item->setEnabled(isEnabled); const KPluginInfo &plugin = pluginForItem.value(parent); if (plugin.isValid()) { if (plugin != pinfo) { qCritical() << "A group contains more than one plugin: '" << plugin.pluginName() << "' and '" << pinfo.pluginName() << "'. Now it won't be possible to enable/disable the plugin." << endl; parent->setCheckable(false); q->disconnect(parent, SIGNAL(toggled(bool)), q, SLOT(_k_updateEnabledState(bool))); } // else everything is fine } else { connectItemCheckBox(parent, pinfo, isEnabled); } } else { pluginForItem.insert(item, pinfo); item->setCheckable(!isPluginImmutable(pinfo)); item->setChecked(isEnabled); q->connect(item, SIGNAL(toggled(bool)), q, SLOT(_k_updateEnabledState(bool))); } break; } } } // now that the KCMs are in, check for empty groups and remove them again { const KPageWidgetModel *model = qobject_cast(q->pageWidget()->model()); const QHash::ConstIterator end = pageItemForGroupId.constEnd(); QHash::ConstIterator it = pageItemForGroupId.constBegin(); for (; it != end; ++it) { const QModelIndex index = model->index(it.value()); KPluginInfo pinfo; - foreach (const KPluginInfo &p, plugininfos) { + for (const KPluginInfo &p : qAsConst(plugininfos)) { if (p.name() == it.key()) { pinfo = p; break; } } bool allowEmpty = false; if (pinfo.isValid()) { allowEmpty = pinfo.property(QStringLiteral("X-KDE-PluginInfo-AllowEmptySettings")).toBool(); } if (!index.child(0, 0).isValid()) { // no children, and it's not allowed => remove this item if (!allowEmpty) { q->removePage(it.value()); } else { connectItemCheckBox(it.value(), pinfo, pinfo.isPluginEnabled()); } } } } // TODO: Don't show the reset button until the issue with the // KPluginSelector::load() method is solved. // Problem: // KCMultiDialog::show() call KCModule::load() to reset all KCMs // (KPluginSelector::load() resets all plugin selections and all plugin // KCMs). // The reset button calls KCModule::load(), too but in this case we want the // KPluginSelector to only reset the current visible plugin KCM and not // touch the plugin selections. // I have no idea how to check that in KPluginSelector::load()... //q->showButton(KDialog::User1, true); QObject::connect(q->button(QDialogButtonBox::Ok), SIGNAL(clicked()), q, SLOT(_k_syncConfiguration())); QObject::connect(q->button(QDialogButtonBox::Apply), SIGNAL(clicked()), q, SLOT(_k_syncConfiguration())); QObject::connect(q, SIGNAL(configCommitted(QByteArray)), q, SLOT(_k_reparseConfiguration(QByteArray))); } void DialogPrivate::connectItemCheckBox(KPageWidgetItem *item, const KPluginInfo &pinfo, bool isEnabled) { Q_Q(Dialog); QCheckBox *checkBox = checkBoxForItem.value(item); Q_ASSERT(checkBox); pluginForItem.insert(item, pinfo); item->setCheckable(!isPluginImmutable(pinfo)); item->setChecked(isEnabled); checkBox->setVisible(!isPluginImmutable(pinfo)); checkBox->setChecked(isEnabled); q->connect(item, SIGNAL(toggled(bool)), q, SLOT(_k_updateEnabledState(bool))); q->connect(item, &KPageWidgetItem::toggled, checkBox, &QAbstractButton::setChecked); q->connect(checkBox, &QAbstractButton::clicked, item, &KPageWidgetItem::setChecked); } void DialogPrivate::_k_syncConfiguration() { Q_Q(Dialog); const QHash::Iterator endIt = pluginForItem.end(); QHash::Iterator it = pluginForItem.begin(); for (; it != endIt; ++it) { KPageWidgetItem *item = it.key(); KPluginInfo pinfo = it.value(); pinfo.setPluginEnabled(item->isChecked()); pinfo.save(); } if (pluginStateDirty > 0) { emit q->pluginSelectionChanged(); pluginStateDirty = 0; } Dispatcher::syncConfiguration(); } void DialogPrivate::_k_reparseConfiguration(const QByteArray &a) { Dispatcher::reparseConfiguration(QString::fromLatin1(a)); } /* void DialogPrivate::_k_configureTree() { // qDebug() ; QObject::connect(subdlg, SIGNAL(okClicked()), q, SLOT(_k_updateTreeList())); QObject::connect(subdlg, SIGNAL(applyClicked()), q, SLOT(_k_updateTreeList())); QObject::connect(subdlg, SIGNAL(okClicked()), q, SIGNAL(pluginSelectionChanged())); QObject::connect(subdlg, SIGNAL(applyClicked()), q, SIGNAL(pluginSelectionChanged())); } */ void DialogPrivate::_k_clientChanged() { if (pluginStateDirty > 0) { Q_Q(Dialog); q->buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(true); } else { KCMultiDialogPrivate::_k_clientChanged(); } } void DialogPrivate::_k_updateEnabledState(bool enabled) { Q_Q(Dialog); KPageWidgetItem *item = qobject_cast(q->sender()); if (!item) { qWarning() << "invalid sender"; return; } // iterate over all child KPageWidgetItem objects and check whether they need to be enabled/disabled const KPageWidgetModel *model = qobject_cast(q->pageWidget()->model()); Q_ASSERT(model); QModelIndex index = model->index(item); if (!index.isValid()) { qWarning() << "could not find item in model"; return; } const KPluginInfo &pinfo = pluginForItem.value(item); if (!pinfo.isValid()) { qWarning() << "could not find KPluginInfo in item"; return; } if (pinfo.isPluginEnabled() != enabled) { ++pluginStateDirty; } else { --pluginStateDirty; } if (pluginStateDirty < 2) { _k_clientChanged(); } //qDebug() ; QModelIndex firstborn = index.child(0, 0); if (firstborn.isValid()) { //qDebug() << "iterating over children"; // change all children index = firstborn; QStack stack; while (index.isValid()) { //qDebug() << index; KPageWidgetItem *item = model->item(index); //qDebug() << "item->setEnabled(" << enabled << ')'; item->setEnabled(enabled); firstborn = index.child(0, 0); if (firstborn.isValid()) { stack.push(index); index = firstborn; } else { index = index.sibling(index.row() + 1, 0); while (!index.isValid() && !stack.isEmpty()) { index = stack.pop(); index = index.sibling(index.row() + 1, 0); } } } } } } //namespace #include "moc_dialog.cpp" diff --git a/src/ksettings/dispatcher.cpp b/src/ksettings/dispatcher.cpp index 4d5fa89..7c0233a 100644 --- a/src/ksettings/dispatcher.cpp +++ b/src/ksettings/dispatcher.cpp @@ -1,106 +1,107 @@ /* This file is part of the KDE project 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 "dispatcher.h" #include "dispatcher_p.h" #include namespace KSettings { namespace Dispatcher { Q_GLOBAL_STATIC(DispatcherPrivate, d) void registerComponent(const QString &componentName, QObject *recv, const char *slot) { Q_ASSERT(!componentName.isEmpty()); // qDebug() << componentName; d()->m_componentName[recv] = componentName; d()->m_componentInfo[componentName].slotList.append(ComponentInfo::Slot(recv, slot)); ++(d()->m_componentInfo[componentName].count); QObject::connect(recv, &QObject::destroyed, d(), &DispatcherPrivate::unregisterComponent); } KSharedConfig::Ptr configForComponentName(const QString &componentName) { // qDebug() ; return KSharedConfig::openConfig(componentName + QStringLiteral("rc")); } QList componentNames() { // qDebug() ; QList names; for (QMap::ConstIterator it = d()->m_componentInfo.constBegin(), total = d()->m_componentInfo.constEnd(); it != total; ++it) { if ((*it).count > 0) { names.append(it.key()); } } return names; } void reparseConfiguration(const QString &componentName) { // qDebug() << componentName; // check if the componentName is valid: if (! d()->m_componentInfo.contains(componentName)) { return; } // first we reparse the config so that the KConfig object will be up to date KSharedConfig::Ptr config = configForComponentName(componentName); config->reparseConfiguration(); - foreach (const ComponentInfo::Slot &slot, d()->m_componentInfo[componentName].slotList) { + const auto lstSlot = d()->m_componentInfo[componentName].slotList; + for (const ComponentInfo::Slot &slot : lstSlot) { QMetaObject::invokeMethod(slot.first, slot.second); } } void syncConfiguration() { for (QMap::ConstIterator it = d()->m_componentInfo.constBegin(), total = d()->m_componentInfo.constEnd(); it != total; ++it) { KSharedConfig::Ptr config = configForComponentName(it.key()); config->sync(); } } void DispatcherPrivate::unregisterComponent(QObject *obj) { if (!m_componentName.contains(obj)) { qWarning() << Q_FUNC_INFO << "Tried to unregister an object which is not already registered."; return; } QString name = m_componentName[obj]; m_componentName.remove(obj); //obj will be destroyed when we return, so we better remove this entry --(m_componentInfo[name].count); // qDebug() << "componentName=" << name << "refcount=" << m_componentInfo[name].count; Q_ASSERT(m_componentInfo[name].count >= 0); if (m_componentInfo[name].count == 0) { m_componentInfo.remove(name); } } } // namespace Dispatcher } // namespace KSettings #include "moc_dispatcher_p.cpp"