File indexing completed on 2024-05-12 05:00:04
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2023 Stefano Crocco <stefano.crocco@alice.it> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef DOWNLOADEREXTENSION_H 0008 #define DOWNLOADEREXTENSION_H 0009 0010 #include <KJob> 0011 #include <KParts/OpenUrlArguments> 0012 0013 #include <QObject> 0014 #include <QUrl> 0015 0016 #include "browserarguments.h" 0017 0018 #include <libkonq_export.h> 0019 0020 class QUrl; 0021 0022 namespace KParts { 0023 class ReadOnlyPart; 0024 } 0025 0026 namespace KonqInterfaces { 0027 0028 class DownloaderJob; 0029 0030 /** 0031 * @brief Interface for parts which need to download files themselves before they're opened or embedded instead of letting Konqueror do it 0032 * 0033 * This interface provides two pure virtual methods, downloadJob(), which returns a DownloaderJob, a `KJob` whose task is to perform the download and part(), 0034 * and a signal, downloadAndOpenUrl(), to be used instead of `KParts::BrowserExtension::openUrlRequest`. 0035 * 0036 * Most likely, when creating a class implementing this interface, you'll also need to create a concrete class deriving from DownloadJob. 0037 * 0038 * @warning When a part requests to download the URL itself, Konqueror doesn't try to auto-detect the mimetype of the URL, assuming that the 0039 * part has already tried to do so and passed the correct value to downloadAndOpenUrl(). 0040 * 0041 * @note The part doesn't need to implement this interface itself: it can be implemented by any of its children. 0042 */ 0043 class LIBKONQ_EXPORT DownloaderExtension : public QObject 0044 { 0045 Q_OBJECT 0046 0047 public: 0048 0049 /** 0050 * @brief Constructor 0051 * @param parent the parent object 0052 */ 0053 DownloaderExtension(QObject *parent = nullptr); 0054 0055 /** 0056 * @brief Destructor 0057 */ 0058 virtual ~DownloaderExtension(); 0059 0060 /** 0061 * @brief Retrieves a the `KJob` to download the given URL. 0062 * 0063 * This method is called by Konqueror in response to a downloadAndOpenUrl() signal 0064 * This method will return a job which, when started, will download the URL. 0065 * 0066 * Implementations of this method may return a new job or an existing job. @p id is a number 0067 * used to distinguish between different download operations for the same URL (in case, for example, 0068 * the user asks a second download of the same file before the first one has finished). 0069 * 0070 * @param url the URL to download 0071 * @param id the id of the download. It's used to distinguish different downloads for the same URLs. If this method is called 0072 * multiple times with the same @p url and @p id, implementations can either return the same job or 0073 * different jobs. They're _required_ to return different jobs when called with different @p url 0074 * and/or @p id. 0075 * @param parent the object to give as parent to the returned object. If this method is called multiple 0076 * times with the same @p url and @p id, and the implementation returns the same job, this will be 0077 * ignored in all calls after the first 0078 * @return the job to use to perform the download or `nullptr` if such a job can't be created. In theory, 0079 * this should never happen, unless this method is called for an URL for which the part didn't request 0080 * a download. 0081 */ 0082 virtual DownloaderJob* downloadJob(const QUrl &url, quint32 id, QObject *parent=nullptr)=0; 0083 0084 /** 0085 * @brief The part associated with the extension 0086 * @return The part the extension belongs to 0087 */ 0088 virtual KParts::ReadOnlyPart* part() const = 0; 0089 0090 /** 0091 * @brief Returns the given object or any of its children casted to a DownloaderInterface* 0092 * 0093 * This is essentially as `QObject::findChildren` except that it works even if DownloaderInterface 0094 * itself isn't a `QObject`. 0095 * @param obj the object which should be cast or have one of its children cast to a DownloaderInterface 0096 * @return @p obj or one of its children cast to a DownloaderInterface or `nullptr` if neither @p obj 0097 * nor any of its children are derived from DownloaderInterface 0098 */ 0099 static DownloaderExtension *downloader(QObject* obj); 0100 0101 signals: 0102 0103 /** 0104 * @brief Signal emitted by the extension to signal the application to open an URL after the part has finished 0105 * downloading the URL 0106 * 0107 * It has the same role of `KParts::BrowserExtension::openUrlRequest`. The main difference (aside from the @p downloadId argument) 0108 * is the fact that, unlike `KParts::BrowserExtension::openUrlRequest`, the handler for this signal is called synchronously. 0109 * This is important for the `WebEnginePart` implementation, where it allows to set the download path before having to accept the 0110 * download request. 0111 * 0112 * @param url the URL to download 0113 * @param downloadId an unique identifier for the download 0114 * @param arguments information about how to open the URL 0115 * @param browserArguments other information about how to open the URL 0116 * @param temp whether the downloaded file, if opened or embedded, should be deleted after use. This will be ignored if the user chooses to save the URL 0117 */ 0118 void downloadAndOpenUrl(const QUrl &url, quint32 downloadId, const KParts::OpenUrlArguments &arguments = KParts::OpenUrlArguments(), 0119 const BrowserArguments &browserArguments = BrowserArguments(), bool temp=true); 0120 }; 0121 0122 /** 0123 * @brief Class allowing a part to perform a download 0124 */ 0125 class LIBKONQ_EXPORT DownloaderJob : public KJob { 0126 Q_OBJECT 0127 public: 0128 0129 /** 0130 * @brief Default constructor 0131 * @param parent the parent object 0132 */ 0133 DownloaderJob(QObject* parent=nullptr); 0134 0135 /** 0136 * @brief destructor 0137 */ 0138 ~DownloaderJob() override {}; 0139 0140 /** 0141 * @brief Changes the path where the URL will be downloaded. 0142 * 0143 * @warning This function must be called from within a slot (or lambda) connected to the 0144 * `BrowserExtension::openUrlRequest` emitted by the part and before `start()` is called. 0145 * If called in other circumstances, whether it has any effect or not is up to the implementation. 0146 * @param path the new download path. It must be an absolute path. 0147 * @return `true` if the download path has been changed succesfully and `false` otherwise 0148 */ 0149 virtual bool setDownloadPath(const QString &path) = 0; 0150 0151 /** 0152 * @brief The path where the URL will be saved 0153 * @return the path where the URL will be saved. This path is decided by the 0154 * part requesting the download 0155 */ 0156 virtual QString downloadPath() const = 0; 0157 0158 /** 0159 * @brief Whether or not the download path can be changed 0160 * 0161 * Implementations are required to allow changing the download path from the slot connected 0162 * with the `BrowserExtension::openUrlRequest` signal and only before the job is started. 0163 * Implementations may also allow to change the download path later. 0164 * @return `true` if the download path can be changed and `false` otherwise. 0165 */ 0166 virtual bool canChangeDownloadPath() const = 0; 0167 0168 /** 0169 * @brief Whether or not the download has finished 0170 */ 0171 virtual bool finished() const = 0; 0172 0173 /** 0174 * @brief The URL to download 0175 * @return the URL to download 0176 */ 0177 virtual QUrl url() const = 0; 0178 0179 /** 0180 * @brief Convenience function to start the download 0181 * 0182 * This sets the job up, setting the Ui delegate and the job tracker interface for the job and changing the 0183 * download path, connects the \link DownloaderJob::downloadResult downloadResult \endlink signal to the given 0184 * functor and starts the job. 0185 * 0186 * @param destPath the path where the URL should be downloaded. If empty, the download path won't be changed 0187 * @param widget the widget to use for the Ui delegate 0188 * @param context the receiver or the context of the signal (depending on whether functor is actually a lambda or functor 0189 * or a pointer to member function) 0190 * @param functor the lambda, functor or pointer to member function to connect to the 0191 * \link DownloaderJob::downloadResult downloadResult \endlink signal 0192 * @warning In Qt5, functor cannot be a member function. If it is, no connection is done 0193 */ 0194 template <typename Functor> 0195 void startDownload(const QString &destPath, QWidget *widget, QObject *context, Functor functor); 0196 0197 /** 0198 * @brief Convenience function to start the download 0199 * 0200 * @overload 0201 * 0202 * As startDownload(const QString &, QWidget*, QObject*, Functor), except that it doesn't change the download path 0203 * @see startDownload(const QString &, QWidget*, QObject*, Functor) 0204 */ 0205 template <typename Functor> 0206 void startDownload(QWidget *widget, QObject *context, Functor functor); 0207 0208 private: 0209 0210 /** 0211 * @brief Helper function called by startDownload() 0212 * 0213 * It sets up the job UI delegate and tracker interface and, optionally, changes the 0214 * download destination. 0215 * 0216 * @param widget the widget to use for the Ui delegate 0217 * @param destPath the new download destination. If empty, the download destination won't be changed 0218 */ 0219 void prepareDownloadJob(QWidget *widget, const QString &destPath={}); 0220 0221 signals: 0222 0223 /** 0224 * @brief Signal emitted when a download has finished 0225 * 0226 * This is a convenience signal which is emitted in response to `KJob::result()`. It 0227 * provides a the job already cast to DownoaderJob and the local URL where the remote 0228 * URL was saved to. You can connect to this signal as you would to `KJob::result()`. 0229 * 0230 * @param job a pointer to the job. It's the same as the `job` argument in `KJob::result()` 0231 * but you don't need to cast it to a DownloaderJob 0232 * @param url the URL where the remote URL was saved to. There are three possibilities: 0233 * - if an error occurred, it will have the `error` scheme 0234 * - if the user canceled the download, it will be empty 0235 * - if the download was completed successfully, it will be a local URL 0236 */ 0237 void downloadResult(DownloaderJob *job, const QUrl &url); 0238 }; 0239 } 0240 0241 template<typename Functor> 0242 void KonqInterfaces::DownloaderJob::startDownload(const QString& destPath, QWidget* widget, QObject* context, Functor functor) 0243 { 0244 prepareDownloadJob(widget, destPath); 0245 //With KF5, this call doesn't compile 0246 #if QT_VERSION_MAJOR > 5 0247 connect(this, &DownloaderJob::downloadResult, context, functor); 0248 #endif 0249 start(); 0250 } 0251 template<typename Functor> 0252 void KonqInterfaces::DownloaderJob::startDownload(QWidget* widget, QObject* context, Functor functor) 0253 { 0254 prepareDownloadJob(widget, {}); 0255 //With KF5, this call doesn't compile 0256 #if QT_VERSION_MAJOR > 5 0257 connect(this, &DownloaderJob::downloadResult, context, functor); 0258 #endif 0259 start(); 0260 } 0261 0262 #endif // DOWNLOADEREXTENSION_H