diff --git a/ChangeLog b/ChangeLog index 6c1dbe08..5f67b632 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,192 +1,193 @@ ChangeLog Diff 0.7 to 0.8 Porting from Qt4 to Qt5, from KDE4 (kdelibs) to KDE Frameworks 5, as well as updating various dependencies in the process (e.g. Qt5-based poppler) - Removing old scripts and configuration files - Updating/adding translations - Removing dependency on Qxt as well as sources in src/3rdparty/libqxt - Refactoring various files' location - Various fundamental classes have only optional dependency on KDE Frameworks 5 (default for KDE-based builds, but allows using those classes in Qt5-only setups) - Various modernizations of C++ code towards C++11, including deprecation of SIGNAL/SLOT - Moving bibliography files that previously resided in testset/ into their own Git repository (kbibtex-testset) +- Removing ISBNdb as it is no longer a free service - KDE Bug 393032: Updating list of journal abbreviations - KDE Bug 393224: LyX pipe detection (issues with Kile 3 fixed) - KDE Bug 391198: Preview image/vnd.djvu+multipage files - KDE Bug 389306: Removal of libQxt - KDE Bug 387638: Locating correct QtOAuth library fixed - KDE Bug 388688: Screenshots for appdata updated - KDE Bug 386226: Character '~' not recognized in localfile entry - KDE Bug 352517: Invalid report, but more verbose output will be logged - KDE Bug 384741: Wrong ID Reported in Duplicate Dialog - KDE Bug 381119: Do not refer to defunct Gna! anymore (note: Gna! infrastructure shut down before all materials (postings) could be retrieved) - KDE Bug 378497: Fixing crash when closing settings dialog - KDE Bug 368732: More options for ID generation: volume number, first page - Numerous small fixes and changes, run 'git diff v0.6.2..v0.7' for details Contributing authors include: Allen Winter, Andreas Sturmlechner, Andrius Štikonas, Antonio Rojas, Bastien Roucaries, Burkhard Lück, Christoph Feck, Frederik Schwarzer, Joao Carreira, Juergen Spitzmueller, Luigi Toscano, Pino Toscano, Raymond Wooninck, Thomas Fischer, and Yuri Chornoivan Diff 0.6.2 to 0.7 - Dependency on Qt WebKit can be disabled at compile time - New dependency on ICU, used to transliterate text to plain ASCII - Generally improved code quality as detected by code checkers such as Clazy or Coverity - New online search: bioRxiv - Various minor fixes - Search in Zotero is rate limited to avoid overloading server - Using KWallet to store Zotero credentials - Adding basic DBUS support to, for example, open files or paste text - Numerous small fixes and changes, run 'git diff v0.6.2..v0.7' for details Diff 0.6.1 to 0.6.2 - KDE Bug 377401: https://bugs.kde.org/show_bug.cgi?id=377401 KBibTeX fails to load zotero bibliography - Numerous small fixes and changes, run 'git diff v0.6.1..v0.6.2' for details Diff 0.6 to 0.6.1 - KDE Bug 351455: https://bugs.kde.org/show_bug.cgi?id=351455 Removing soversion from KBibTeX Part - KDE Bug 353898: https://bugs.kde.org/show_bug.cgi?id=353898 Fixing build issues on ARM architecture - KDE Bug 354785: https://bugs.kde.org/show_bug.cgi?id=354785 Using QTextDocument/QTextEdit instead of WebKit/WebEngine: more lightweight and supported on all platforms - KDE Bug 371515: Speeding up selection of elements in bibliography lists - KDE Bug 371593: Sorting field and entry types in comboboxes alphabetically - Fixing crash when open file got modified externally - Correcting choke on PubMed searches to 10 seconds - Fixing search issues for ACM, Google Scholar, JSTOR, and ScienceDirect - Setting foreground color of colored rows to either black or white for better readability - Disabling OCLC WorldCat (request for support denied by this organization) - Generally improved code quality as detected by code checkers such as Clazy or Coverity - Fixing handling of URLs and their protocols for local files - Fixing setting default id suggestion - Adding 'Keywords' field to .desktop file - Removing file that was licensed under CC BY-NC, but never got installed - Improved Unicode support - Refactoring writing of bibliography files, both to local and to remote places, including writing to symbolic links - Better handling quotation marks and protective curly brackets around titles - Updating translations - Numerous small fixes and changes, run 'git diff v0.6..v0.6.1' for details Diff 0.5.2 to 0.6 - Allowing "unity builds", i.e. merging source code files for faster compilation - Enabling BibUtils support to import/export exotic file formats - Entries can be rated with stars - Adding entry type for Master's thesis - Setting entry identifiers automatically if configured by user - Files (e.g. PDF) can be 'associated' with an entry, including moving/copying/renaming the file to match the bibliography's location and the entry's id - In the element editor, unused tabs are no longer just disabled, but hidden instead - Automatic column-resizing improved - Bibliographies can be imported from Zotero - Adding user interface translations to various languages - New online search engines: CERN Document Server, DOI, IDEAS (RePEc), MR Lookup; fixes to existing search engines - New dockets for file settings, file statistics, and browsing Zotero bibliographies - Value selected in the value list can be added or removed from selected entries - Enhancing the Id Suggestion system - Various fixes as suggested by KDE's code analysis tool Krazy - Numerous small fixes and changes, run 'git diff v0.5.2..v0.6' for details Diff 0.5.1 to 0.5.2 - Migrating to KDE's Git infrastructure - Gna Bug 22418: http://gna.org/bugs/?22418: Relative paths fail to get resolved - KDE Bug 339086: https://bugs.kde.org/show_bug.cgi?id=339086 Fixing ScienceDirect search - KDE Bug 343855: https://bugs.kde.org/show_bug.cgi?id=343855 'Copy Reference' setting in GUI correctly stored - KDE Bug 344495: https://bugs.kde.org/show_bug.cgi?id=344495 Uninitialized variable causes crash - KDE Bug 344497: https://bugs.kde.org/show_bug.cgi?id=344497 Message next to Import button in Search Results - Various minor changes and backports from 0.6.x Run git log v0.5.1..v0.5.2 for a more detailed change log Diff 0.5 to 0.5.1 - KDE Bug 329724: https://bugs.kde.org/show_bug.cgi?id=329724 Fixing sorting issue in main list - KDE Bug 329750: https://bugs.kde.org/show_bug.cgi?id=329750 KBibTeX will set itself as default bibliography editor in KDE - KDE Bug 330700: https://bugs.kde.org/show_bug.cgi?id=330700 Crash when finding PDFs - KDE Bug 332043: https://bugs.kde.org/show_bug.cgi?id=332043 Fixing crash in id suggestion editor - Gentoo Bug 498932: https://bugs.gentoo.org/show_bug.cgi?id=498932 Fixing compilation issue - Gna Bug 21581: http://gna.org/bugs/?21581 Restoring session state (1) - Gna Bug 21545: http://gna.org/bugs/?21545 Restoring session state (2) - Debian Bug 689310: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=689310 Correctly parsing command line arguments if relative paths are given - Various minor clean-ups and improvements Run git log v0.5..v0.5.1 for a more detailed change log Diff 0.4.1 to 0.5 - Initial support for BibLaTeX - Id Suggestion editor like available in old KDE3 version - "Find PDF" function to locate PDF files through web search engines - New online database searches: MathSciNet, Ingenta Connect, Inspire Hep, SAO/NASA ADS, ISBN DB, JStor - Improved memory management - Numerous bug fixes and improvements Diff 0.4 to 0.4.1 - Web searches: Improved support for user-triggered cancelling - SpringerLink search: GUI changes, using api.springer.com for search - PubMed: Limiting search requests per time - ACM Portal: Retrieving "month", fixing HTTP header - JSTOR: fixing HTTP header - Google Scholar: Updates to compensate for changes in Google's web layout; handling redirects - Science Direct: Updates to compensate for changes in Science Direct's web layout; handling redirects - arXiv: Trying to extract bibliographic information from journal strings - BibSonomy: Specifying number of hits to find - Minor changes in IEEExplore search; non-functional due to Qt bug? - Web search uses KDE's proxy settings - Using KDE subsystem to open external files (e.g. PDF files) - Adding preview for images (in addition to PDF or HTML files); handling references to arXiv - Squeezing long file names in user interface - Handling quit actions more gracefully - Improving interface to external programs such as pdflatex - More robust XSL transformations - BibTeX import: guessing encoding information left by JabRef, more informative debug output, improved handling of multiple fields with same name - Reference preview: supporting dark color schemes - Fixing sorting in value list - Fixes in setting color tag to entries - Fixes in name formatting - Keeping user interface read-only for read-only use cases - Numerous bug fixes, closing memory leaks, speed improvements - Fixes in duplicate merging code: remove fields user doesn't want to keep Diff 0.3 to 0.4 - Support for Windows (compiles out of the box) - Configuration file system refactored - Adding more online search engines: SpringerLink, PubMed, ACM Digital Library, JSTOR, IEEE Xplorer, Science Direct - Improving all other online search engines: Google Scholar, arXiv, BibSonomy - "List of Values" refactored, allows to search for items - Introducing preferences dialog to manage various settings - Improved support for drag'n'drop throughout the program - Improving tagging elements with color - Introducing global keyword list to select from - Editing widgets get "history" to select from - Widget for cross references allows to select from existing elements - Introducing duplicate finding and merging code and user interface - Improvements in usability of filter line edit - File view can resize and order columns, settings get stored - Improving file importer and exporter filters - BibTeX references can be sent to LyX via a pipe - Numerous bug fixes diff --git a/src/networking/CMakeLists.txt b/src/networking/CMakeLists.txt index 54fbf82f..be17498d 100644 --- a/src/networking/CMakeLists.txt +++ b/src/networking/CMakeLists.txt @@ -1,153 +1,153 @@ # Network library set( kbibtexnetworking_LIB_SRCS onlinesearch/onlinesearchabstract.cpp onlinesearch/onlinesearchbibsonomy.cpp onlinesearch/onlinesearcharxiv.cpp onlinesearch/onlinesearchsciencedirect.cpp onlinesearch/onlinesearchgooglescholar.cpp onlinesearch/onlinesearchieeexplore.cpp onlinesearch/onlinesearchpubmed.cpp onlinesearch/onlinesearchacmportal.cpp onlinesearch/onlinesearchspringerlink.cpp onlinesearch/onlinesearchjstor.cpp onlinesearch/onlinesearchmathscinet.cpp onlinesearch/onlinesearchmrlookup.cpp onlinesearch/onlinesearchinspirehep.cpp onlinesearch/onlinesearchcernds.cpp onlinesearch/onlinesearchingentaconnect.cpp onlinesearch/onlinesearchsimplebibtexdownload.cpp onlinesearch/onlinesearchgeneral.cpp onlinesearch/onlinesearchsoanasaads.cpp - onlinesearch/onlinesearchisbndb.cpp + # onlinesearch/onlinesearchisbndb.cpp # disabled as provider switched to a paid model on 2017-12-26 onlinesearch/onlinesearchideasrepec.cpp onlinesearch/onlinesearchdoi.cpp onlinesearch/onlinesearchbiorxiv.cpp associatedfiles.cpp findpdf.cpp internalnetworkaccessmanager.cpp ${CMAKE_SOURCE_DIR}/src/global/kbibtex.cpp logging_networking.cpp ) if(BUILD_ZOTERO) list( APPEND kbibtexnetworking_LIB_SRCS zotero/api.cpp zotero/collectionmodel.cpp zotero/collection.cpp zotero/items.cpp zotero/groups.cpp zotero/oauthwizard.cpp zotero/tags.cpp zotero/tagmodel.cpp ) endif(BUILD_ZOTERO) set( kbibtexnetworking_HDRS onlinesearch/onlinesearchgeneral.h onlinesearch/onlinesearchsciencedirect.h onlinesearch/onlinesearchabstract.h onlinesearch/onlinesearchacmportal.h onlinesearch/onlinesearchbibsonomy.h onlinesearch/onlinesearchgooglescholar.h onlinesearch/onlinesearchspringerlink.h onlinesearch/onlinesearchjstor.h onlinesearch/onlinesearchieeexplore.h onlinesearch/onlinesearcharxiv.h onlinesearch/onlinesearchpubmed.h onlinesearch/onlinesearchingentaconnect.h onlinesearch/onlinesearchsimplebibtexdownload.h onlinesearch/onlinesearchsoanasaads.h onlinesearch/onlinesearchmathscinet.h onlinesearch/onlinesearchmrlookup.h onlinesearch/onlinesearchinspirehep.h onlinesearch/onlinesearchcernds.h onlinesearch/onlinesearchisbndb.h onlinesearch/onlinesearchideasrepec.h onlinesearch/onlinesearchdoi.h onlinesearch/onlinesearchbiorxiv.h zotero/collectionmodel.h zotero/collection.h zotero/groups.h zotero/tags.h zotero/tagmodel.h zotero/items.h zotero/api.h zotero/oauthwizard.h associatedfiles.h findpdf.h internalnetworkaccessmanager.h ) if(UNITY_BUILD) enable_unity_build(kbibtexnetworking kbibtexnetworking_LIB_SRCS) endif(UNITY_BUILD) include_directories( ${CMAKE_BINARY_DIR}/src/config ${CMAKE_SOURCE_DIR}/src/config ${CMAKE_BINARY_DIR}/src/data ${CMAKE_SOURCE_DIR}/src/data ${CMAKE_BINARY_DIR}/src/io ${CMAKE_SOURCE_DIR}/src/io ${CMAKE_SOURCE_DIR}/src/networking/onlinesearch ${CMAKE_SOURCE_DIR}/src/networking ${CMAKE_SOURCE_DIR}/src/global ) add_library( kbibtexnetworking SHARED ${kbibtexnetworking_LIB_SRCS} ) target_link_libraries( kbibtexnetworking Qt5::Core Qt5::Widgets Qt5::Network KF5::I18n KF5::XmlGui KF5::Completion KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets KF5::KIONTLM KF5::Wallet kbibtexconfig kbibtexdata kbibtexio Poppler::Qt5 ) if(BUILD_ZOTERO) include_directories( ${QTOAUTH_INCLUDE_DIR} ) target_link_libraries( kbibtexnetworking qca-qt5 ${QTOAUTH_LIBRARY} ) endif(BUILD_ZOTERO) set_target_properties( kbibtexnetworking PROPERTIES EXPORT_NAME "kbibtexnetworking" VERSION ${KBIBTEX_RELEASE_VERSION} SOVERSION ${KBIBTEX_SOVERSION} ) install( TARGETS kbibtexnetworking ${INSTALL_TARGETS_DEFAULT_ARGS} ) generate_export_header( kbibtexnetworking ) diff --git a/src/program/docklets/searchform.cpp b/src/program/docklets/searchform.cpp index 9bf76cb4..8bbccb54 100644 --- a/src/program/docklets/searchform.cpp +++ b/src/program/docklets/searchform.cpp @@ -1,506 +1,506 @@ /*************************************************************************** * Copyright (C) 2004-2017 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "searchform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "element.h" #include "file.h" #include "comment.h" #include "fileexporterbibtex.h" #include "onlinesearchabstract.h" #include "onlinesearchgeneral.h" #include "onlinesearchbibsonomy.h" #include "onlinesearchgooglescholar.h" #include "onlinesearchpubmed.h" #include "onlinesearchieeexplore.h" #include "onlinesearchacmportal.h" #include "onlinesearchsciencedirect.h" #include "onlinesearchspringerlink.h" #include "onlinesearcharxiv.h" #include "onlinesearchjstor.h" #include "onlinesearchmathscinet.h" #include "onlinesearchmrlookup.h" #include "onlinesearchinspirehep.h" #include "onlinesearchcernds.h" #include "onlinesearchingentaconnect.h" #include "onlinesearchsoanasaads.h" #include "onlinesearchisbndb.h" #include "onlinesearchideasrepec.h" #include "onlinesearchdoi.h" #include "onlinesearchbiorxiv.h" #include "openfileinfo.h" #include "fileview.h" #include "models/filemodel.h" #include "searchresults.h" #include "logging_program.h" class SearchForm::SearchFormPrivate { private: SearchForm *p; QStackedWidget *queryTermsStack; QWidget *listContainer; QListWidget *enginesList; QLabel *whichEnginesLabel; QAction *actionOpenHomepage; public: KSharedConfigPtr config; const QString configGroupName; SearchResults *sr; QMap itemToOnlineSearch; QSet runningSearches; QPushButton *searchButton; QPushButton *useEntryButton; OnlineSearchQueryFormGeneral *generalQueryTermsForm; QTabWidget *tabWidget; QSharedPointer currentEntry; QProgressBar *progressBar; QMap progressMap; QMap formToScrollArea; enum SearchFormPrivateRole { /// Homepage of a search engine HomepageRole = Qt::UserRole + 5, /// Special widget for a search engine WidgetRole = Qt::UserRole + 6, /// Name of a search engine NameRole = Qt::UserRole + 7 }; SearchFormPrivate(SearchResults *searchResults, SearchForm *parent) : p(parent), whichEnginesLabel(nullptr), config(KSharedConfig::openConfig(QStringLiteral("kbibtexrc"))), configGroupName(QStringLiteral("Search Engines Docklet")), sr(searchResults), searchButton(nullptr), useEntryButton(nullptr), currentEntry(nullptr) { createGUI(); } OnlineSearchQueryFormAbstract *currentQueryForm() { QScrollArea *area = qobject_cast(queryTermsStack->currentWidget()); return formToScrollArea.key(area, nullptr); } QScrollArea *wrapInScrollArea(OnlineSearchQueryFormAbstract *form, QWidget *parent) { QScrollArea *scrollArea = new QScrollArea(parent); form->setParent(scrollArea); scrollArea->setWidget(form); scrollArea->setWidgetResizable(true); scrollArea->setFrameShape(QFrame::NoFrame); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); formToScrollArea.insert(form, scrollArea); return scrollArea; } QWidget *createQueryTermsStack(QWidget *parent) { QWidget *container = new QWidget(parent); QVBoxLayout *vLayout = new QVBoxLayout(container); whichEnginesLabel = new QLabel(container); whichEnginesLabel->setWordWrap(true); vLayout->addWidget(whichEnginesLabel); vLayout->setStretchFactor(whichEnginesLabel, 0); connect(whichEnginesLabel, &QLabel::linkActivated, p, &SearchForm::switchToEngines); vLayout->addSpacing(8); queryTermsStack = new QStackedWidget(container); vLayout->addWidget(queryTermsStack); vLayout->setStretchFactor(queryTermsStack, 5); QScrollArea *scrollArea = wrapInScrollArea(createGeneralQueryTermsForm(queryTermsStack), queryTermsStack); queryTermsStack->addWidget(scrollArea); return container; } OnlineSearchQueryFormAbstract *createGeneralQueryTermsForm(QWidget *parent = nullptr) { generalQueryTermsForm = new OnlineSearchQueryFormGeneral(parent); return generalQueryTermsForm; } QWidget *createEnginesGUI(QWidget *parent) { listContainer = new QWidget(parent); QGridLayout *layout = new QGridLayout(listContainer); layout->setRowStretch(0, 1); layout->setRowStretch(1, 0); enginesList = new QListWidget(listContainer); layout->addWidget(enginesList, 0, 0, 1, 1); connect(enginesList, &QListWidget::itemChanged, p, &SearchForm::itemCheckChanged); connect(enginesList, &QListWidget::currentItemChanged, p, &SearchForm::enginesListCurrentChanged); enginesList->setSelectionMode(QAbstractItemView::NoSelection); actionOpenHomepage = new QAction(QIcon::fromTheme(QStringLiteral("internet-web-browser")), i18n("Go to Homepage"), p); connect(actionOpenHomepage, &QAction::triggered, p, &SearchForm::openHomepage); enginesList->addAction(actionOpenHomepage); enginesList->setContextMenuPolicy(Qt::ActionsContextMenu); return listContainer; } void createGUI() { QGridLayout *layout = new QGridLayout(p); layout->setMargin(0); layout->setRowStretch(0, 1); layout->setRowStretch(1, 0); layout->setColumnStretch(0, 0); layout->setColumnStretch(1, 1); layout->setColumnStretch(2, 0); tabWidget = new QTabWidget(p); tabWidget->setDocumentMode(true); layout->addWidget(tabWidget, 0, 0, 1, 3); QWidget *widget = createQueryTermsStack(tabWidget); tabWidget->addTab(widget, QIcon::fromTheme(QStringLiteral("edit-rename")), i18n("Query Terms")); QWidget *listContainer = createEnginesGUI(tabWidget); tabWidget->addTab(listContainer, QIcon::fromTheme(QStringLiteral("applications-engineering")), i18n("Engines")); connect(tabWidget, &QTabWidget::currentChanged, p, &SearchForm::tabSwitched); useEntryButton = new QPushButton(QIcon::fromTheme(QStringLiteral("go-up")), i18n("Use Entry"), p); layout->addWidget(useEntryButton, 1, 0, 1, 1); useEntryButton->setEnabled(false); connect(useEntryButton, &QPushButton::clicked, p, &SearchForm::copyFromEntry); progressBar = new QProgressBar(p); layout->addWidget(progressBar, 1, 1, 1, 1); progressBar->setMaximum(1000); progressBar->hide(); searchButton = new QPushButton(QIcon::fromTheme(QStringLiteral("edit-find")), i18n("Search"), p); layout->addWidget(searchButton, 1, 2, 1, 1); connect(generalQueryTermsForm, &OnlineSearchQueryFormGeneral::returnPressed, searchButton, &QPushButton::click); updateGUI(); } void loadEngines() { enginesList->clear(); addEngine(new OnlineSearchAcmPortal(p)); addEngine(new OnlineSearchArXiv(p)); addEngine(new OnlineSearchBioRxiv(p)); addEngine(new OnlineSearchBibsonomy(p)); addEngine(new OnlineSearchGoogleScholar(p)); addEngine(new OnlineSearchIEEEXplore(p)); addEngine(new OnlineSearchIngentaConnect(p)); addEngine(new OnlineSearchJStor(p)); addEngine(new OnlineSearchMathSciNet(p)); addEngine(new OnlineSearchMRLookup(p)); addEngine(new OnlineSearchInspireHep(p)); addEngine(new OnlineSearchCERNDS(p)); addEngine(new OnlineSearchPubMed(p)); addEngine(new OnlineSearchScienceDirect(p)); addEngine(new OnlineSearchSpringerLink(p)); addEngine(new OnlineSearchSOANASAADS(p)); - addEngine(new OnlineSearchIsbnDB(p)); + /// addEngine(new OnlineSearchIsbnDB(p)); /// disabled as provider switched to a paid model on 2017-12-26 addEngine(new OnlineSearchIDEASRePEc(p)); addEngine(new OnlineSearchDOI(p)); p->itemCheckChanged(nullptr); updateGUI(); } void addEngine(OnlineSearchAbstract *engine) { KConfigGroup configGroup(config, configGroupName); QListWidgetItem *item = new QListWidgetItem(engine->label(), enginesList); item->setCheckState(configGroup.readEntry(engine->name(), false) ? Qt::Checked : Qt::Unchecked); item->setIcon(engine->icon(item)); item->setToolTip(engine->label()); item->setData(HomepageRole, engine->homepage()); item->setData(NameRole, engine->name()); OnlineSearchQueryFormAbstract *widget = engine->customWidget(queryTermsStack); item->setData(WidgetRole, QVariant::fromValue(widget)); if (widget != nullptr) { connect(widget, &OnlineSearchQueryFormAbstract::returnPressed, searchButton, &QPushButton::click); QScrollArea *scrollArea = wrapInScrollArea(widget, queryTermsStack); queryTermsStack->addWidget(scrollArea); } itemToOnlineSearch.insert(item, engine); connect(engine, &OnlineSearchAbstract::foundEntry, p, &SearchForm::foundEntry); connect(engine, &OnlineSearchAbstract::stoppedSearch, p, &SearchForm::stoppedSearch); connect(engine, &OnlineSearchAbstract::progress, p, &SearchForm::updateProgress); } void switchToSearch() { for (QMap::ConstIterator it = itemToOnlineSearch.constBegin(); it != itemToOnlineSearch.constEnd(); ++it) disconnect(searchButton, &QPushButton::clicked, it.value(), &OnlineSearchAbstract::cancel); connect(searchButton, &QPushButton::clicked, p, &SearchForm::startSearch); searchButton->setText(i18n("Search")); searchButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); for (int i = tabWidget->count() - 1; i >= 0; --i) tabWidget->widget(i)->setEnabled(true); tabWidget->unsetCursor(); } void switchToCancel() { disconnect(searchButton, &QPushButton::clicked, p, &SearchForm::startSearch); for (QMap::ConstIterator it = itemToOnlineSearch.constBegin(); it != itemToOnlineSearch.constEnd(); ++it) connect(searchButton, &QPushButton::clicked, it.value(), &OnlineSearchAbstract::cancel); searchButton->setText(i18n("Stop")); searchButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop"))); for (int i = tabWidget->count() - 1; i >= 0; --i) tabWidget->widget(i)->setEnabled(false); tabWidget->setCursor(Qt::WaitCursor); } void switchToEngines() { tabWidget->setCurrentWidget(listContainer); } void updateGUI() { if (whichEnginesLabel == nullptr) return; QStringList checkedEngines; QListWidgetItem *cursor = nullptr; for (QMap::ConstIterator it = itemToOnlineSearch.constBegin(); it != itemToOnlineSearch.constEnd(); ++it) if (it.key()->checkState() == Qt::Checked) { checkedEngines << it.key()->text(); cursor = it.key(); } switch (checkedEngines.size()) { case 0: whichEnginesLabel->setText(i18n("No search engine selected (change).")); break; case 1: whichEnginesLabel->setText(i18n("Search engine %1 is selected (change).", checkedEngines.first())); break; case 2: whichEnginesLabel->setText(i18n("Search engines %1 and %2 are selected (change).", checkedEngines.first(), checkedEngines.at(1))); break; case 3: whichEnginesLabel->setText(i18n("Search engines %1, %2, and %3 are selected (change).", checkedEngines.first(), checkedEngines.at(1), checkedEngines.at(2))); break; default: whichEnginesLabel->setText(i18n("Search engines %1, %2, and more are selected (change).", checkedEngines.first(), checkedEngines.at(1))); break; } OnlineSearchQueryFormAbstract *currentQueryWidget = nullptr; if (cursor != nullptr && checkedEngines.size() == 1) currentQueryWidget = cursor->data(WidgetRole).value(); if (currentQueryWidget == nullptr) currentQueryWidget = generalQueryTermsForm; QScrollArea *area = formToScrollArea.value(currentQueryWidget, nullptr); if (area != nullptr) queryTermsStack->setCurrentWidget(area); if (useEntryButton != nullptr) useEntryButton->setEnabled(!currentEntry.isNull() && tabWidget->currentIndex() == 0); } void openHomepage() { QListWidgetItem *item = enginesList->currentItem(); if (item != nullptr) { QUrl url = item->data(HomepageRole).toUrl(); /// Guess mime type for url to open QMimeType mimeType = FileInfo::mimeTypeForUrl(url); const QString mimeTypeName = mimeType.name(); /// Ask KDE subsystem to open url in viewer matching mime type #if KIO_VERSION < 0x051f00 // < 5.31.0 KRun::runUrl(url, mimeTypeName, p, false, false); #else // KIO_VERSION < 0x051f00 // >= 5.31.0 KRun::runUrl(url, mimeTypeName, p, KRun::RunFlags()); #endif // KIO_VERSION < 0x051f00 } } void enginesListCurrentChanged(QListWidgetItem *current) { actionOpenHomepage->setEnabled(current != nullptr); } }; SearchForm::SearchForm(SearchResults *searchResults, QWidget *parent) : QWidget(parent), d(new SearchFormPrivate(searchResults, this)) { d->loadEngines(); d->switchToSearch(); } SearchForm::~SearchForm() { delete d; } void SearchForm::updatedConfiguration() { d->loadEngines(); } void SearchForm::setElement(QSharedPointer element, const File *) { d->currentEntry = element.dynamicCast(); d->useEntryButton->setEnabled(!d->currentEntry.isNull() && d->tabWidget->currentIndex() == 0); } void SearchForm::switchToEngines() { d->switchToEngines(); } void SearchForm::startSearch() { OnlineSearchQueryFormAbstract *currentForm = d->currentQueryForm(); if (!currentForm->readyToStart()) { KMessageBox::sorry(this, i18n("Could not start searching the Internet:\nThe search terms are not complete or invalid."), i18n("Searching the Internet")); return; } d->runningSearches.clear(); d->sr->clear(); d->progressBar->setValue(0); d->progressMap.clear(); d->useEntryButton->hide(); d->progressBar->show(); if (currentForm == d->generalQueryTermsForm) { /// start search using the general-purpose form's values QMap queryTerms = d->generalQueryTermsForm->getQueryTerms(); int numResults = d->generalQueryTermsForm->getNumResults(); for (QMap::ConstIterator it = d->itemToOnlineSearch.constBegin(); it != d->itemToOnlineSearch.constEnd(); ++it) if (it.key()->checkState() == Qt::Checked) { it.value()->startSearch(queryTerms, numResults); d->runningSearches.insert(it.value()); } if (d->runningSearches.isEmpty()) { /// if no search engine has been checked (selected), something went wrong return; } } else { /// use the single selected search engine's specific form for (QMap::ConstIterator it = d->itemToOnlineSearch.constBegin(); it != d->itemToOnlineSearch.constEnd(); ++it) if (it.key()->checkState() == Qt::Checked) { it.value()->startSearchFromForm(); d->runningSearches.insert(it.value()); } if (d->runningSearches.isEmpty()) { /// if no search engine has been checked (selected), something went wrong return; } } d->switchToCancel(); } void SearchForm::foundEntry(QSharedPointer entry) { d->sr->insertElement(entry); } void SearchForm::stoppedSearch(int) { OnlineSearchAbstract *engine = static_cast(sender()); if (d->runningSearches.remove(engine)) { if (d->runningSearches.isEmpty()) { /// last search engine stopped d->switchToSearch(); emit doneSearching(); QTimer::singleShot(1000, d->progressBar, &QProgressBar::hide); QTimer::singleShot(1100, d->useEntryButton, &QPushButton::show); } else { QStringList remainingEngines; remainingEngines.reserve(d->runningSearches.size()); for (OnlineSearchAbstract *running : const_cast &>(d->runningSearches)) { remainingEngines.append(running->label()); } if (!remainingEngines.isEmpty()) qCDebug(LOG_KBIBTEX_PROGRAM) << "Remaining running engines:" << remainingEngines.join(QStringLiteral(", ")); } } } void SearchForm::tabSwitched(int newTab) { Q_UNUSED(newTab); d->updateGUI(); } void SearchForm::itemCheckChanged(QListWidgetItem *item) { int numCheckedEngines = 0; for (QMap::ConstIterator it = d->itemToOnlineSearch.constBegin(); it != d->itemToOnlineSearch.constEnd(); ++it) if (it.key()->checkState() == Qt::Checked) ++numCheckedEngines; d->searchButton->setEnabled(numCheckedEngines > 0); if (item != nullptr) { KConfigGroup configGroup(d->config, d->configGroupName); QString name = item->data(SearchForm::SearchFormPrivate::NameRole).toString(); configGroup.writeEntry(name, item->checkState() == Qt::Checked); d->config->sync(); } } void SearchForm::openHomepage() { d->openHomepage(); } void SearchForm::enginesListCurrentChanged(QListWidgetItem *current, QListWidgetItem *) { d->enginesListCurrentChanged(current); } void SearchForm::copyFromEntry() { Q_ASSERT_X(!d->currentEntry.isNull(), "SearchForm::copyFromEntry", "d->currentEntry is NULL"); d->currentQueryForm()->copyFromEntry(*(d->currentEntry)); } void SearchForm::updateProgress(int cur, int total) { OnlineSearchAbstract *ws = static_cast(sender()); d->progressMap[ws] = total > 0 ? cur * 1000 / total : 0; int progress = 0, count = 0; for (QMap::ConstIterator it = d->progressMap.constBegin(); it != d->progressMap.constEnd(); ++it, ++count) progress += it.value(); d->progressBar->setValue(count >= 1 ? progress / count : 0); } diff --git a/src/test/kbibtextest.cpp b/src/test/kbibtextest.cpp index d0ec69d5..eeef41db 100644 --- a/src/test/kbibtextest.cpp +++ b/src/test/kbibtextest.cpp @@ -1,251 +1,251 @@ /*************************************************************************** * Copyright (C) 2004-2014 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "kbibtextest.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int filenameCounter = 0; class TestWidget : public QWidget { Q_OBJECT private: KBibTeXTest *m_parent; QPushButton *buttonStartTest; QProgressBar *progressBar; QAction *actionStartOnlineSearchTests; public: QListWidget *messageList; TestWidget(KBibTeXTest *parent) : QWidget(parent), m_parent(parent) { QGridLayout *layout = new QGridLayout(this); buttonStartTest = new QPushButton(QIcon::fromTheme(QStringLiteral("application-x-executable")), QStringLiteral("Start Tests"), this); layout->addWidget(buttonStartTest, 0, 0, 1, 1); progressBar = new QProgressBar(this); layout->addWidget(progressBar, 0, 1, 1, 3); progressBar->setVisible(false); messageList = new QListWidget(this); layout->addWidget(messageList, 1, 0, 4, 4); setupMenus(); } void setProgress(int pos, int total) { if (pos < 0 || total < 0) { progressBar->setVisible(false); progressBar->setMaximum(1); progressBar->setValue(0); } else { progressBar->setVisible(true); progressBar->setMaximum(total); progressBar->setValue(pos); } } void setupMenus() { QMenu *menu = new QMenu(buttonStartTest); buttonStartTest->setMenu(menu); /// ** Online Search ** actionStartOnlineSearchTests = new QAction(QStringLiteral("Online Search"), m_parent); connect(actionStartOnlineSearchTests, &QAction::triggered, m_parent, &KBibTeXTest::startOnlineSearchTests); menu->addAction(actionStartOnlineSearchTests); } void setBusy(bool isBusy) { buttonStartTest->setEnabled(!isBusy); actionStartOnlineSearchTests->setEnabled(!isBusy); } }; KBibTeXTest::KBibTeXTest(QWidget *parent) : QDialog(parent), m_running(false), m_isBusy(false) { static const QIcon iconINFO = QIcon::fromTheme(QStringLiteral("dialog-information")); m_onlineSearchList << new OnlineSearchAcmPortal(this); m_onlineSearchList << new OnlineSearchArXiv(this); m_onlineSearchList << new OnlineSearchBibsonomy(this); m_onlineSearchList << new OnlineSearchCERNDS(this); m_onlineSearchList << new OnlineSearchGoogleScholar(this); m_onlineSearchList << new OnlineSearchIDEASRePEc(this); m_onlineSearchList << new OnlineSearchIEEEXplore(this); m_onlineSearchList << new OnlineSearchIngentaConnect(this); m_onlineSearchList << new OnlineSearchInspireHep(this); - m_onlineSearchList << new OnlineSearchIsbnDB(this); + /// m_onlineSearchList << new OnlineSearchIsbnDB(this); /// disabled as provider switched to a paid model on 2017-12-26 m_onlineSearchList << new OnlineSearchJStor(this); m_onlineSearchList << new OnlineSearchMathSciNet(this); m_onlineSearchList << new OnlineSearchMRLookup(this); m_onlineSearchList << new OnlineSearchPubMed(this); m_onlineSearchList << new OnlineSearchScienceDirect(this); m_onlineSearchList << new OnlineSearchSOANASAADS(this); m_onlineSearchList << new OnlineSearchSpringerLink(this); m_onlineSearchList << new OnlineSearchBioRxiv(this); m_currentOnlineSearch = m_onlineSearchList.constBegin(); setWindowTitle(QStringLiteral("KBibTeX Test Suite")); m_testWidget = new TestWidget(this); const int fontSize = m_testWidget->fontMetrics().width(QLatin1Char('a')); m_testWidget->setMinimumSize(fontSize * 96, fontSize * 48); QBoxLayout *boxLayout = new QVBoxLayout(this); boxLayout->addWidget(m_testWidget); connect(this, &KBibTeXTest::rejected, this, &KBibTeXTest::aboutToQuit); addMessage(QString(QStringLiteral("Compiled for %1")).arg(KAboutData::applicationData().version()), iconINFO); } void KBibTeXTest::addMessage(const QString &message, const QIcon &icon) { QListWidgetItem *item = icon.isNull() ? new QListWidgetItem(message) : new QListWidgetItem(icon, message); item->setToolTip(item->text()); m_testWidget->messageList->addItem(item); m_testWidget->messageList->scrollToBottom(); qApp->processEvents(); } void KBibTeXTest::setBusy(bool isBusy) { m_testWidget->setBusy(isBusy); if (isBusy && !m_isBusy) { /// changing to busy state QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } else if (!isBusy && m_isBusy) { /// changing to idle state QApplication::restoreOverrideCursor(); } m_isBusy = isBusy; } void KBibTeXTest::aboutToQuit() { m_running = false; QTimer::singleShot(500, qApp, &QApplication::quit); } void KBibTeXTest::startOnlineSearchTests() { m_running = true; setBusy(true); m_testWidget->messageList->clear(); qApp->processEvents(); processNextSearch(); } void KBibTeXTest::onlineSearchStoppedSearch(int searchResult) { static const QIcon iconOK = QIcon::fromTheme(QStringLiteral("dialog-ok-apply")); static const QIcon iconERROR = QIcon::fromTheme(QStringLiteral("dialog-cancel")); static const QIcon iconAUTH = QIcon::fromTheme(QStringLiteral("dialog-cancel")); // FIXME "dialog-cancel" should be overlay on "dialog-password" static const QIcon iconNETWORK = QIcon::fromTheme(QStringLiteral("dialog-cancel")); // FIXME "dialog-cancel" should be overlay on "network-wired" if (searchResult == OnlineSearchAbstract::resultNoError) { if (m_currentOnlineSearchNumFoundEntries == 0) addMessage(QString(QStringLiteral("Got no error message searching '%1', but found NO entries")).arg((*m_currentOnlineSearch)->label()), iconERROR); else addMessage(QString(QStringLiteral("No error searching '%1', found %2 entries")).arg((*m_currentOnlineSearch)->label()).arg(m_currentOnlineSearchNumFoundEntries), iconOK); } else if (searchResult == OnlineSearchAbstract::resultAuthorizationRequired) { addMessage(QString(QStringLiteral("Authorization required for '%1'")).arg((*m_currentOnlineSearch)->label()), iconAUTH); } else if (searchResult == OnlineSearchAbstract::resultNetworkError) { addMessage(QString(QStringLiteral("Network error for '%1'")).arg((*m_currentOnlineSearch)->label()), iconNETWORK); } else { addMessage(QString(QStringLiteral("Error searching '%1'")).arg((*m_currentOnlineSearch)->label()), iconERROR); } m_currentOnlineSearch++; progress(-1, -1); processNextSearch(); } void KBibTeXTest::onlineSearchFoundEntry() { ++m_currentOnlineSearchNumFoundEntries; } void KBibTeXTest::progress(int pos, int total) { m_testWidget->setProgress(pos, total); } void KBibTeXTest::resetProgress() { m_testWidget->setProgress(-1, -1); } void KBibTeXTest::processNextSearch() { static const QIcon iconINFO = QIcon::fromTheme(QStringLiteral("dialog-information")); if (m_running && m_currentOnlineSearch != m_onlineSearchList.constEnd()) { setBusy(true); m_currentOnlineSearchNumFoundEntries = 0; addMessage(QString(QStringLiteral("Searching '%1'")).arg((*m_currentOnlineSearch)->label()), iconINFO); QMap query; query.insert(OnlineSearchAbstract::queryKeyAuthor, QStringLiteral("smith")); connect(*m_currentOnlineSearch, &OnlineSearchAbstract::stoppedSearch, this, &KBibTeXTest::onlineSearchStoppedSearch); connect(*m_currentOnlineSearch, &OnlineSearchAbstract::foundEntry, this, &KBibTeXTest::onlineSearchFoundEntry); connect(*m_currentOnlineSearch, &OnlineSearchAbstract::progress, this, &KBibTeXTest::progress); (*m_currentOnlineSearch)->startSearch(query, 3); } else { addMessage(QStringLiteral("Done testing"), iconINFO); setBusy(false); m_running = false; QTimer::singleShot(500, this, &KBibTeXTest::resetProgress); } } #include "kbibtextest.moc"