diff --git a/CMakeLists.txt b/CMakeLists.txt index 9580cf1..9c62596 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,95 +1,95 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.66.0") # handled by release scripts set(KF5_DEP_VERSION "5.65.0") # handled by release scripts project(KCMUtils VERSION ${KF5_VERSION}) include(FeatureSummary) find_package(ECM 5.65.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) set(REQUIRED_QT_VERSION 5.11.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(KF5GuiAddons ${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(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x054100) 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/CMakeLists.txt b/src/CMakeLists.txt index 6a5293d..ac2aa19 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,114 +1,114 @@ ########### kcmutils ############### set(kcmutils_LIB_SRCS kcmoduleinfo.cpp kcmoduleloader.cpp kcmoduleqml.cpp kcmultidialog.cpp kcmoduleproxy.cpp kpluginselector.cpp kcmodulecontainer.cpp ksettingswidgetadaptor.cpp ksettings/dispatcher.cpp ksettings/dialog.cpp ksettings/pluginpage.cpp ksettings/componentsdialog.cpp ) add_library(KF5KCMUtils ${kcmutils_LIB_SRCS}) generate_export_header(KF5KCMUtils BASE_NAME KCMUtils) target_include_directories(KF5KCMUtils INTERFACE "$") target_link_libraries(KF5KCMUtils PUBLIC Qt5::Widgets KF5::ConfigWidgets # KCModule KF5::Service # KService PRIVATE Qt5::DBus # dbus usage in kcmoduleproxy.cpp Qt5::Qml Qt5::Quick Qt5::QuickWidgets KF5::CoreAddons + KF5::GuiAddons # KIconUtils KF5::I18n - KF5::IconThemes # KIconLoader KF5::ItemViews # KWidgetItemDelegate KF5::XmlGui # KAboutApplicationDialog KF5::QuickAddons KF5::Declarative KF5::Package ) set_target_properties(KF5KCMUtils PROPERTIES VERSION ${KCMUTILS_VERSION_STRING} SOVERSION ${KCMUTILS_SOVERSION} EXPORT_NAME KCMUtils) ecm_generate_headers(KCMUtils_HEADERS HEADER_NAMES KCModuleInfo KCModuleLoader KCMultiDialog KCModuleProxy KPluginSelector KCModuleContainer REQUIRED_HEADERS KCMUtils_HEADERS ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kcmutils_export.h ${KCMUtils_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KCMUtils COMPONENT Devel ) ecm_generate_headers(KSettings_HEADERS HEADER_NAMES Dispatcher Dialog PluginPage RELATIVE ksettings REQUIRED_HEADERS KSettings_HEADERS ) install(FILES ${KSettings_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KCMUtils/ksettings COMPONENT Devel ) install(TARGETS KF5KCMUtils EXPORT KF5KCMUtilsTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES kcmodule.desktop kcmoduleinit.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR} ) if(BUILD_QCH) ecm_add_qch( KF5KCMUtils_QCH NAME KCMUtils BASE_NAME KF5KCMUtils VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KCMUtils_HEADERS} ${KSettings_HEADERS} ksettings/README.dox MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS Qt5Widgets_QCH KF5ConfigWidgets_QCH KF5Service_QCH INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} BLANK_MACROS KCMUTILS_EXPORT KCMUTILS_DEPRECATED KCMUTILS_DEPRECATED_EXPORT TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KCMUtils LIB_NAME KF5KCMUtils DEPS "widgets KConfigWidgets KService" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KCMUtils) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/kcmultidialog.cpp b/src/kcmultidialog.cpp index d53b05a..550ee84 100644 --- a/src/kcmultidialog.cpp +++ b/src/kcmultidialog.cpp @@ -1,568 +1,568 @@ /* 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 -#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; } } // Remove margins for the buttonbox; KPageDialog handles that already q->buttonBox()->setContentsMargins(0, 0, 0, 0); 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; bool defaulted = false; if (activeModule) { change = activeModule->changed(); defaulted = activeModule->defaulted(); 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) && !defaulted); } } } 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"))); + item->setIcon(KIconUtils::addOverlay(QIcon::fromTheme(kcm->moduleInfo().icon()), QIcon::fromTheme(QStringLiteral("dialog-warning")), Qt::BottomRightCorner)); } 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) */ QScreen *screen = QApplication::screenAt(pos()); if (screen) { const QSize maxSize = screen->availableGeometry().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; 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; for (const QString &componentName : componentNames) { if (!updatedComponents.contains(componentName)) { updatedComponents.append(componentName); } } } } // Send the configCommitted signal for every updated component. 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) */ 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"))); + item->setIcon(KIconUtils::addOverlay(QIcon::fromTheme(moduleInfo.icon()), QIcon::fromTheme(QStringLiteral("dialog-warning")), Qt::BottomRightCorner)); } 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(model->index(row, 0, parentIndex)); 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 3700d36..b3e0e32 100644 --- a/src/kpluginselector.cpp +++ b/src/kpluginselector.cpp @@ -1,920 +1,920 @@ /** * 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"); 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); // When a KPluginSelector instance gets focus, // it should pass over the focus to its child searchbar. setFocusProxy(d->lineEdit); } 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; 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--; } const QFont font = titleFont(option.font); const QFontMetrics fmTitle(font); const QString text = index.model()->data(index, Qt::DisplayRole).toString(); const QString comment = index.model()->data(index, CommentRole).toString(); const int maxTextWidth = qMax(fmTitle.boundingRect(text).width(), option.fontMetrics.boundingRect(comment).width()); + const auto iconSize = pluginSelector_d->listView->style()->pixelMetric(QStyle::PM_IconViewIconSize); return QSize(maxTextWidth + - (pluginSelector_d->showIcons ? KIconLoader::SizeMedium : 0) + MARGIN * i + pushButton->sizeHint().width() * j, - qMax(KIconLoader::SizeMedium + MARGIN * 2, fmTitle.height() + option.fontMetrics.height() + MARGIN * 2)); + (pluginSelector_d->showIcons ? iconSize : 0) + MARGIN * i + pushButton->sizeHint().width() * j, + qMax(iconSize + 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(); PluginEntry *pluginEntry = model->data(index, PluginEntryRole).value(); KPluginMetaData pluginMetaData = pluginEntry->pluginInfo.toMetaData(); KAboutPluginDialog aboutPlugin(pluginMetaData, itemView()); 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; 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) { for (KCModuleProxy *moduleProxy : qAsConst(moduleProxyList)) { const QStringList parentComponents = moduleProxy->moduleInfo().service()->property(QStringLiteral("X-KDE-ParentComponents")).toStringList(); moduleProxy->save(); for (const QString &parentComponent : parentComponents) { emit configCommitted(parentComponent.toLatin1()); } } } else { for (KCModuleProxy *moduleProxy : qAsConst(moduleProxyList)) { moduleProxy->load(); } } qDeleteAll(moduleProxyList); moduleProxyList.clear(); } } void KPluginSelector::Private::PluginDelegate::slotDefaultClicked() { 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/componentsdialog.cpp b/src/ksettings/componentsdialog.cpp index 60e2230..ed0e2b0 100644 --- a/src/ksettings/componentsdialog.cpp +++ b/src/ksettings/componentsdialog.cpp @@ -1,180 +1,179 @@ /* 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 "componentsdialog_p.h" #include #include #include #include #include -#include #include #include #include #include #include #include #include namespace KSettings { class Q_DECL_HIDDEN ComponentsDialog::ComponentsDialogPrivate { public: QTreeWidget *listview; QFrame *infowidget; QLabel *iconwidget; QLabel *commentwidget; QLabel *descriptionwidget; QMap plugininfomap; QList plugininfolist; }; ComponentsDialog::ComponentsDialog(QWidget *parent, const char *name) : QDialog(parent), d(new ComponentsDialogPrivate) { setObjectName(QString::fromLatin1(name)); setModal(false); setWindowTitle(i18n("Select Components")); QVBoxLayout *layout = new QVBoxLayout(this); QWidget *page = new QWidget(this); layout->addWidget(page); QDialogButtonBox *buttonBox = new QDialogButtonBox(this); buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel); connect(buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, this, &ComponentsDialog::savePluginInfos); connect(buttonBox, &QDialogButtonBox::accepted, this, &ComponentsDialog::savePluginInfos); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); layout->addWidget(buttonBox); QHBoxLayout *hbox = new QHBoxLayout(page); hbox->setContentsMargins(0, 0, 0, 0); d->listview = new QTreeWidget(page); d->listview->setMinimumSize(200, 200); d->infowidget = new QFrame(page); d->infowidget->setMinimumSize(200, 200); QVBoxLayout *vbox = new QVBoxLayout(d->infowidget); vbox->setContentsMargins(0, 0, 0, 0); d->iconwidget = new QLabel(d->infowidget); vbox->addWidget(d->iconwidget); vbox->addWidget(new KSeparator(d->infowidget)); d->commentwidget = new QLabel(d->infowidget); d->commentwidget->setWordWrap(true); vbox->addWidget(d->commentwidget); d->descriptionwidget = new QLabel(d->infowidget); d->descriptionwidget->setWordWrap(true); vbox->addWidget(d->descriptionwidget); d->listview->setAcceptDrops(false); connect(d->listview, &QTreeWidget::itemPressed, this, &ComponentsDialog::executed); connect(d->listview, &QTreeWidget::itemActivated, this, &ComponentsDialog::executed); connect(d->listview, SIGNAL(itemSelectionChanged(QTreeWidgetItem*,int)), this, SLOT(executed(QTreeWidgetItem*,int))); } ComponentsDialog::~ComponentsDialog() { delete d; } void ComponentsDialog::addPluginInfo(KPluginInfo *info) { d->plugininfolist.append(info); } void ComponentsDialog::setPluginInfos(const QMap & plugininfos) { for (QMap::ConstIterator it = plugininfos.begin(), total = plugininfos.end(); it != total; ++it) { d->plugininfolist.append(it.value()); } } void ComponentsDialog::setPluginInfos(const QList &plugins) { d->plugininfolist = plugins; } void ComponentsDialog::show() { // clear the treelist d->listview->clear(); d->plugininfomap.clear(); // construct the treelist for (QList::ConstIterator it = d->plugininfolist.constBegin(), total = d->plugininfolist.constEnd(); it != total; ++it) { (*it)->load(); QTreeWidgetItem *item = new QTreeWidgetItem(d->listview, QStringList((*it)->name())); if (!(*it)->icon().isEmpty()) { item->setIcon(0, QIcon::fromTheme((*it)->icon())); } item->setCheckState(0, (*it)->isPluginEnabled() ? Qt::Checked : Qt::Unchecked); d->plugininfomap[ item ] = (*it); } QDialog::show(); } void ComponentsDialog::executed(QTreeWidgetItem *item, int) { // qDebug() ; if (item == nullptr) { return; } bool checked = (item->checkState(0) == Qt::Checked); // qDebug() << "it's a " << ( checked ? "checked" : "unchecked" ) // << " QCheckListItem" << endl; KPluginInfo *info = d->plugininfomap[ item ]; info->setPluginEnabled(checked); //checkDependencies( info ); // show info about the component on the right d->iconwidget->setPixmap(QIcon::fromTheme(info->icon()).pixmap(style()->pixelMetric(QStyle::PM_MessageBoxIconSize))); d->commentwidget->setText(info->comment()); //d->descriptionwidget->setText( info->description() ); } void ComponentsDialog::savePluginInfos() { for (QList::ConstIterator it = d->plugininfolist.constBegin(), total = d->plugininfolist.constEnd(); it != total; ++it) { if ((*it)->config().isValid()) { (*it)->save(); (*it)->config().sync(); } } } } //namespace #include "moc_componentsdialog_p.cpp"