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"