File indexing completed on 2024-05-19 05:01:22

0001 /*
0002     This file is part of the KDE project.
0003 
0004     SPDX-FileCopyrightText: 2017 Stefano Crocco <stefano.crocco@alice.it>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-or-later
0007 */
0008 
0009 #ifndef WEBENGINEPARTDOWNLOADMANAGER_H
0010 #define WEBENGINEPARTDOWNLOADMANAGER_H
0011 
0012 #include <QObject>
0013 #include <QVector>
0014 #include <QTemporaryDir>
0015 #include <QDateTime>
0016 #include <QSet>
0017 #include <KJob>
0018 #include <QPointer>
0019 
0020 #include "qtwebengine6compat.h"
0021 
0022 #include "browseropenorsavequestion.h"
0023 #include "interfaces/downloaderextension.h"
0024 
0025 class WebEnginePage;
0026 class QWebEngineProfile;
0027 class WebEngineDownloadJob;
0028 
0029 class WebEnginePartDownloadManager : public QObject
0030 {
0031     Q_OBJECT
0032 
0033 public:
0034     ~WebEnginePartDownloadManager() override;
0035 
0036     WebEnginePartDownloadManager(QWebEngineProfile *profile, QObject *parent = nullptr);
0037 
0038     /**
0039      * @brief Enum which describes what the user wants to do with a URL once it has been downloaded
0040      *
0041      * Currently there are three possibilities:
0042      * - the user wants to open the URL in the application embedding the part (for example, when
0043      *  clicking on a link). This is the default download objective
0044      * - the user wants to save locally the file represented by the URL (for example, when using
0045      *  the "save link as..." context menu entry
0046      * - the user wants to save the currently displayed page locally (for example, when using the "Save as"
0047      *  menu entry
0048      */
0049     enum class DownloadObjective {
0050         OpenInApplication, //!< A URL is to be downloaded to be opened in the application
0051         SaveAs, //!< The current page is to saved locally
0052         SaveOnly //!< A URL is to be saved locally
0053     };
0054 
0055     /**
0056      * @brief Tells the download manager that the next download of the given URL for the given page
0057      * has a special objective
0058      *
0059      * This is needed to ensure that if the user choses, for example "Save As..." the page or document will actually be saved and not
0060      * opened with an external application or embedded.
0061      *
0062      * By default, downloads are considered having the \link DownloadObjective::OpenInApplication OpenInApplication\endlink objective;
0063      * this function is only needed to specify a different objective.
0064      *
0065      * @param url the url this setting applies to
0066      * @param page the page this setting applies to. Requests to download @p url made by pages other than @p page will be processed as
0067      * usual
0068      * @param objective the special objective for the download
0069      */
0070     void specifyDownloadObjective(const QUrl &url, WebEnginePage *page, DownloadObjective objective);
0071 
0072 private:
0073 
0074     static QString generateDownloadTempFileName(QString const &suggestedName, const QString &ext);
0075 
0076     /**
0077      * @brief Struct encapsulating a download objective with the page it refers to
0078      */
0079     struct DownloadObjectiveWithPage {
0080         QPointer<WebEnginePage> page = nullptr; //!< The page requesting the download
0081         DownloadObjective downloadObjective = DownloadObjective::OpenInApplication; //!< The objective of the download
0082         bool operator==(const DownloadObjectiveWithPage &other) const {return page == other.page && downloadObjective == other.downloadObjective;} //!< Equality operator
0083     };
0084 
0085     /**
0086      * @brief Retrieves the special objective for a download, if any
0087      *
0088      * This function is used to retrieve data set using specifyDownloadObjective().
0089      *
0090      * @param req the url to download
0091      * @param page the page requesting the download
0092      * @return the specified objective for the URL in @p url and page @p page, if any, and
0093      *  \link DownloadObjective::OpenInApplication OpenInApplication\endlink otherwise
0094      */
0095     DownloadObjective fetchDownloadObjective(const QUrl &url, WebEnginePage *page);
0096 
0097     /**
0098      * @brief Checks whether a download request for the given URL by the given page should be treated as a forced download or not
0099      *
0100      * @warning This function @b should only be called @b once for each download, because it removes information about the download from the internal
0101      * state (this is for performance reasons).
0102      * @param req the download request
0103      * @param page the page which requested the download
0104      * @return `true` if the page should be downloaded by the download manager and `false` if it should be processed as usual
0105      */
0106     // bool checkForceDownload(QWebEngineDownloadRequest *req, WebEnginePage *page);
0107 
0108     /**
0109      * @brief Saves a full HTML page, after asking the user which formats he wants to use
0110      *
0111      * The available formats are described in `QWebEngineDownloadRequest::SavePageFormat`
0112      * @param it the item to use for the download
0113      * @param page the page which requested the download
0114      */
0115     void saveHtmlPage(QWebEngineDownloadRequest *it, WebEnginePage *page);
0116 
0117     static QTemporaryDir& tempDownloadDir();
0118 
0119 public Q_SLOTS:
0120     void addPage(WebEnginePage *page);
0121     void removePage(QObject *page);
0122 
0123 private Q_SLOTS:
0124     void performDownload(QWebEngineDownloadRequest *it);
0125 
0126 
0127 private:
0128     QVector<WebEnginePage*> m_pages;
0129 
0130     /**
0131      * @brief Information about download objectives
0132      *
0133      * @see specifyDownloadObjective
0134      * @see fetchDownloadObjective
0135      * @todo See wether it would be possible to use both url and page as key
0136      */
0137     QMultiHash<QUrl, DownloadObjectiveWithPage> m_downloadObjectives;
0138 };
0139 
0140 class WebEngineDownloadJob : public KonqInterfaces::DownloaderJob
0141 {
0142     Q_OBJECT
0143 
0144 public:
0145     WebEngineDownloadJob(QWebEngineDownloadRequest *it, QObject *parent = nullptr);
0146     ~WebEngineDownloadJob() override;
0147 
0148     QUrl url() const override;
0149 
0150     void start() override;
0151 
0152     QString errorString() const override;
0153 
0154     bool setDownloadPath(const QString & path) override;
0155     QString downloadPath() const override;
0156     bool canChangeDownloadPath() const override;
0157     bool finished() const override;
0158 
0159     QWebEngineDownloadRequest* item() const;
0160 
0161 protected:
0162     bool doKill() override;
0163     bool doResume() override;
0164     bool doSuspend() override;
0165 
0166 private slots:
0167 #if QT_VERSION_MAJOR < 6
0168     void downloadProgressed(qint64 received, qint64 total);
0169 #else
0170     void downloadProgressed();
0171 #endif
0172 
0173     void stateChanged(QWebEngineDownloadRequest::DownloadState state);
0174     void startDownloading();
0175     void downloadFinished();
0176     void emitDownloadResult(KJob *job);
0177 
0178 private:
0179     bool m_started = false; ///<! @brief Whether the job has been started or not
0180     QPointer<QWebEngineDownloadRequest> m_downloadItem;
0181     QDateTime m_startTime;
0182 };
0183 
0184 #endif // WEBENGINEPARTDOWNLOADMANAGER_H