diff --git a/CMakeLists.txt b/CMakeLists.txt index b3490d6..0d96dfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,95 +1,95 @@ 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(KParts 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}) set(REQUIRED_QT_VERSION 5.10.0) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core Widgets Xml) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(KDEPackageAppTemplates) include(ECMAddQch) include(GenerateExportHeader) include(ECMSetupVersion) 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 KPARTS VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kparts_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5PartsConfigVersion.cmake" SOVERSION 5) find_package(KF5Config ${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(KF5KIO ${KF5_DEP_VERSION} REQUIRED) find_package(KF5JobWidgets ${KF5_DEP_VERSION} REQUIRED) find_package(KF5Service ${KF5_DEP_VERSION} REQUIRED) find_package(KF5TextWidgets ${KF5_DEP_VERSION} REQUIRED) find_package(KF5WidgetsAddons ${KF5_DEP_VERSION} REQUIRED) find_package(KF5XmlGui ${KF5_DEP_VERSION} REQUIRED) if(BUILD_TESTING) add_subdirectory( tests ) add_subdirectory( autotests ) endif() add_definitions(-DTRANSLATION_DOMAIN=\"kparts5\") if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ki18n_install(po) endif() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) - +add_definitions(-DQT_NO_FOREACH) add_subdirectory( src ) add_subdirectory(templates) # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Parts") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5Parts_QCH FILE KF5PartsQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5PartsQchTargets.cmake\")") endif() include(CMakePackageConfigHelpers) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5PartsConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5PartsConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5PartsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5PartsConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5PartsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5PartsTargets.cmake NAMESPACE KF5:: ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kparts_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/partmanager.cpp b/src/partmanager.cpp index f4d5247..a828862 100644 --- a/src/partmanager.cpp +++ b/src/partmanager.cpp @@ -1,591 +1,591 @@ /* This file is part of the KDE project Copyright (C) 1999 Simon Hausmann (C) 1999 David Faure 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 "partmanager.h" #include "partactivateevent.h" #include "partselectevent.h" #include "guiactivateevent.h" #include "part.h" #include #include #include #include //#define DEBUG_PARTMANAGER using namespace KParts; namespace KParts { class PartManagerPrivate { public: PartManagerPrivate() { m_activeWidget = nullptr; m_activePart = nullptr; m_selectedPart = nullptr; m_selectedWidget = nullptr; m_bAllowNestedParts = false; m_bIgnoreScrollBars = false; m_activationButtonMask = Qt::LeftButton | Qt::MidButton | Qt::RightButton; m_reason = PartManager::NoReason; m_bIgnoreExplicitFocusRequest = false; } ~PartManagerPrivate() { } void setReason(QEvent *ev) { switch (ev->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonDblClick: { QMouseEvent *mev = static_cast(ev); m_reason = mev->button() == Qt::LeftButton ? PartManager::ReasonLeftClick : (mev->button() == Qt::MidButton ? PartManager::ReasonMidClick : PartManager::ReasonRightClick); break; } case QEvent::FocusIn: m_reason = static_cast(ev)->reason(); break; default: qWarning() << "PartManagerPrivate::setReason got unexpected ev type " << ev->type(); break; } } bool allowExplicitFocusEvent(QEvent *ev) const { if (ev->type() == QEvent::FocusIn) { QFocusEvent *fev = static_cast(ev); return (!m_bIgnoreExplicitFocusRequest || fev->reason() != Qt::OtherFocusReason); } return true; } Part *m_activePart; QWidget *m_activeWidget; QList m_parts; PartManager::SelectionPolicy m_policy; Part *m_selectedPart; QWidget *m_selectedWidget; QList m_managedTopLevelWidgets; short int m_activationButtonMask; bool m_bIgnoreScrollBars; bool m_bAllowNestedParts; int m_reason; bool m_bIgnoreExplicitFocusRequest; }; } PartManager::PartManager(QWidget *parent) : QObject(parent), d(new PartManagerPrivate) { qApp->installEventFilter(this); d->m_policy = Direct; addManagedTopLevelWidget(parent); } PartManager::PartManager(QWidget *topLevel, QObject *parent) : QObject(parent), d(new PartManagerPrivate) { qApp->installEventFilter(this); d->m_policy = Direct; addManagedTopLevelWidget(topLevel); } PartManager::~PartManager() { - foreach (const QWidget *w, d->m_managedTopLevelWidgets) { + for (const QWidget *w : qAsConst(d->m_managedTopLevelWidgets)) { disconnect(w, &QWidget::destroyed, this, &PartManager::slotManagedTopLevelWidgetDestroyed); } - foreach (Part *it, d->m_parts) { + for (Part *it : qAsConst(d->m_parts)) { it->setManager(nullptr); } // core dumps ... setActivePart( 0 ); qApp->removeEventFilter(this); delete d; } void PartManager::setSelectionPolicy(SelectionPolicy policy) { d->m_policy = policy; } PartManager::SelectionPolicy PartManager::selectionPolicy() const { return d->m_policy; } void PartManager::setAllowNestedParts(bool allow) { d->m_bAllowNestedParts = allow; } bool PartManager::allowNestedParts() const { return d->m_bAllowNestedParts; } void PartManager::setIgnoreScrollBars(bool ignore) { d->m_bIgnoreScrollBars = ignore; } bool PartManager::ignoreScrollBars() const { return d->m_bIgnoreScrollBars; } void PartManager::setActivationButtonMask(short int buttonMask) { d->m_activationButtonMask = buttonMask; } short int PartManager::activationButtonMask() const { return d->m_activationButtonMask; } bool PartManager::eventFilter(QObject *obj, QEvent *ev) { if (ev->type() != QEvent::MouseButtonPress && ev->type() != QEvent::MouseButtonDblClick && ev->type() != QEvent::FocusIn) { return false; } if (!obj->isWidgetType()) { return false; } QWidget *w = static_cast(obj); if (((w->windowFlags().testFlag(Qt::Dialog)) && w->isModal()) || (w->windowFlags().testFlag(Qt::Popup)) || (w->windowFlags().testFlag(Qt::Tool))) { return false; } QMouseEvent *mev = nullptr; if (ev->type() == QEvent::MouseButtonPress || ev->type() == QEvent::MouseButtonDblClick) { mev = static_cast(ev); #ifdef DEBUG_PARTMANAGER qDebug() << "PartManager::eventFilter button: " << mev->button() << " " << "d->m_activationButtonMask=" << d->m_activationButtonMask; #endif if ((mev->button() & d->m_activationButtonMask) == 0) { return false; // ignore this button } } Part *part; while (w) { QPoint pos; if (!d->m_managedTopLevelWidgets.contains(w->topLevelWidget())) { return false; } if (d->m_bIgnoreScrollBars && ::qobject_cast(w)) { return false; } if (mev) { // mouse press or mouse double-click event pos = mev->globalPos(); part = findPartFromWidget(w, pos); } else { part = findPartFromWidget(w); } #ifdef DEBUG_PARTMANAGER const char *evType = (ev->type() == QEvent::MouseButtonPress) ? "MouseButtonPress" : (ev->type() == QEvent::MouseButtonDblClick) ? "MouseButtonDblClick" : (ev->type() == QEvent::FocusIn) ? "FocusIn" : "OTHER! ERROR!"; #endif if (part) { // We found a part whose widget is w if (d->m_policy == PartManager::TriState) { if (ev->type() == QEvent::MouseButtonDblClick) { if (part == d->m_activePart && w == d->m_activeWidget) { return false; } #ifdef DEBUG_PARTMANAGER qDebug() << "PartManager::eventFilter dblclick -> setActivePart" << part; #endif d->setReason(ev); setActivePart(part, w); d->m_reason = NoReason; return true; } if ((d->m_selectedWidget != w || d->m_selectedPart != part) && (d->m_activeWidget != w || d->m_activePart != part)) { if (part->isSelectable()) { setSelectedPart(part, w); } else { #ifdef DEBUG_PARTMANAGER qDebug() << "Part " << part << " (non-selectable) made active because " << w->metaObject()->className() << " got event" << " " << evType; #endif d->setReason(ev); setActivePart(part, w); d->m_reason = NoReason; } return true; } else if (d->m_selectedWidget == w && d->m_selectedPart == part) { #ifdef DEBUG_PARTMANAGER qDebug() << "Part " << part << " made active (from selected) because " << w->metaObject()->className() << " got event" << " " << evType; #endif d->setReason(ev); setActivePart(part, w); d->m_reason = NoReason; return true; } else if (d->m_activeWidget == w && d->m_activePart == part) { setSelectedPart(nullptr); return false; } return false; } else if (part != d->m_activePart && d->allowExplicitFocusEvent(ev)) { #ifdef DEBUG_PARTMANAGER qDebug() << "Part " << part << " made active because " << w->metaObject()->className() << " got event" << " " << evType; #endif d->setReason(ev); setActivePart(part, w); d->m_reason = NoReason; } return false; } w = w->parentWidget(); if (w && (((w->windowFlags() & Qt::Dialog) && w->isModal()) || (w->windowFlags() & Qt::Popup) || (w->windowFlags() & Qt::Tool))) { #ifdef DEBUG_PARTMANAGER qDebug() << QString("No part made active although %1/%2 got event - loop aborted").arg(obj->objectName()).arg(obj->metaObject()->className()); #endif return false; } } #ifdef DEBUG_PARTMANAGER qDebug() << QString("No part made active although %1/%2 got event").arg(obj->objectName()).arg(obj->metaObject()->className()); #endif return false; } Part *PartManager::findPartFromWidget(QWidget *widget, const QPoint &pos) { for (QList::iterator it = d->m_parts.begin(), end = d->m_parts.end(); it != end; ++it) { Part *part = (*it)->hitTest(widget, pos); if (part && d->m_parts.contains(part)) { return part; } } return nullptr; } Part *PartManager::findPartFromWidget(QWidget *widget) { for (QList::iterator it = d->m_parts.begin(), end = d->m_parts.end(); it != end; ++it) { if (widget == (*it)->widget()) { return (*it); } } return nullptr; } void PartManager::addPart(Part *part, bool setActive) { Q_ASSERT(part); // don't add parts more than once :) if (d->m_parts.contains(part)) { #ifdef DEBUG_PARTMANAGER qWarning() << part << " already added"; #endif return; } d->m_parts.append(part); part->setManager(this); if (setActive) { setActivePart(part); if (QWidget *w = part->widget()) { // Prevent focus problems if (w->focusPolicy() == Qt::NoFocus) { qWarning() << "Part '" << part->objectName() << "' has a widget " << w->objectName() << " with a focus policy of NoFocus. It should have at least a" << "ClickFocus policy, for part activation to work well." << endl; } if (part->widget() && part->widget()->focusPolicy() == Qt::TabFocus) { qWarning() << "Part '" << part->objectName() << "' has a widget " << w->objectName() << " with a focus policy of TabFocus. It should have at least a" << "ClickFocus policy, for part activation to work well." << endl; } w->setFocus(); w->show(); } } emit partAdded(part); } void PartManager::removePart(Part *part) { if (!d->m_parts.contains(part)) { return; } const int nb = d->m_parts.removeAll(part); Q_ASSERT(nb == 1); Q_UNUSED(nb); // no warning in release mode part->setManager(nullptr); emit partRemoved(part); if (part == d->m_activePart) { setActivePart(nullptr); } if (part == d->m_selectedPart) { setSelectedPart(nullptr); } } void PartManager::replacePart(Part *oldPart, Part *newPart, bool setActive) { //qDebug() << "replacePart " << oldPart->name() << "-> " << newPart->name() << " setActive=" << setActive; // This methods does exactly removePart + addPart but without calling setActivePart(0) in between if (!d->m_parts.contains(oldPart)) { qFatal("Can't remove part %s, not in KPartManager's list.", oldPart->objectName().toLocal8Bit().constData()); return; } d->m_parts.removeAll(oldPart); oldPart->setManager(nullptr); emit partRemoved(oldPart); addPart(newPart, setActive); } void PartManager::setActivePart(Part *part, QWidget *widget) { if (part && !d->m_parts.contains(part)) { qWarning() << "trying to activate a non-registered part!" << part->objectName(); return; // don't allow someone call setActivePart with a part we don't know about } //check whether nested parts are disallowed and activate the top parent part then, by traversing the //tree recursively (Simon) if (part && !d->m_bAllowNestedParts) { QObject *parentPart = part->parent(); // ### this relies on people using KParts::Factory! KParts::Part *parPart = ::qobject_cast(parentPart); if (parPart) { setActivePart(parPart, parPart->widget()); return; } } #ifdef DEBUG_PARTMANAGER qDebug() << "PartManager::setActivePart d->m_activePart=" << d->m_activePart << "<->part=" << part << " d->m_activeWidget=" << d->m_activeWidget << "<->widget=" << widget << endl; #endif // don't activate twice if (d->m_activePart && part && d->m_activePart == part && (!widget || d->m_activeWidget == widget)) { return; } KParts::Part *oldActivePart = d->m_activePart; QWidget *oldActiveWidget = d->m_activeWidget; setSelectedPart(nullptr); d->m_activePart = part; d->m_activeWidget = widget; if (oldActivePart) { KParts::Part *savedActivePart = part; QWidget *savedActiveWidget = widget; PartActivateEvent ev(false, oldActivePart, oldActiveWidget); QApplication::sendEvent(oldActivePart, &ev); if (oldActiveWidget) { disconnect(oldActiveWidget, &QWidget::destroyed, this, &PartManager::slotWidgetDestroyed); QApplication::sendEvent(oldActiveWidget, &ev); } d->m_activePart = savedActivePart; d->m_activeWidget = savedActiveWidget; } if (d->m_activePart) { if (!widget) { d->m_activeWidget = part->widget(); } PartActivateEvent ev(true, d->m_activePart, d->m_activeWidget); QApplication::sendEvent(d->m_activePart, &ev); if (d->m_activeWidget) { connect(d->m_activeWidget, &QWidget::destroyed, this, &PartManager::slotWidgetDestroyed); QApplication::sendEvent(d->m_activeWidget, &ev); } } // Set the new active instance //setActiveComponent(d->m_activePart ? d->m_activePart->componentData() : KComponentData::mainComponent()); #ifdef DEBUG_PARTMANAGER qDebug() << this << " emitting activePartChanged " << d->m_activePart; #endif emit activePartChanged(d->m_activePart); } Part *PartManager::activePart() const { return d->m_activePart; } QWidget *PartManager::activeWidget() const { return d->m_activeWidget; } void PartManager::setSelectedPart(Part *part, QWidget *widget) { if (part == d->m_selectedPart && widget == d->m_selectedWidget) { return; } Part *oldPart = d->m_selectedPart; QWidget *oldWidget = d->m_selectedWidget; d->m_selectedPart = part; d->m_selectedWidget = widget; if (part && !widget) { d->m_selectedWidget = part->widget(); } if (oldPart) { PartSelectEvent ev(false, oldPart, oldWidget); QApplication::sendEvent(oldPart, &ev); QApplication::sendEvent(oldWidget, &ev); } if (d->m_selectedPart) { PartSelectEvent ev(true, d->m_selectedPart, d->m_selectedWidget); QApplication::sendEvent(d->m_selectedPart, &ev); QApplication::sendEvent(d->m_selectedWidget, &ev); } } Part *PartManager::selectedPart() const { return d->m_selectedPart; } QWidget *PartManager::selectedWidget() const { return d->m_selectedWidget; } void PartManager::slotObjectDestroyed() { // qDebug(); removePart(const_cast(static_cast(sender()))); } void PartManager::slotWidgetDestroyed() { // qDebug(); if (static_cast(sender()) == d->m_activeWidget) { setActivePart(nullptr); //do not remove the part because if the part's widget dies, then the } //part will delete itself anyway, invoking removePart() in its destructor } const QList PartManager::parts() const { return d->m_parts; } void PartManager::addManagedTopLevelWidget(const QWidget *topLevel) { if (!topLevel->isTopLevel()) { return; } if (d->m_managedTopLevelWidgets.contains(topLevel)) { return; } d->m_managedTopLevelWidgets.append(topLevel); connect(topLevel, &QWidget::destroyed, this, &PartManager::slotManagedTopLevelWidgetDestroyed); } void PartManager::removeManagedTopLevelWidget(const QWidget *topLevel) { d->m_managedTopLevelWidgets.removeAll(topLevel); } void PartManager::slotManagedTopLevelWidgetDestroyed() { const QWidget *widget = static_cast(sender()); removeManagedTopLevelWidget(widget); } int PartManager::reason() const { return d->m_reason; } void PartManager::setIgnoreExplictFocusRequests(bool ignore) { d->m_bIgnoreExplicitFocusRequest = ignore; } diff --git a/src/plugin.cpp b/src/plugin.cpp index 7ac2446..451c693 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -1,300 +1,301 @@ /* This file is part of the KDE project Copyright (C) 1999 Simon Hausmann (C) 1999 David Faure 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 "plugin.h" #include "part.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KParts; class Q_DECL_HIDDEN Plugin::PluginPrivate { public: QString m_parentInstance; QString m_library; // filename of the library }; Plugin::Plugin(QObject *parent) : QObject(parent), d(new PluginPrivate()) { //qDebug() << className(); } Plugin::~Plugin() { delete d; } QString Plugin::xmlFile() const { QString path = KXMLGUIClient::xmlFile(); if (d->m_parentInstance.isEmpty() || (!path.isEmpty() && QDir::isAbsolutePath(path))) { return path; } QString absPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, d->m_parentInstance + QLatin1Char('/') + path); Q_ASSERT(!absPath.isEmpty()); return absPath; } QString Plugin::localXMLFile() const { QString path = KXMLGUIClient::xmlFile(); if (d->m_parentInstance.isEmpty() || (!path.isEmpty() && QDir::isAbsolutePath(path))) { return path; } QString absPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + d->m_parentInstance + QLatin1Char('/') + path; return absPath; } //static QList Plugin::pluginInfos(const QString &componentName) { QList plugins; QMap sortedPlugins; const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, componentName + QStringLiteral("/kpartplugins"), QStandardPaths::LocateDirectory); - Q_FOREACH (const QString &dir, dirs) { - Q_FOREACH (const QString &file, QDir(dir).entryList(QStringList(QStringLiteral("*.rc")))) { + for (const QString &dir : dirs) { + const auto rcfiles = QDir(dir).entryList(QStringList(QStringLiteral("*.rc"))); + for (const QString &file : rcfiles) { const QFileInfo fInfo(dir + QLatin1Char('/') + file); QMap::Iterator mapIt = sortedPlugins.find(fInfo.fileName()); if (mapIt == sortedPlugins.end()) { mapIt = sortedPlugins.insert(fInfo.fileName(), QStringList()); } mapIt.value().append(fInfo.absoluteFilePath()); } } QMap::ConstIterator mapIt = sortedPlugins.constBegin(); QMap::ConstIterator mapEnd = sortedPlugins.constEnd(); for (; mapIt != mapEnd; ++mapIt) { PluginInfo info; QString doc; info.m_absXMLFileName = KXMLGUIClient::findMostRecentXMLFile(mapIt.value(), doc); if (info.m_absXMLFileName.isEmpty()) { continue; } // qDebug() << "found KParts Plugin : " << info.m_absXMLFileName; info.m_relXMLFileName = QStringLiteral("kpartplugins/") + mapIt.key(); info.m_document.setContent(doc); if (info.m_document.documentElement().isNull()) { continue; } plugins.append(info); } return plugins; } void Plugin::loadPlugins(QObject *parent, const QString &componentName) { loadPlugins(parent, pluginInfos(componentName), componentName); } void Plugin::loadPlugins(QObject *parent, const QList &pluginInfos, const QString &componentName) { QList::ConstIterator pIt = pluginInfos.begin(); QList::ConstIterator pEnd = pluginInfos.end(); for (; pIt != pEnd; ++pIt) { QString library = (*pIt).m_document.documentElement().attribute(QStringLiteral("library")); if (library.isEmpty() || hasPlugin(parent, library)) { continue; } Plugin *plugin = loadPlugin(parent, library, (*pIt).m_document.documentElement().attribute(QStringLiteral("X-KDE-PluginKeyword"))); if (plugin) { plugin->d->m_parentInstance = componentName; plugin->setXMLFile((*pIt).m_relXMLFileName, false, false); plugin->setDOMDocument((*pIt).m_document); } } } void Plugin::loadPlugins(QObject *parent, const QList &pluginInfos) { loadPlugins(parent, pluginInfos, QString()); } // static Plugin *Plugin::loadPlugin(QObject *parent, const QString &libname, const QString &keyword) { KPluginLoader loader(libname); KPluginFactory *factory = loader.factory(); if (!factory) { return nullptr; } Plugin *plugin = factory->create(keyword, parent); if (!plugin) { return nullptr; } plugin->d->m_library = libname; return plugin; } QList Plugin::pluginObjects(QObject *parent) { QList objects; if (!parent) { return objects; } objects = parent->findChildren(QString(), Qt::FindDirectChildrenOnly); return objects; } bool Plugin::hasPlugin(QObject *parent, const QString &library) { const QObjectList plugins = parent->children(); QObjectList::ConstIterator it = plugins.begin(); for (; it != plugins.end(); ++it) { Plugin *plugin = qobject_cast(*it); if (plugin && plugin->d->m_library == library) { return true; } } return false; } void Plugin::setComponentData(const KAboutData &pluginData) { KAboutData::registerPluginData(pluginData); KXMLGUIClient::setComponentName(pluginData.componentName(), pluginData.displayName()); } void Plugin::loadPlugins(QObject *parent, KXMLGUIClient *parentGUIClient, const QString &componentName, bool enableNewPluginsByDefault, int interfaceVersionRequired) { KConfigGroup cfgGroup(KSharedConfig::openConfig(componentName + QStringLiteral("rc")), "KParts Plugins"); const QList plugins = pluginInfos(componentName); QList::ConstIterator pIt = plugins.begin(); const QList::ConstIterator pEnd = plugins.end(); for (; pIt != pEnd; ++pIt) { QDomElement docElem = (*pIt).m_document.documentElement(); QString library = docElem.attribute(QStringLiteral("library")); QString keyword; if (library.isEmpty()) { continue; } // Check configuration const QString name = docElem.attribute(QStringLiteral("name")); bool pluginEnabled = enableNewPluginsByDefault; if (cfgGroup.hasKey(name + QStringLiteral("Enabled"))) { pluginEnabled = cfgGroup.readEntry(name + QStringLiteral("Enabled"), false); } else { // no user-setting, load plugin default setting QString relPath = componentName + QLatin1Char('/') + (*pIt).m_relXMLFileName; relPath.truncate(relPath.lastIndexOf(QLatin1Char('.'))); // remove extension relPath += QStringLiteral(".desktop"); //qDebug() << "looking for " << relPath; const QString desktopfile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, relPath); if (!desktopfile.isEmpty()) { //qDebug() << "loadPlugins found desktop file for " << name << ": " << desktopfile; KDesktopFile _desktop(desktopfile); const KConfigGroup desktop = _desktop.desktopGroup(); keyword = desktop.readEntry("X-KDE-PluginKeyword", ""); pluginEnabled = desktop.readEntry("X-KDE-PluginInfo-EnabledByDefault", enableNewPluginsByDefault); if (interfaceVersionRequired != 0) { const int version = desktop.readEntry("X-KDE-InterfaceVersion", 1); if (version != interfaceVersionRequired) { // qDebug() << "Discarding plugin " << name << ", interface version " << version << ", expected " << interfaceVersionRequired; pluginEnabled = false; } } } else { //qDebug() << "loadPlugins no desktop file found in " << relPath; } } // search through already present plugins const QObjectList pluginList = parent->children(); bool pluginFound = false; for (QObjectList::ConstIterator it = pluginList.begin(); it != pluginList.end(); ++it) { Plugin *plugin = qobject_cast(*it); if (plugin && plugin->d->m_library == library) { // delete and unload disabled plugins if (!pluginEnabled) { // qDebug() << "remove plugin " << name; KXMLGUIFactory *factory = plugin->factory(); if (factory) { factory->removeClient(plugin); } delete plugin; } pluginFound = true; break; } } // if the plugin is already loaded or if it's disabled in the // configuration do nothing if (pluginFound || !pluginEnabled) { continue; } // qDebug() << "load plugin " << name << " " << library << " " << keyword; Plugin *plugin = loadPlugin(parent, library, keyword); if (plugin) { plugin->d->m_parentInstance = componentName; plugin->setXMLFile((*pIt).m_relXMLFileName, false, false); plugin->setDOMDocument((*pIt).m_document); parentGUIClient->insertChildClient(plugin); } } }