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