diff --git a/CMakeLists.txt b/CMakeLists.txt index e3a3d5c..d2ca3cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,96 +1,97 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.71.0") # handled by release scripts set(KF5_DEP_VERSION "5.70.0") # handled by release scripts project(KCMUtils VERSION ${KF5_VERSION}) include(FeatureSummary) find_package(ECM 5.70.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.12.0) -find_package(Qt5 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED Widgets DBus Qml Quick QuickWidgets) +find_package(Qt5 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED Widgets DBus Qml Quick QuickWidgets Test) include(ECMGenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(CMakePackageConfigHelpers) include(ECMAddQch) include(ECMSetupQtPluginMacroNames) 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(KF5Service ${KF5_DEP_VERSION} REQUIRED) find_package(KF5XmlGui ${KF5_DEP_VERSION} REQUIRED) find_package(KF5Declarative ${KF5_DEP_VERSION} REQUIRED) ecm_setup_qtplugin_macro_names( JSON_NONE "KCMODULECONTAINER" CONFIG_CODE_VARIABLE PACKAGE_SETUP_AUTOMOC_VARIABLES ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x054600) 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) +add_subdirectory(autotests) # 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/autotests/CMakeLists.txt b/autotests/CMakeLists.txt new file mode 100644 index 0000000..d494215 --- /dev/null +++ b/autotests/CMakeLists.txt @@ -0,0 +1,7 @@ +include(ECMAddTests) + +ecm_add_tests( + kplugininfotest.cpp + + LINK_LIBRARIES KF5KCMUtils Qt5::Test +) diff --git a/autotests/YaST-systemsettings.desktop b/autotests/YaST-systemsettings.desktop new file mode 100644 index 0000000..c33c091 --- /dev/null +++ b/autotests/YaST-systemsettings.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Service +Name=YaST +Icon=yast-control-center +GenericName=Administrator Settings +Exec=kdesu -c /sbin/yast2 +X-KDE-System-Settings-Parent-Category=system-administration +X-KDE-ServiceTypes=SystemSettingsExternalApp diff --git a/autotests/kplugininfotest.cpp b/autotests/kplugininfotest.cpp new file mode 100644 index 0000000..6541eb4 --- /dev/null +++ b/autotests/kplugininfotest.cpp @@ -0,0 +1,42 @@ +/* This file is part of the KDE Frameworks + Copyright (c) 2020 David Faure + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License or ( at + your option ) version 3 or, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), 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 Lesser 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 +#include +#include + +class KPluginInfoTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void testExternalApp(); +}; + +void KPluginInfoTest::testExternalApp() +{ + const QString yast = QFINDTESTDATA("YaST-systemsettings.desktop"); + QVERIFY(!yast.isEmpty()); + KCModuleInfo info(yast); + QVERIFY(info.service()); +} + +QTEST_MAIN(KPluginInfoTest) +#include "kplugininfotest.moc" diff --git a/src/kcmoduleinfo.cpp b/src/kcmoduleinfo.cpp index 11d6643..efe9adb 100644 --- a/src/kcmoduleinfo.cpp +++ b/src/kcmoduleinfo.cpp @@ -1,214 +1,249 @@ /* Copyright (c) 1999 Matthias Hoelzer-Kluepfel Copyright (c) 2000 Matthias Elter Copyright (c) 2003 Daniel Molkentin Copyright (c) 2003,2006 Matthias Kretz This file is part of the KDE project 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 "kcmoduleinfo.h" #include #include #include #include #include class Q_DECL_HIDDEN KCModuleInfo::Private { public: Private(); Private(const KPluginInfo &); Private(const KService::Ptr &); QStringList keywords; QString name, icon, lib, handle, fileName, doc, comment; bool allLoaded = false; int weight = 100; + // For real C++ plugins KPluginInfo pluginInfo; + // Can be a C++ plugin, or just a desktop file launching an executable (see autotest) + KService::Ptr service; + /** * Reads the service entries specific for KCModule from the desktop file. * The usual desktop entries are read in the Private ctor. */ void loadAll(); }; KCModuleInfo::Private::Private() { } KCModuleInfo::Private::Private(const KPluginInfo &pluginInfo) : allLoaded(false) , pluginInfo(pluginInfo) { if (!pluginInfo.isValid()) { return; } // set the modules simple attributes name = pluginInfo.name(); comment = pluginInfo.comment(); icon = pluginInfo.icon(); fileName = pluginInfo.entryPath(); lib = pluginInfo.libraryPath(); keywords = pluginInfo.property(QStringLiteral("Keywords")).toStringList(); } +KCModuleInfo::Private::Private(const KService::Ptr &service) + : allLoaded(false), + pluginInfo(), + service(service) +{ + if (!service) { + return; + } + + name = service->name(); + comment = service->comment(); + icon = service->icon(); + fileName = service->entryPath(); + lib = service->library(); + keywords = service->keywords(); +} + KCModuleInfo::KCModuleInfo() : d(new Private) { } KCModuleInfo::KCModuleInfo(const QString &desktopFile) -// TODO KF6: turn this into KPluginMetaData(file) so that most callers still work, after adding the JSON to the .so files - : d(new Private(KPluginInfo(KService::serviceByStorageId(desktopFile)))) + : d(new Private(KService::serviceByStorageId(desktopFile))) { } KCModuleInfo::KCModuleInfo(KService::Ptr service) - : d(new Private(KPluginInfo(service))) + : d(new Private(service)) { } KCModuleInfo::KCModuleInfo(const KPluginInfo &pluginInfo) : d(new Private(pluginInfo)) { } KCModuleInfo::KCModuleInfo(const KCModuleInfo &rhs) : d(new Private) { (*this) = rhs; } KCModuleInfo &KCModuleInfo::operator=(const KCModuleInfo &rhs) { *d = *(rhs.d); return *this; } bool KCModuleInfo::operator==(const KCModuleInfo &rhs) const { return ((d->name == rhs.d->name) && (d->lib == rhs.d->lib) && (d->fileName == rhs.d->fileName)); } bool KCModuleInfo::operator!=(const KCModuleInfo &rhs) const { return ! operator==(rhs); } KCModuleInfo::~KCModuleInfo() { delete d; } void KCModuleInfo::Private::loadAll() { allLoaded = true; - if (!pluginInfo.isValid()) { /* We have a bogus service. All get functions will return empty/zero values */ + if (!pluginInfo.isValid() && !service) { /* We have a bogus service. All get functions will return empty/zero values */ return; } - // get the documentation path - doc = pluginInfo.property(QStringLiteral("X-DocPath")).toString(); - if (doc.isEmpty()) { - doc = pluginInfo.property(QStringLiteral("DocPath")).toString(); + if (service) { + // get the documentation path + doc = service->property(QStringLiteral("X-DocPath"), QVariant::String).toString(); + if (doc.isEmpty()) { + doc = service->property(QStringLiteral("DocPath"), QVariant::String).toString(); + } + + // read weight + QVariant tmp = service->property(QStringLiteral("X-KDE-Weight"), QVariant::Int); + weight = tmp.isValid() ? tmp.toInt() : 100; + + // factory handle + tmp = service->property(QStringLiteral("X-KDE-FactoryName"), QVariant::String); + handle = tmp.isValid() ? tmp.toString() : lib; + } else { + // get the documentation path + doc = pluginInfo.property(QStringLiteral("X-DocPath")).toString(); + if (doc.isEmpty()) { + doc = pluginInfo.property(QStringLiteral("DocPath")).toString(); + } + + // read weight + QVariant tmp = pluginInfo.property(QStringLiteral("X-KDE-Weight")).toInt(); + weight = tmp.isValid() ? tmp.toInt() : 100; + + // factory handle + tmp = pluginInfo.property(QStringLiteral("X-KDE-FactoryName")); + handle = tmp.isValid() ? tmp.toString() : lib; } - - // read weight - QVariant tmp = pluginInfo.property(QStringLiteral("X-KDE-Weight")).toInt(); - weight = tmp.isValid() ? tmp.toInt() : 100; - - // factory handle - tmp = pluginInfo.property(QStringLiteral("X-KDE-FactoryName")); - handle = tmp.isValid() ? tmp.toString() : lib; - } QString KCModuleInfo::fileName() const { return d->fileName; } QStringList KCModuleInfo::keywords() const { return d->keywords; } QString KCModuleInfo::moduleName() const { return d->name; } KService::Ptr KCModuleInfo::service() const { - return d->pluginInfo.service(); + return d->service ? d->service : d->pluginInfo.service(); } KPluginInfo KCModuleInfo::pluginInfo() const { return d->pluginInfo; } QString KCModuleInfo::comment() const { return d->comment; } QString KCModuleInfo::icon() const { return d->icon; } QString KCModuleInfo::library() const { return d->lib; } QString KCModuleInfo::docPath() const { if (!d->allLoaded) { d->loadAll(); } return d->doc; } QString KCModuleInfo::handle() const { if (!d->allLoaded) { d->loadAll(); } return d->handle; } int KCModuleInfo::weight() const { if (!d->allLoaded) { d->loadAll(); } return d->weight; }