File indexing completed on 2025-02-16 04:40:51
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 #include "onlinesearchdoi.h" 0021 0022 #ifdef HAVE_QTWIDGETS 0023 #include <QLabel> 0024 #include <QLineEdit> 0025 #include <QGridLayout> 0026 #endif // HAVE_QTWIDGETS 0027 #include <QNetworkRequest> 0028 #include <QNetworkReply> 0029 #include <QRegularExpression> 0030 0031 #ifdef HAVE_KF 0032 #include <KConfigGroup> 0033 #include <KLocalizedString> 0034 #endif // HAVE_KF 0035 0036 #include <KBibTeX> 0037 #include <FileImporterBibTeX> 0038 #include "internalnetworkaccessmanager.h" 0039 #include "onlinesearchabstract_p.h" 0040 #include "logging_networking.h" 0041 0042 #ifdef HAVE_QTWIDGETS 0043 class OnlineSearchDOI::Form : public OnlineSearchAbstract::Form 0044 { 0045 Q_OBJECT 0046 0047 private: 0048 QString configGroupName; 0049 0050 void loadState() { 0051 KConfigGroup configGroup(d->config, configGroupName); 0052 lineEditDoiNumber->setText(configGroup.readEntry(QStringLiteral("doiNumber"), QString())); 0053 } 0054 0055 public: 0056 QLineEdit *lineEditDoiNumber; 0057 0058 Form(QWidget *widget) 0059 : OnlineSearchAbstract::Form(widget), configGroupName(QStringLiteral("Search Engine DOI")) { 0060 QGridLayout *layout = new QGridLayout(this); 0061 layout->setContentsMargins(0, 0, 0, 0); 0062 0063 QLabel *label = new QLabel(i18n("DOI:"), this); 0064 layout->addWidget(label, 0, 0, 1, 1); 0065 lineEditDoiNumber = new QLineEdit(this); 0066 layout->addWidget(lineEditDoiNumber, 0, 1, 1, 1); 0067 lineEditDoiNumber->setClearButtonEnabled(true); 0068 connect(lineEditDoiNumber, &QLineEdit::returnPressed, this, &OnlineSearchDOI::Form::returnPressed); 0069 0070 layout->setRowStretch(1, 100); 0071 lineEditDoiNumber->setFocus(Qt::TabFocusReason); 0072 0073 loadState(); 0074 } 0075 0076 bool readyToStart() const override { 0077 return !lineEditDoiNumber->text().isEmpty(); 0078 } 0079 0080 void copyFromEntry(const Entry &entry) override { 0081 lineEditDoiNumber->setText(PlainTextValue::text(entry[Entry::ftDOI])); 0082 } 0083 0084 void saveState() { 0085 KConfigGroup configGroup(d->config, configGroupName); 0086 configGroup.writeEntry(QStringLiteral("doiNumber"), lineEditDoiNumber->text()); 0087 d->config->sync(); 0088 } 0089 }; 0090 #endif // HAVE_QTWIDGETS 0091 0092 0093 class OnlineSearchDOI::OnlineSearchDOIPrivate 0094 { 0095 public: 0096 #ifdef HAVE_QTWIDGETS 0097 OnlineSearchDOI::Form *form; 0098 #endif // HAVE_QTWIDGETS 0099 0100 OnlineSearchDOIPrivate(OnlineSearchDOI *parent) 0101 #ifdef HAVE_QTWIDGETS 0102 : form(nullptr) 0103 #endif // HAVE_QTWIDGETS 0104 { 0105 Q_UNUSED(parent) 0106 } 0107 0108 #ifdef HAVE_QTWIDGETS 0109 QUrl buildQueryUrl() { 0110 if (form == nullptr) { 0111 qCWarning(LOG_KBIBTEX_NETWORKING) << "Cannot build query url if no form is specified"; 0112 return QUrl(); 0113 } 0114 0115 return QUrl(QStringLiteral("https://dx.doi.org/") + form->lineEditDoiNumber->text()); 0116 } 0117 #endif // HAVE_QTWIDGETS 0118 0119 QUrl buildQueryUrl(const QMap<QueryKey, QString> &query, int numResults) { 0120 Q_UNUSED(numResults) 0121 0122 const QRegularExpressionMatch doiRegExpMatch = KBibTeX::doiRegExp.match(query[QueryKey::FreeText]); 0123 if (doiRegExpMatch.hasMatch()) { 0124 return QUrl(QStringLiteral("https://dx.doi.org/") + doiRegExpMatch.captured(QStringLiteral("doi"))); 0125 } 0126 0127 return QUrl(); 0128 } 0129 }; 0130 0131 0132 OnlineSearchDOI::OnlineSearchDOI(QObject *parent) 0133 : OnlineSearchAbstract(parent), d(new OnlineSearchDOIPrivate(this)) 0134 { 0135 // TODO 0136 } 0137 0138 OnlineSearchDOI::~OnlineSearchDOI() 0139 { 0140 delete d; 0141 } 0142 0143 #ifdef HAVE_QTWIDGETS 0144 void OnlineSearchDOI::startSearchFromForm() 0145 { 0146 m_hasBeenCanceled = false; 0147 Q_EMIT progress(curStep = 0, numSteps = 1); 0148 0149 const QUrl url = d->buildQueryUrl(); 0150 if (url.isValid()) { 0151 QNetworkRequest request(url); 0152 request.setRawHeader(QByteArray("Accept"), QByteArray("text/bibliography; style=bibtex")); 0153 QNetworkReply *reply = InternalNetworkAccessManager::instance().get(request); 0154 InternalNetworkAccessManager::instance().setNetworkReplyTimeout(reply); 0155 connect(reply, &QNetworkReply::finished, this, &OnlineSearchDOI::downloadDone); 0156 0157 d->form->saveState(); 0158 } else 0159 delayedStoppedSearch(resultNoError); 0160 0161 refreshBusyProperty(); 0162 } 0163 #endif // HAVE_QTWIDGETS 0164 0165 void OnlineSearchDOI::startSearch(const QMap<QueryKey, QString> &query, int numResults) 0166 { 0167 m_hasBeenCanceled = false; 0168 Q_EMIT progress(curStep = 0, numSteps = 1); 0169 0170 const QUrl url = d->buildQueryUrl(query, numResults); 0171 if (url.isValid()) { 0172 QNetworkRequest request(url); 0173 request.setRawHeader(QByteArray("Accept"), QByteArray("text/bibliography; style=bibtex")); 0174 QNetworkReply *reply = InternalNetworkAccessManager::instance().get(request); 0175 InternalNetworkAccessManager::instance().setNetworkReplyTimeout(reply); 0176 connect(reply, &QNetworkReply::finished, this, &OnlineSearchDOI::downloadDone); 0177 0178 refreshBusyProperty(); 0179 } else 0180 delayedStoppedSearch(resultNoError); 0181 } 0182 0183 QString OnlineSearchDOI::label() const 0184 { 0185 return i18n("DOI"); 0186 } 0187 0188 #ifdef HAVE_QTWIDGETS 0189 OnlineSearchAbstract::Form *OnlineSearchDOI::customWidget(QWidget *parent) 0190 { 0191 if (d->form == nullptr) 0192 d->form = new OnlineSearchDOI::Form(parent); 0193 return d->form; 0194 } 0195 #endif // HAVE_QTWIDGETS 0196 0197 QUrl OnlineSearchDOI::homepage() const 0198 { 0199 return QUrl(QStringLiteral("https://dx.doi.org/")); 0200 } 0201 0202 void OnlineSearchDOI::downloadDone() 0203 { 0204 Q_EMIT progress(++curStep, numSteps); 0205 QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); 0206 0207 QUrl redirUrl; 0208 if (handleErrors(reply, redirUrl)) { 0209 if (redirUrl.isValid()) { 0210 /// redirection to another url 0211 ++numSteps; 0212 0213 QNetworkRequest request(redirUrl); 0214 request.setRawHeader(QByteArray("Accept"), QByteArray("text/bibliography; style=bibtex")); 0215 QNetworkReply *newReply = InternalNetworkAccessManager::instance().get(request); 0216 InternalNetworkAccessManager::instance().setNetworkReplyTimeout(newReply); 0217 connect(newReply, &QNetworkReply::finished, this, &OnlineSearchDOI::downloadDone); 0218 } else { /// ensure proper treatment of UTF-8 characters 0219 const QString bibTeXcode = QString::fromUtf8(reply->readAll().constData()); 0220 0221 if (!bibTeXcode.isEmpty()) { 0222 FileImporterBibTeX importer(this); 0223 File *bibtexFile = importer.fromString(bibTeXcode); 0224 0225 bool hasEntries = false; 0226 if (bibtexFile != nullptr) { 0227 for (const auto &element : const_cast<const File &>(*bibtexFile)) { 0228 QSharedPointer<Entry> entry = element.dynamicCast<Entry>(); 0229 hasEntries |= publishEntry(entry); 0230 } 0231 0232 stopSearch(resultNoError); 0233 0234 delete bibtexFile; 0235 } else { 0236 qCWarning(LOG_KBIBTEX_NETWORKING) << "No valid BibTeX file results returned on request on" << InternalNetworkAccessManager::removeApiKey(reply->url()).toDisplayString(); 0237 stopSearch(resultUnspecifiedError); 0238 } 0239 } else { 0240 /// returned file is empty 0241 stopSearch(resultNoError); 0242 } 0243 } 0244 } 0245 0246 refreshBusyProperty(); 0247 } 0248 0249 #include "onlinesearchdoi.moc"