File indexing completed on 2024-11-24 04:34:29

0001 /***************************************************************************
0002  *   SPDX-License-Identifier: GPL-2.0-or-later
0003  *                                                                         *
0004  *   SPDX-FileCopyrightText: 2004-2023 Thomas Fischer <fischer@unix-ag.uni-kl.de>
0005  *                                                                         *
0006  *   This program is free software; you can redistribute it and/or modify  *
0007  *   it under the terms of the GNU General Public License as published by  *
0008  *   the Free Software Foundation; either version 2 of the License, or     *
0009  *   (at your option) any later version.                                   *
0010  *                                                                         *
0011  *   This program is distributed in the hope that it will be useful,       *
0012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0014  *   GNU General Public License for more details.                          *
0015  *                                                                         *
0016  *   You should have received a copy of the GNU General Public License     *
0017  *   along with this program; if not, see <https://www.gnu.org/licenses/>. *
0018  ***************************************************************************/
0019 
0020 #ifndef KBIBTEX_NETWORKING_ONLINESEARCHABSTRACT_H
0021 #define KBIBTEX_NETWORKING_ONLINESEARCHABSTRACT_H
0022 
0023 #include <QObject>
0024 #include <QMap>
0025 #include <QString>
0026 #include <QNetworkReply>
0027 #ifdef HAVE_QTWIDGETS
0028 #include <QWidget>
0029 #endif // HAVE_QTWIDGETS
0030 #include <QMetaType>
0031 #include <QIcon>
0032 #include <QUrl>
0033 
0034 #include <Entry>
0035 
0036 #ifdef HAVE_KF
0037 #include "kbibtexnetworking_export.h"
0038 #endif // HAVE_KF
0039 
0040 class QNetworkReply;
0041 class QNetworkRequest;
0042 class QListWidgetItem;
0043 
0044 /**
0045  * @author Thomas Fischer <fischer@unix-ag.uni-kl.de>
0046  */
0047 class KBIBTEXNETWORKING_EXPORT OnlineSearchAbstract : public QObject
0048 {
0049     Q_OBJECT
0050     Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
0051 
0052 public:
0053     explicit OnlineSearchAbstract(QObject *parent);
0054 
0055 #ifdef HAVE_QTWIDGETS
0056     class Form;
0057 #endif // HAVE_QTWIDGETS
0058 
0059     enum class QueryKey {FreeText = 1, Title = 2, Author = 3, Year = 4};
0060 
0061     static const int resultCancelled;
0062     static const int resultNoError;
0063     static const int resultUnspecifiedError;
0064     static const int resultAuthorizationRequired;
0065     static const int resultNetworkError;
0066     static const int resultInvalidArguments;
0067 
0068 #ifdef HAVE_QTWIDGETS
0069     virtual void startSearchFromForm();
0070 #endif // HAVE_QTWIDGETS
0071     virtual void startSearch(const QMap<QueryKey, QString> &query, int numResults) = 0;
0072     virtual QString label() const = 0;
0073     QString name();
0074 #ifdef HAVE_QTWIDGETS
0075     virtual QIcon icon(QListWidgetItem *listWidgetItem);
0076     virtual OnlineSearchAbstract::Form *customWidget(QWidget *parent);
0077 #endif // HAVE_QTWIDGETS
0078     virtual QUrl homepage() const = 0;
0079     virtual bool busy() const;
0080 
0081 public Q_SLOTS:
0082     void cancel();
0083 
0084 protected:
0085     QObject *m_parent;
0086     bool m_hasBeenCanceled;
0087 
0088     int numSteps, curStep;
0089 
0090     /**
0091      * Split a string along spaces, but keep text in quotation marks together
0092      */
0093     static QStringList splitRespectingQuotationMarks(const QString &text);
0094 
0095     /**
0096     * Will check for common problems with downloads via QNetworkReply. It will return true
0097     * if there is no problem and you may process this job result. If there is a problem,
0098     * this function will notify the user if necessary (KMessageBox), emit a
0099     * "stoppedSearch" signal (by invoking "stopSearch"), and return false.
0100     * @see handleErrors(KJob*)
0101     */
0102     bool handleErrors(QNetworkReply *reply);
0103 
0104     /**
0105     * Will check for common problems with downloads via QNetworkReply. It will return true
0106     * if there is no problem and you may process this job result. If there is a problem,
0107     * this function will notify the user if necessary (KMessageBox), emit a
0108     * "stoppedSearch" signal (by invoking "stopSearch"), and return false.
0109     * @see handleErrors(KJob*)
0110     * @param reply The reply the function will handle errors for
0111     * @param newUrl will be set to the new URL if reply contains a redirection, otherwise reply's original URL
0112     */
0113     bool handleErrors(QNetworkReply *reply, QUrl &newUrl, const QSet<const QNetworkReply::NetworkError> &ignoredErrors = QSet<const QNetworkReply::NetworkError>({QNetworkReply::NoError}));
0114 
0115     /**
0116      * Encode a text to be HTTP URL save, e.g. replace '=' by '%3D'.
0117      */
0118     static QString encodeURL(QString rawText);
0119 
0120     static QString decodeURL(QString rawText);
0121 
0122     static QString deHTMLify(const QString &input);
0123     static QByteArray htmlEntityToUnicode(const QByteArray &input);
0124 
0125     static QString monthToMacroKeyText(const QString &rawText);
0126 
0127     QMultiMap<QString, QString> formParameters(const QString &htmlText, int startPos) const;
0128 
0129     /**
0130      * Delay sending of stop signal by a few milliseconds.
0131      * Necessary if search stops (is cancelled) already in one
0132      * of the startSearch functions.
0133      */
0134     void delayedStoppedSearch(int returnCode);
0135 
0136     /**
0137      * Correct the most common problems encountered in fetched entries.
0138      * This function should be specialized in each descendant of this class.
0139      * @param entry Entry to sanitize
0140      */
0141     virtual void sanitizeEntry(QSharedPointer<Entry> entry);
0142 
0143     /**
0144      * Perform the following steps: (1) sanitize entry, (2) add name
0145      * of search engine that found the entry, (3) send it back to search
0146      * result list.
0147      * Returns true if a valid entry was passed to this function and all
0148      * steps could be performed.
0149      * @param entry Entry to publish
0150      * @return returns true if a valid entry was passed to this function and all steps could be performed.
0151      */
0152     bool publishEntry(QSharedPointer<Entry> entry);
0153 
0154     void stopSearch(int errorCode);
0155 
0156     /**
0157      * Allows an online search to notify about a change of its busy state,
0158      * i.e. that the public function @see busy may return a different value
0159      * than before. If the actual busy state has changed compared to previous
0160      * invocations of this function, the signal @see busyChanged will be
0161      * emitted.
0162      * This function here may be called both on changes from active to
0163      * inactive as well as vice versa.
0164      */
0165     void refreshBusyProperty();
0166 
0167 #ifdef HAVE_KF
0168     /**
0169      * @brief Send a visual notification to the desktop, similar to KNotification
0170      * @param text Message to be shown
0171      * @param title Title of the message, such as which OnlineSearch engine
0172      * @param timeout time after which the message will automatically disappear (in seconds)
0173      * @param icon Name of icon to be shown
0174      */
0175     void sendVisualNotification(const QString &text, const QString &title, int timeout = 10, const QString &icon = QStringLiteral("kbibtex"));
0176 #endif // HAVE_KF
0177 
0178 private:
0179     bool m_previousBusyState;
0180     QString m_name;
0181     static const char *httpUnsafeChars;
0182 #ifdef HAVE_QTWIDGETS
0183     QMap<QNetworkReply *, QListWidgetItem *> m_iconReplyToListWidgetItem;
0184 #endif // HAVE_QTWIDGETS
0185     int m_delayedStoppedSearchReturnCode;
0186 
0187     QString htmlAttribute(const QString &htmlCode, const int startPos, const QString &attribute) const;
0188     bool htmlAttributeIsSelected(const QString &htmlCode, const int startPos, const QString &attribute) const;
0189 
0190 Q_SIGNALS:
0191     void foundEntry(QSharedPointer<Entry>);
0192     void stoppedSearch(int);
0193     void progress(int, int);
0194     void busyChanged();
0195 };
0196 
0197 #ifdef HAVE_QTWIDGETS
0198 /**
0199  * @author Thomas Fischer <fischer@unix-ag.uni-kl.de>
0200  */
0201 class KBIBTEXNETWORKING_EXPORT OnlineSearchAbstract::Form : public QWidget
0202 {
0203     Q_OBJECT
0204 
0205 public:
0206     explicit Form(QWidget *parent);
0207     ~Form();
0208 
0209     virtual bool readyToStart() const = 0;
0210     virtual void copyFromEntry(const Entry &) = 0;
0211 
0212 Q_SIGNALS:
0213     void returnPressed();
0214 
0215 protected:
0216     class Private;
0217     Private *d;
0218 };
0219 #endif // HAVE_QTWIDGETS
0220 
0221 #endif // KBIBTEX_NETWORKING_ONLINESEARCHABSTRACT_H