File indexing completed on 2024-04-28 15:29:22

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef KPARTS_PARTLOADER_H
0009 #define KPARTS_PARTLOADER_H
0010 
0011 #include <KPluginFactory>
0012 #include <KPluginMetaData>
0013 #include <QObject>
0014 #include <QVector>
0015 #include <kparts/kparts_export.h>
0016 
0017 namespace KParts
0018 {
0019 /**
0020  * Helper methods for locating and loading parts.
0021  * This is based upon KPluginFactory, but it takes
0022  * care of querying by mimetype, sorting the available parts by builtin
0023  * preference and by user preference.
0024  * @since 5.69
0025  */
0026 namespace PartLoader
0027 {
0028 namespace Private
0029 {
0030 
0031 enum ErrorType {
0032     CouldNotLoadPlugin,
0033     NoPartFoundForMimeType,
0034     NoPartInstantiatedForMimeType,
0035 };
0036 
0037 /**
0038  * @internal
0039  * @param errorString translated, user-visible error string
0040  * @param errorText untranslated error text
0041  * @param argument argument for the text
0042  */
0043 KPARTS_EXPORT void getErrorStrings(QString *errorString, QString *errorText, const QString &argument, ErrorType type);
0044 
0045 #if KPARTS_ENABLE_DEPRECATED_SINCE(5, 88)
0046 /**
0047  * Helper for PartLoader::createPartInstanceForMimeType<T>
0048  * @internal
0049  */
0050 KPARTS_EXPORT QObject *createPartInstanceForMimeTypeHelper(const char *iface, const QString &mimeType, QWidget *parentWidget, QObject *parent, QString *error);
0051 #endif
0052 }
0053 
0054 /**
0055  * Locate all available KParts for a mimetype.
0056  * @return a list of plugin metadata, sorted by preference.
0057  * This takes care both of the builtin preference (set by developers)
0058  * and of user preference (stored in mimeapps.list).
0059  *
0060  * This uses KPluginMetaData::findPlugins, i.e. it requires the parts to
0061  * provide the metadata as JSON embedded into the plugin.
0062  * Until KF6, however, it also supports .desktop files as a fallback solution.
0063  *
0064  * To load a part from one of the KPluginMetaData instances returned here,
0065  * use \ref instantiatePart()
0066  *
0067  * @since 5.69
0068  */
0069 KPARTS_EXPORT QVector<KPluginMetaData> partsForMimeType(const QString &mimeType);
0070 
0071 /**
0072  * Attempts to create a KPart from the given metadata.
0073  *
0074  * @code
0075  * KPluginFactory::Result<MyPart> result = KParts::PartLoader::instantiatePart<MyPart>(metaData, parentWidget, parent, args);
0076  * if (result) {
0077  *     // result.plugin is valid and can be accessed
0078  * } else {
0079  *     // result contains information about the error
0080  * }
0081  * @endcode
0082  * If there is no extra error handling needed the plugin can be directly accessed and checked if it is a nullptr
0083  * @code
0084  * if (auto plugin = KParts::PartLoader::instantiatePart<MyPart>(metaData, parentWidget, parent, args).plugin) {
0085  *     // The plugin is valid and can be accessed
0086  * }
0087  * @endcode
0088  * @param data KPluginMetaData from which the plugin should be loaded
0089  * @param parentWidget The parent widget
0090  * @param parent The parent object
0091  * @param args A list of arguments to be passed to the part
0092  * @return Result object which contains the plugin instance and potentially error information
0093  * @since 5.100
0094  */
0095 template<typename T>
0096 static KPluginFactory::Result<T>
0097 instantiatePart(const KPluginMetaData &data, QWidget *parentWidget = nullptr, QObject *parent = nullptr, const QVariantList &args = {})
0098 {
0099     KPluginFactory::Result<T> result;
0100     KPluginFactory::Result<KPluginFactory> factoryResult = KPluginFactory::loadFactory(data);
0101     if (!factoryResult.plugin) {
0102         result.errorString = factoryResult.errorString;
0103         result.errorReason = factoryResult.errorReason;
0104         return result;
0105     }
0106     T *instance = factoryResult.plugin->create<T>(parentWidget, parent, args);
0107     if (!instance) {
0108         const QString fileName = data.fileName();
0109         Private::getErrorStrings(&result.errorString, &result.errorText, fileName, Private::CouldNotLoadPlugin);
0110         result.errorReason = KPluginFactory::INVALID_KPLUGINFACTORY_INSTANTIATION;
0111     } else {
0112         result.plugin = instance;
0113     }
0114     return result;
0115 }
0116 
0117 /**
0118  * Use this method to create a KParts part. It will try to create an object which inherits
0119  * @p T.
0120  *
0121  * @code
0122  * KPluginFactory::Result<KParts::ReadOnlyPart> result = KParts::PartLoader::instantiatePartForMimeType<KParts::ReadOnlyPart>(mimeType, parentWidget, parent,
0123  * args);
0124  * if (result) {
0125  *     // result.plugin is valid and can be accessed
0126  * } else {
0127  *     // result contains information about the error
0128  * }
0129  * @endcode
0130  * If there is no extra error handling needed the plugin can be directly accessed and checked if it is a nullptr
0131  * @code
0132  * if (auto plugin = KParts::PartLoader::instantiatePartForMimeType<KParts::ReadOnlyPart>(mimeType, parentWidget, parent, args).plugin) {
0133  *     // The plugin is valid and can be accessed
0134  * }
0135  * @endcode
0136  *
0137  * @tparam T The interface for which an object should be created. The object will inherit @p T.
0138  * @param mimeType The mimetype for which we need a KParts.
0139  * @param parentWidget The parent widget for the part's widget.
0140  * @param parent The parent of the part.
0141  * @return Result object which contains the plugin instance and potentially error information
0142  * @since 5.100
0143  */
0144 template<class T>
0145 static KPluginFactory::Result<T>
0146 instantiatePartForMimeType(const QString &mimeType, QWidget *parentWidget = nullptr, QObject *parent = nullptr, const QVariantList &args = {})
0147 {
0148     const QVector<KPluginMetaData> plugins = KParts::PartLoader::partsForMimeType(mimeType);
0149 
0150     if (plugins.isEmpty()) {
0151         KPluginFactory::Result<T> errorResult;
0152         errorResult.errorReason = KPluginFactory::ResultErrorReason::INVALID_PLUGIN;
0153         Private::getErrorStrings(&errorResult.errorString, &errorResult.errorText, mimeType, Private::NoPartFoundForMimeType);
0154 
0155         return errorResult;
0156     }
0157 
0158     for (const KPluginMetaData &plugin : plugins) {
0159         const KPluginFactory::Result<T> result = instantiatePart<T>(plugin, parentWidget, parent, args);
0160 
0161         if (result) {
0162             return result;
0163         }
0164     }
0165 
0166     KPluginFactory::Result<T> errorResult;
0167     errorResult.errorReason = KPluginFactory::ResultErrorReason::INVALID_PLUGIN;
0168     Private::getErrorStrings(&errorResult.errorString, &errorResult.errorText, mimeType, Private::NoPartInstantiatedForMimeType);
0169 
0170     return errorResult;
0171 }
0172 
0173 /**
0174  * Use this method to create a KParts part. It will try to create an object which inherits
0175  * \p T.
0176  *
0177  * Example:
0178  * \code
0179  *     QString errorString;
0180  *     m_part = KParts::PartLoader::createPartInstanceForMimeType<KParts::ReadOnlyPart>(
0181  *                   mimeType, this, this, &errorString);
0182  *     if (m_part) {
0183  *         layout->addWidget(m_part->widget()); // Integrate the widget
0184  *         createGUI(m_part); // Integrate the actions
0185  *         m_part->openUrl(url);
0186  *     } else {
0187  *         qWarning() << errorString;
0188  *     }
0189  * \endcode
0190  *
0191  * \tparam T The interface for which an object should be created. The object will inherit \p T.
0192  * \param mimeType The mimetype for which we need a KParts.
0193  * \param parentWidget The parent widget for the part's widget.
0194  * \param parent The parent of the part.
0195  * \param error Optional output parameter, it will be set to the error string, if any.
0196  * \returns A pointer to the created object is returned, or @c nullptr if an error occurred.
0197  * @since 5.69
0198  */
0199 template<class T>
0200 static T *createPartInstanceForMimeType(const QString &mimeType, QWidget *parentWidget = nullptr, QObject *parent = nullptr, QString *error = nullptr)
0201 {
0202     const KPluginFactory::Result<T> result = instantiatePartForMimeType<T>(mimeType, parentWidget, parent, {});
0203 
0204     if (result) {
0205         return result.plugin;
0206     }
0207 
0208     if (error) {
0209         *error = result.errorString;
0210     }
0211 
0212     return nullptr;
0213 }
0214 
0215 } // namespace
0216 } // namespace
0217 
0218 #endif