Commit d9d708de authored by Friedrich W. H. Kossebau's avatar Friedrich W. H. Kossebau
Browse files

Port mediawiki runner to Plasma5/Qt5

Summary:
Straight initial port of existing logic, with separate plugin metadata files
for different services. Perhaps could be changed to have just one normal
plugin, but with a config UI where the user can edit a list of
mediawiki-running servers and individual trigger words per server.
Left for another step/developer for now.

Test Plan:
A bug in Milou (kde #389611) prevents normal testing for now.
One can increase that reset timeout to some big value, e.g.
m_resetTimer.setInterval(3000);
in the Milou::SourcesModel constructor to work around the bug.
Then enable the mediawiki plugins you want to test, e.g. the
Wikipedia one, and enter in KRunner "wiki kde plasma"

Reviewers: broulik, jriddell, davidedmundson, sebas, mart

Reviewed By: mart

Subscribers: ngraham, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D10184
parent 42eaeb1d
add_subdirectory(converter)
add_subdirectory(datetime)
add_subdirectory(katesessions)
# add_subdirectory(mediawiki)
add_subdirectory(mediawiki)
add_subdirectory(spellchecker)
add_subdirectory(characters)
add_subdirectory(dictionary)
......
add_definitions(-DTRANSLATION_DOMAIN="plasma_runner_mediawiki")
set(krunner_mediawiki_SRCS
mediawikirunner.cpp
mediawiki.cpp
)
kde4_add_plugin(krunner_mediawiki ${krunner_mediawiki_SRCS})
target_link_libraries(krunner_mediawiki ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${KDE4_SOLID_LIBS})
add_library(krunner_mediawiki MODULE ${krunner_mediawiki_SRCS})
target_link_libraries(krunner_mediawiki
KF5::Runner
KF5::I18n
Qt5::Network
)
install(TARGETS krunner_mediawiki DESTINATION ${PLUGIN_INSTALL_DIR} )
install(TARGETS krunner_mediawiki DESTINATION ${KDE_INSTALL_PLUGINDIR} )
install(FILES
plasma-runner-wikipedia.desktop
plasma-runner-wikitravel.desktop
plasma-runner-techbase.desktop
DESTINATION ${SERVICES_INSTALL_DIR})
# doesn't seem to work, maybe XML API is disabled
#install(FILES plasma-runner-userbase.desktop DESTINATION ${SERVICES_INSTALL_DIR})
plasma-runner-userbase.desktop
DESTINATION ${KDE_INSTALL_KSERVICES5DIR}
)
......@@ -20,16 +20,15 @@
#include "mediawiki.h"
// KF
#include <KRunner/RunnerContext>
// Qt
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QXmlStreamReader>
#include <QTimer>
#include <KDebug>
#include <KIO/AccessManager>
#include <Plasma/RunnerContext>
#include <QUrlQuery>
enum State {
StateApiChanged,
......@@ -56,16 +55,17 @@ MediaWiki::MediaWiki( QObject *parent )
{
d->state = StateApiChanged;
// should be overwritten by the user
d->apiUrl = QUrl("http://en.wikipedia.org/w/api.php");
d->apiUrl = QUrl(QStringLiteral("https://en.wikipedia.org/w/api.php"));
//FIXME: at the moment KIO doesn't seem to work in threads
d->manager = new QNetworkAccessManager( this );
d->manager->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
//d->manager = new KIO::AccessManager( this );
d->maxItems = 10;
d->timeout = 30 * 1000; // 30 second
d->reply = 0;
d->reply = nullptr;
d->userAgent = QByteArray("KDE Plasma Silk; MediaWikiRunner; 1.0");
connect( d->manager, SIGNAL(finished(QNetworkReply*)), SLOT(finished(QNetworkReply*)) );
connect(d->manager, &QNetworkAccessManager::finished, this, &MediaWiki::onNetworkRequestFinished);
}
MediaWiki::~MediaWiki()
......@@ -118,24 +118,26 @@ void MediaWiki::abort()
return;
d->reply->abort();
d->reply = 0;
d->reply = nullptr;
}
void MediaWiki::search( const QString &searchTerm )
{
QUrl url = d->apiUrl;
url.addQueryItem( QString("action"), QString("query") );
url.addQueryItem( QString("format"), QString("xml") );
url.addQueryItem( QString("list"), QString("search") );
url.addQueryItem( QString("srsearch"), searchTerm );
url.addQueryItem( QString("srlimit"), QString::number(d->maxItems) );
QUrlQuery urlQuery(url);
urlQuery.addQueryItem(QStringLiteral("action"), QStringLiteral("query"));
urlQuery.addQueryItem(QStringLiteral("format"), QStringLiteral("xml"));
urlQuery.addQueryItem(QStringLiteral("list"), QStringLiteral("search"));
urlQuery.addQueryItem(QStringLiteral("srsearch"), searchTerm );
urlQuery.addQueryItem(QStringLiteral("srlimit"), QString::number(d->maxItems));
url.setQuery(urlQuery);
kDebug() << "Constructed search URL" << url;
qDebug() << "Constructed search URL" << url;
if ( d->state == StateReady ) {
QNetworkRequest req(url);
req.setRawHeader( QByteArray("User-Agent"), d->userAgent );
kDebug() << "mediawiki User-Agent" << req.rawHeader(QByteArray("UserAgent"));
qDebug() << "mediawiki User-Agent" << req.rawHeader(QByteArray("UserAgent"));
d->reply = d->manager->get( req );
QTimer::singleShot( d->timeout, this, SLOT(abort()) );
......@@ -149,11 +151,13 @@ void MediaWiki::findBase()
{
// http://en.wikipedia.org/w/api.php?action=query&meta=siteinfo
QUrl url = d->apiUrl;
url.addQueryItem( QString("action"), QString("query") );
url.addQueryItem( QString("format"), QString("xml") );
url.addQueryItem( QString("meta"), QString("siteinfo") );
QUrlQuery urlQuery(url);
urlQuery.addQueryItem(QStringLiteral("action"), QStringLiteral("query"));
urlQuery.addQueryItem(QStringLiteral("format"), QStringLiteral("xml"));
urlQuery.addQueryItem(QStringLiteral("meta"), QStringLiteral("siteinfo"));
url.setQuery(urlQuery);
kDebug() << "Constructed base query URL" << url;
qDebug() << "Constructed base query URL" << url;
QNetworkRequest req(url);
req.setRawHeader( QByteArray("User-Agent"), d->userAgent );
......@@ -161,21 +165,21 @@ void MediaWiki::findBase()
d->state = StateApiUpdating;
}
void MediaWiki::finished( QNetworkReply *reply )
void MediaWiki::onNetworkRequestFinished(QNetworkReply *reply)
{
if ( reply->error() != QNetworkReply::NoError ) {
kDebug() << "Request failed, " << reply->errorString();
qDebug() << "Request failed, " << reply->errorString();
emit finished(false);
return;
}
kDebug() << "Request succeeded" << d->apiUrl;
qDebug() << "Request succeeded" << d->apiUrl;
if ( d->state == StateApiUpdating ) {
bool ok = processBaseResult( reply );
Q_UNUSED ( ok );
reply->deleteLater();
reply= 0;
reply= nullptr;
d->state = StateReady;
QNetworkRequest req(d->query);
......@@ -187,7 +191,7 @@ void MediaWiki::finished( QNetworkReply *reply )
emit finished( ok );
d->reply->deleteLater();
d->reply = 0;
d->reply = nullptr;
}
}
......@@ -197,13 +201,13 @@ bool MediaWiki::processBaseResult( QIODevice *source )
while ( !reader.atEnd() ) {
QXmlStreamReader::TokenType tokenType = reader.readNext();
// kDebug() << "Token" << int(tokenType);
// qDebug() << "Token" << int(tokenType);
if ( tokenType == QXmlStreamReader::StartElement ) {
if ( reader.name() == QString("general") ) {
if (reader.name() == QLatin1String("general")) {
QXmlStreamAttributes attrs = reader.attributes();
d->baseUrl = QUrl( attrs.value( QString("base") ).toString() );
return true;
d->baseUrl = QUrl(attrs.value(QStringLiteral("base")).toString());
return true;
}
} else if ( tokenType == QXmlStreamReader::Invalid )
return false;
......@@ -219,18 +223,18 @@ bool MediaWiki::processSearchResult( QIODevice *source )
QXmlStreamReader reader( source );
while ( !reader.atEnd() ) {
QXmlStreamReader::TokenType tokenType = reader.readNext();
// kDebug() << "Token" << int(tokenType);
// qDebug() << "Token" << int(tokenType);
if ( tokenType == QXmlStreamReader::StartElement ) {
if ( reader.name() == QString("p") ) {
if (reader.name() == QLatin1String("p")) {
QXmlStreamAttributes attrs = reader.attributes();
Result r;
r.url = d->baseUrl.resolved( attrs.value( QString("title") ).toString() );
r.title = attrs.value( QString("title") ).toString();
Result r;
r.title = attrs.value(QStringLiteral("title")).toString();
r.url = d->baseUrl.resolved(QUrl(r.title));
kDebug() << "Got result: url=" << r.url << "title=" << r.title;
qDebug() << "Got result: url=" << r.url << "title=" << r.title;
d->results.prepend( r );
d->results.prepend( r );
}
} else if ( tokenType == QXmlStreamReader::Invalid ) {
return false;
......@@ -238,5 +242,3 @@ bool MediaWiki::processSearchResult( QIODevice *source )
}
return true;
}
......@@ -21,11 +21,13 @@
#ifndef MEDIAWIKI_H
#define MEDIAWIKI_H
// Qt
#include <QObject>
#include <QList>
#include <QUrl>
class QNetworkReply;
class QIODevice;
/**
* Searches MediaWiki based wikis like wikipedia and techbase.
......@@ -69,8 +71,8 @@ public:
* a time.
* @param parent The parent object
*/
MediaWiki( QObject *parent=0 );
virtual ~MediaWiki();
explicit MediaWiki(QObject *parent = nullptr);
~MediaWiki() override;
/**
* @returns a list of matches.
......@@ -108,14 +110,14 @@ public:
*/
void setTimeout( int millis );
signals:
Q_SIGNALS:
/**
* Emitted when a search has been completed.
* @param success true if the search was completed successfully.
*/
void finished( bool success );
public slots:
public Q_SLOTS:
/**
* Search the wiki for the specified search term.
*/
......@@ -126,8 +128,8 @@ public slots:
*/
void abort();
private slots:
void finished( QNetworkReply *reply );
private Q_SLOTS:
void onNetworkRequestFinished(QNetworkReply *reply);
private:
void findBase();
......
......@@ -18,45 +18,45 @@
*/
#include "mediawikirunner.h"
#include "mediawiki.h"
// KF
#include <KPluginInfo>
#include <KServiceTypeTrader>
#include <KLocalizedString>
// Qt
#include <QMutex>
#include <QtCore/QEventLoop>
#include <QEventLoop>
#include <QWaitCondition>
#include <QDesktopServices>
#include <QDebug>
#include <KDebug>
#include <KIcon>
#include <KPluginInfo>
#include <KServiceTypeTrader>
#include <KToolInvocation>
#include <solid/networking.h>
MediaWikiRunner::MediaWikiRunner(QObject *parent, const QVariantList& args)
MediaWikiRunner::MediaWikiRunner(QObject *parent, const QVariantList &args)
: Plasma::AbstractRunner(parent, args)
{
Q_UNUSED(args);
setObjectName("MediaWikiRunner");
setObjectName(QStringLiteral("MediaWikiRunner"));
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(id());
const KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner", constraint);
const QString constraint = QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(id());
const KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("Plasma/Runner"), constraint);
foreach (const KPluginInfo &info, KPluginInfo::fromServices(offers)) {
QStringList _urls = info.property("X-Plasma-Args").toStringList();
QString _u;
kDebug() << info.name() << info.property("X-Plasma-Args").toStringList() << _urls.count();
const auto _urls = info.property(QStringLiteral("X-Plasma-Args")).toStringList();
qDebug() << info.name() << _urls << _urls.count();
if (_urls.count()) {
m_apiUrl = _urls[0];
m_apiUrl = QUrl(_urls[0]);
} else {
kWarning() << "No X-Plasma-Args found in .desktop file";
qWarning() << "No X-Plasma-Args found in .desktop file";
}
m_name = info.name();
m_comment = info.comment();
m_icon = KIcon(info.icon());
m_iconName = info.icon();
}
addSyntax(Plasma::RunnerSyntax("wiki :q:", i18n("Searches %1 for :q:.", m_name)));
addSyntax(Plasma::RunnerSyntax(QStringLiteral("wiki :q:"), i18n("Searches %1 for :q:.", m_name)));
setSpeed( SlowSpeed );
}
......@@ -69,20 +69,23 @@ MediaWikiRunner::~MediaWikiRunner()
void MediaWikiRunner::match(Plasma::RunnerContext &context)
{
// Check for networkconnection
if(Solid::Networking::status() == Solid::Networking::Unconnected) {
if (!m_networkConfigurationManager.isOnline() ||
!m_apiUrl.isValid()) {
return;
}
QString term = context.query();
if (!context.singleRunnerQueryMode()) {
if (!term.startsWith("wiki ")) {
if (!term.startsWith(QLatin1String("wiki "))) {
return;
} else {
term = term.remove("wiki ");
}
term.remove(0, 5);
}
if (!m_apiUrl.isValid() || term.length() < 3) {
//kDebug() << "yours is too short" << term;
if (term.length() < 3) {
//qDebug() << "yours is too short" << term;
return;
}
......@@ -105,10 +108,10 @@ void MediaWikiRunner::match(Plasma::RunnerContext &context)
mediawiki.setMaxItems(3);
}
mediawiki.setApiUrl( m_apiUrl );
connect( &mediawiki, SIGNAL(finished(bool)), &loop, SLOT(quit()) );
connect(&mediawiki, &MediaWiki::finished, &loop, &QEventLoop::quit);
mediawiki.search(term);
kDebug() << "Wikisearch:" << m_name << term;
qDebug() << "Wikisearch:" << m_name << term;
loop.exec();
......@@ -119,27 +122,32 @@ void MediaWikiRunner::match(Plasma::RunnerContext &context)
qreal stepRelevance = 0.1;
foreach(const MediaWiki::Result& res, mediawiki.results()) {
kDebug() << "Match:" << res.url << res.title;
qDebug() << "Match:" << res.url << res.title;
Plasma::QueryMatch match(this);
match.setType(Plasma::QueryMatch::PossibleMatch);
match.setIcon(m_icon);
match.setText(QString("%1: %2").arg(m_name, res.title));
match.setIconName(m_iconName);
match.setText(QStringLiteral("%1: %2").arg(m_name, res.title));
match.setData(res.url);
match.setRelevance(relevance);
relevance +=stepRelevance;
stepRelevance *=0.5;
context.addMatch(res.title, match);
context.addMatch(match);
}
}
void MediaWikiRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match)
{
Q_UNUSED(context)
const QString wikiurl = match.data().toUrl().toString();
kDebug() << "Open MediaWiki page " << wikiurl;
qDebug() << "Open MediaWiki page " << wikiurl;
if (!wikiurl.isEmpty()) {
KToolInvocation::invokeBrowser(wikiurl, "");
QDesktopServices::openUrl(QUrl(wikiurl));
}
}
K_EXPORT_PLASMA_RUNNER(mediawiki, MediaWikiRunner)
#include "mediawikirunner.moc"
......@@ -20,37 +20,30 @@
#ifndef MEDIAWIKIRUNNER_H
#define MEDIAWIKIRUNNER_H
#include <plasma/abstractrunner.h>
// KF
#include <KRunner/AbstractRunner>
// Qt
#include <QNetworkConfigurationManager>
class KIcon;
#include <KIcon>
#include <QWaitCondition>
class QWaitCondition;
#include "mediawiki.h"
class MediaWikiRunner : public Plasma::AbstractRunner {
class MediaWikiRunner : public Plasma::AbstractRunner
{
Q_OBJECT
public:
MediaWikiRunner( QObject *parent, const QVariantList& args );
~MediaWikiRunner();
public:
MediaWikiRunner(QObject *parent, const QVariantList &args);
~MediaWikiRunner() override;
void match(Plasma::RunnerContext &context);
void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match);
void match(Plasma::RunnerContext &context) override;
void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) override;
signals:
void done();
private:
QString m_iconName;
QString m_name;
QString m_comment;
QUrl m_apiUrl;
private:
KIcon m_icon;
QString m_name;
QString m_comment;
QUrl m_apiUrl;
QNetworkConfigurationManager m_networkConfigurationManager;
};
K_EXPORT_PLASMA_RUNNER(mediawiki, MediaWikiRunner)
#endif
......@@ -106,4 +106,4 @@ X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-License=LGPL
X-KDE-PluginInfo-EnabledByDefault=false
X-Plasma-Args=http://techbase.kde.org/api.php
X-Plasma-Args=https://techbase.kde.org/api.php
......@@ -110,4 +110,4 @@ X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-License=LGPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-Args=http://userbase.kde.org/api.php
X-Plasma-Args=https://userbase.kde.org/api.php
......@@ -115,4 +115,4 @@ X-KDE-PluginInfo-License=LGPL
X-KDE-PluginInfo-EnabledByDefault=false
X-Plasma-AdvertiseSingleRunnerQueryMode=true
X-Plasma-Args=http://en.wikipedia.org/w/api.php
X-Plasma-Args=https://en.wikipedia.org/w/api.php
......@@ -110,4 +110,4 @@ X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-License=LGPL
X-KDE-PluginInfo-EnabledByDefault=false
X-Plasma-Args=http://wikitravel.org/wiki/en/api.php
X-Plasma-Args=https://wikitravel.org/wiki/en/api.php
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment