File indexing completed on 2024-05-19 05:05:55

0001 /***************************************************************************
0002  *   SPDX-License-Identifier: GPL-2.0-or-later
0003  *                                                                         *
0004  *   SPDX-FileCopyrightText: 2004-2022 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 "kbibtextest.h"
0021 
0022 #include <QProgressBar>
0023 #include <QTimer>
0024 #include <QLayout>
0025 #include <QMenu>
0026 #include <QIcon>
0027 #include <QPalette>
0028 #include <QPushButton>
0029 #include <QAction>
0030 #include <QListWidget>
0031 #include <QApplication>
0032 #include <QRandomGenerator>
0033 
0034 #include <KAboutData>
0035 
0036 #include <onlinesearch/OnlineSearchAcmPortal>
0037 #include <onlinesearch/OnlineSearchArXiv>
0038 #include <onlinesearch/OnlineSearchBibsonomy>
0039 #include <onlinesearch/OnlineSearchGoogleScholar>
0040 #include <onlinesearch/OnlineSearchCERNDS>
0041 #include <onlinesearch/OnlineSearchIEEEXplore>
0042 #include <onlinesearch/OnlineSearchIngentaConnect>
0043 #include <onlinesearch/OnlineSearchInspireHep>
0044 #include <onlinesearch/OnlineSearchIDEASRePEc>
0045 #ifdef HAVE_WEBENGINEWIDGETS
0046 #include <onlinesearch/OnlineSearchJStor>
0047 #endif // HAVE_WEBENGINEWIDGETS
0048 #include <onlinesearch/OnlineSearchMathSciNet>
0049 #include <onlinesearch/OnlineSearchMRLookup>
0050 #include <onlinesearch/OnlineSearchPubMed>
0051 #include <onlinesearch/OnlineSearchScienceDirect>
0052 #include <onlinesearch/OnlineSearchSpringerLink>
0053 #include <onlinesearch/OnlineSearchSOANASAADS>
0054 #include <onlinesearch/OnlineSearchBioRxiv>
0055 #include <onlinesearch/OnlineSearchSemanticScholar>
0056 #include <onlinesearch/OnlineSearchUnpaywall>
0057 #include <onlinesearch/OnlineSearchZbMath>
0058 
0059 static QColor blendColors(const QColor &color1, const QColor &color2, const qreal ratio)
0060 {
0061     const int r = static_cast<int>(color1.red() * (1 - ratio) + color2.red() * ratio);
0062     const int g = static_cast<int>(color1.green() * (1 - ratio) + color2.green() * ratio);
0063     const int b = static_cast<int>(color1.blue() * (1 - ratio) + color2.blue() * ratio);
0064 
0065     return QColor(r, g, b, 255);
0066 }
0067 
0068 class TestWidget : public QWidget
0069 {
0070     Q_OBJECT
0071 
0072 private:
0073     KBibTeXTest *m_parent;
0074     QPushButton *buttonStartTest;
0075     QProgressBar *progressBar;
0076     QAction *actionStartOnlineSearchTests;
0077 
0078 public:
0079     QListWidget *messageList;
0080 
0081     TestWidget(KBibTeXTest *parent)
0082             : QWidget(parent), m_parent(parent) {
0083         QGridLayout *layout = new QGridLayout(this);
0084 
0085         buttonStartTest = new QPushButton(QIcon::fromTheme(QStringLiteral("application-x-executable")), QStringLiteral("Start Tests"), this);
0086         layout->addWidget(buttonStartTest, 0, 0, 1, 1);
0087 
0088         progressBar = new QProgressBar(this);
0089         layout->addWidget(progressBar, 0, 1, 1, 3);
0090         progressBar->setVisible(false);
0091 
0092         messageList = new QListWidget(this);
0093         layout->addWidget(messageList, 1, 0, 4, 4);
0094 
0095         setupMenus();
0096     }
0097 
0098     void setProgress(int pos, int total) {
0099         if (pos < 0 || total < 0) {
0100             progressBar->setVisible(false);
0101             progressBar->setMaximum(1);
0102             progressBar->setValue(0);
0103         } else {
0104             progressBar->setVisible(true);
0105             progressBar->setMaximum(total);
0106             progressBar->setValue(pos);
0107         }
0108     }
0109 
0110     void setupMenus() {
0111         QMenu *menu = new QMenu(buttonStartTest);
0112         buttonStartTest->setMenu(menu);
0113 
0114         /// ** Online Search **
0115         actionStartOnlineSearchTests = new QAction(QStringLiteral("Online Search"), m_parent);
0116         connect(actionStartOnlineSearchTests, &QAction::triggered, m_parent, &KBibTeXTest::startOnlineSearchTests);
0117         menu->addAction(actionStartOnlineSearchTests);
0118     }
0119 
0120     void setBusy(bool isBusy) {
0121         buttonStartTest->setEnabled(!isBusy);
0122         actionStartOnlineSearchTests->setEnabled(!isBusy);
0123     }
0124 };
0125 
0126 KBibTeXTest::KBibTeXTest(QWidget *parent)
0127         : QDialog(parent), m_running(false), m_isBusy(false)
0128 {
0129     m_onlineSearchList << new OnlineSearchAcmPortal(this);
0130     m_onlineSearchList << new OnlineSearchArXiv(this);
0131     m_onlineSearchList << new OnlineSearchBibsonomy(this);
0132     m_onlineSearchList << new OnlineSearchCERNDS(this);
0133     m_onlineSearchList << new OnlineSearchGoogleScholar(this);
0134     m_onlineSearchList << new OnlineSearchIDEASRePEc(this);
0135     m_onlineSearchList << new OnlineSearchIEEEXplore(this);
0136     m_onlineSearchList << new OnlineSearchIngentaConnect(this);
0137     m_onlineSearchList << new OnlineSearchInspireHep(this);
0138 #ifdef HAVE_WEBENGINEWIDGETS
0139     m_onlineSearchList << new OnlineSearchJStor(this);
0140 #endif // HAVE_WEBENGINEWIDGETS
0141     m_onlineSearchList << new OnlineSearchMathSciNet(this);
0142     m_onlineSearchList << new OnlineSearchMRLookup(this);
0143     m_onlineSearchList << new OnlineSearchPubMed(this);
0144     m_onlineSearchList << new OnlineSearchScienceDirect(this);
0145     m_onlineSearchList << new OnlineSearchSOANASAADS(this);
0146     m_onlineSearchList << new OnlineSearchSpringerLink(this);
0147     m_onlineSearchList << new OnlineSearchBioRxiv(this);
0148     m_onlineSearchList << new OnlineSearchSemanticScholar(this);
0149     m_onlineSearchList << new OnlineSearchUnpaywall(this);
0150     m_onlineSearchList << new OnlineSearchZbMath(this);
0151     m_currentOnlineSearch = m_onlineSearchList.constBegin();
0152 
0153     setWindowTitle(QStringLiteral("KBibTeX Test Suite"));
0154 
0155     m_testWidget = new TestWidget(this);
0156 #if QT_VERSION >= 0x050b00
0157     const int fontSize = m_testWidget->fontMetrics().horizontalAdvance(QLatin1Char('a'));
0158 #else // QT_VERSION >= 0x050b00
0159     const int fontSize = m_testWidget->fontMetrics().width(QLatin1Char('a'));
0160 #endif // QT_VERSION >= 0x050b00
0161     m_testWidget->setMinimumSize(fontSize * 96, fontSize * 48);
0162     QBoxLayout *boxLayout = new QVBoxLayout(this);
0163     boxLayout->addWidget(m_testWidget);
0164 
0165     connect(this, &KBibTeXTest::rejected, this, &KBibTeXTest::aboutToQuit);
0166 
0167     addMessage(QString(QStringLiteral("Compiled for %1")).arg(KAboutData::applicationData().version()), MessageStatus::Info);
0168 }
0169 
0170 void KBibTeXTest::addMessage(const QString &message, const MessageStatus messageStatus)
0171 {
0172     static const QIcon iconINFO = QIcon::fromTheme(QStringLiteral("dialog-information"));
0173     static const QIcon iconOK = QIcon::fromTheme(QStringLiteral("dialog-ok-apply"));
0174     static const QIcon iconERROR = QIcon::fromTheme(QStringLiteral("dialog-cancel"));
0175     static const QIcon iconAUTH = QIcon::fromTheme(QStringLiteral("dialog-cancel")); // FIXME "dialog-cancel" should be overlay on "dialog-password"
0176     static const QIcon iconNETWORK = QIcon::fromTheme(QStringLiteral("dialog-cancel")); // FIXME "dialog-cancel" should be overlay on "network-wired"
0177     QIcon icon;
0178     switch (messageStatus) {
0179     case MessageStatus::Info: icon = iconINFO; break;
0180     case MessageStatus::Ok: icon = iconOK; break;
0181     case MessageStatus::Error: icon = iconERROR; break;
0182     case MessageStatus::Auth: icon = iconAUTH; break;
0183     case MessageStatus::Network: icon = iconNETWORK; break;
0184     }
0185 
0186     QListWidgetItem *item = icon.isNull() ? new QListWidgetItem(message) : new QListWidgetItem(icon, message);
0187     item->setToolTip(item->text());
0188     const QColor originalBgColor = QGuiApplication::palette().color(QPalette::Base);
0189     switch (messageStatus) {
0190     case MessageStatus::Info: break; ///< nothing to do
0191     case MessageStatus::Ok: item->setBackground(QBrush(blendColors(originalBgColor, Qt::green, .1))); break;
0192     case MessageStatus::Error: item->setBackground(QBrush(blendColors(originalBgColor, Qt::red, .1))); break;
0193     case MessageStatus::Auth: item->setBackground(QBrush(blendColors(originalBgColor, Qt::yellow, .1))); break;
0194     case MessageStatus::Network: item->setBackground(QBrush(blendColors(originalBgColor, Qt::yellow, .1))); break;
0195     }
0196 
0197     m_testWidget->messageList->addItem(item);
0198     m_testWidget->messageList->scrollToBottom();
0199     qApp->processEvents();
0200 }
0201 
0202 void KBibTeXTest::setBusy(bool isBusy)
0203 {
0204     m_testWidget->setBusy(isBusy);
0205     if (isBusy && !m_isBusy) {
0206         /// changing to busy state
0207         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0208     } else if (!isBusy && m_isBusy) {
0209         /// changing to idle state
0210         QApplication::restoreOverrideCursor();
0211     }
0212     m_isBusy = isBusy;
0213 }
0214 
0215 void KBibTeXTest::aboutToQuit()
0216 {
0217     m_running = false;
0218     QTimer::singleShot(500, qApp, &QApplication::quit);
0219 }
0220 
0221 void KBibTeXTest::startOnlineSearchTests()
0222 {
0223     m_running = true;
0224     setBusy(true);
0225     m_testWidget->messageList->clear();
0226     qApp->processEvents();
0227     processNextSearch();
0228 }
0229 
0230 void KBibTeXTest::onlineSearchStoppedSearch(int searchResult)
0231 {
0232     if (m_currentOnlineSearch != m_onlineSearchList.constEnd())
0233         disconnect(*m_currentOnlineSearch, &OnlineSearchAbstract::stoppedSearch, this, &KBibTeXTest::onlineSearchStoppedSearch);
0234     if (searchResult == OnlineSearchAbstract::resultNoError) {
0235         if (m_currentOnlineSearchNumFoundEntries == 0)
0236             addMessage(QString(QStringLiteral("Got no error message searching '%1', but found NO entries")).arg((*m_currentOnlineSearch)->label()), MessageStatus::Error);
0237         else
0238             addMessage(QString(QStringLiteral("No error searching '%1', found %2 entries")).arg((*m_currentOnlineSearch)->label()).arg(m_currentOnlineSearchNumFoundEntries), MessageStatus::Ok);
0239     } else if (searchResult == OnlineSearchAbstract::resultAuthorizationRequired) {
0240         addMessage(QString(QStringLiteral("Authorization required for '%1'")).arg((*m_currentOnlineSearch)->label()), MessageStatus::Auth);
0241     } else if (searchResult == OnlineSearchAbstract::resultNetworkError) {
0242         addMessage(QString(QStringLiteral("Network error for '%1'")).arg((*m_currentOnlineSearch)->label()), MessageStatus::Network);
0243     } else {
0244         addMessage(QString(QStringLiteral("Error searching '%1'")).arg((*m_currentOnlineSearch)->label()), MessageStatus::Error);
0245     }
0246     m_currentOnlineSearch++;
0247 
0248     progress(-1, -1);
0249     processNextSearch();
0250 }
0251 
0252 void KBibTeXTest::progress(int pos, int total)
0253 {
0254     m_testWidget->setProgress(pos, total);
0255 }
0256 
0257 void KBibTeXTest::processNextSearch()
0258 {
0259     if (m_running && m_currentOnlineSearch != m_onlineSearchList.constEnd()) {
0260         setBusy(true);
0261         m_currentOnlineSearchNumFoundEntries = 0;
0262         addMessage(QString(QStringLiteral("Searching '%1'")).arg((*m_currentOnlineSearch)->label()), MessageStatus::Info);
0263 
0264         QMap<OnlineSearchAbstract::QueryKey, QString> query;
0265         if (qobject_cast<OnlineSearchSemanticScholar *>(*m_currentOnlineSearch) != nullptr)
0266             /// Semantic Scholar cannot search for last names, but for DOIs or arXiv IDs instead
0267             query.insert(OnlineSearchAbstract::QueryKey::FreeText, QStringLiteral("10.1002/smj.863"));
0268         else if (qobject_cast<OnlineSearchUnpaywall *>(*m_currentOnlineSearch) != nullptr)
0269             /// Unpaywall cannot search for last names, but for DOIs of open access publications
0270             query.insert(OnlineSearchAbstract::QueryKey::FreeText, QStringLiteral("10.1002/andp.201600209"));
0271         else {
0272             static const QStringList lastNames{QStringLiteral("Smith"), QStringLiteral("Jones"), QStringLiteral("Andersson"), QStringLiteral("Ivanova"), QStringLiteral("Wang"), QStringLiteral("Gonzalez"), QStringLiteral("Garcia"), QStringLiteral("Lopez"), QStringLiteral("Ahmed"), QStringLiteral("Nkosi"), QStringLiteral("Kim"), QStringLiteral("Chen"), QStringLiteral("Devi"), QStringLiteral("Khan"), QStringLiteral("Johansson"), QStringLiteral("Sharipov"), QStringLiteral("Korhonen"), QStringLiteral("Muller"), QStringLiteral("Murphy"), QStringLiteral("Papadopoulos"), QStringLiteral("Rossi"), QStringLiteral("Hernandez"), QStringLiteral("Williams"), QStringLiteral("Zhang"), QStringLiteral("Singh"), QStringLiteral("Kumar")};
0273             query.insert(OnlineSearchAbstract::QueryKey::Author, lastNames[QRandomGenerator::global()->bounded(lastNames.count())]);
0274         }
0275         connect(*m_currentOnlineSearch, &OnlineSearchAbstract::stoppedSearch, this, &KBibTeXTest::onlineSearchStoppedSearch);
0276         connect(*m_currentOnlineSearch, &OnlineSearchAbstract::foundEntry, this, [this]() {
0277             ++m_currentOnlineSearchNumFoundEntries;
0278         });
0279         connect(*m_currentOnlineSearch, &OnlineSearchAbstract::progress, this, &KBibTeXTest::progress);
0280         (*m_currentOnlineSearch)->startSearch(query, 3);
0281     } else {
0282         addMessage(QStringLiteral("Done testing"), MessageStatus::Info);
0283         setBusy(false);
0284         m_running = false;
0285         QTimer::singleShot(500, this, [this]() {
0286             m_testWidget->setProgress(-1, -1);
0287         });
0288     }
0289 }
0290 
0291 #include "kbibtextest.moc"