- Search for artists/albums using wikipedia search API.
- Add configurable languages
This commit is contained in:
committed by
craig.p.drummond
parent
15449d9999
commit
6114afbe5e
@@ -103,7 +103,8 @@ SET( CANTATA_SRCS gui/application.cpp gui/main.cpp gui/initialsettingswizard.cpp
|
||||
network/networkaccessmanager.cpp
|
||||
devices/deviceoptions.cpp
|
||||
context/lyricsettings.cpp context/ultimatelyricsprovider.cpp context/ultimatelyrics.cpp context/lyricsdialog.cpp
|
||||
context/contextpage.cpp context/view.cpp context/artistview.cpp context/albumview.cpp context/songview.cpp)
|
||||
context/contextpage.cpp context/view.cpp context/artistview.cpp context/albumview.cpp context/songview.cpp context/contextengine.cpp
|
||||
context/wikipediaengine.cpp context/wikipediasettings.cpp)
|
||||
SET( CANTATA_MOC_HDRS
|
||||
gui/initialsettingswizard.h gui/mainwindow.h gui/settings.h gui/covers.h gui/folderpage.h gui/librarypage.h gui/albumspage.h
|
||||
gui/playlistspage.h gui/serverplaybacksettings.h gui/serversettings.h gui/preferencesdialog.h gui/filesettings.h
|
||||
@@ -119,14 +120,15 @@ SET( CANTATA_MOC_HDRS
|
||||
widgets/genrecombo.h widgets/toolbar.h
|
||||
network/networkaccessmanager.h
|
||||
context/lyricsettings.h context/ultimatelyrics.h context/ultimatelyricsprovider.h context/lyricsdialog.h
|
||||
context/contextpage.h context/artistview.h context/albumview.h context/songview.h context/view.h)
|
||||
context/contextpage.h context/artistview.h context/albumview.h context/songview.h context/view.h context/contextengine.h
|
||||
context/wikipediaengine.h context/wikipediasettings.h)
|
||||
SET( CANTATA_UIS
|
||||
gui/initialsettingswizard.ui gui/mainwindow.ui gui/folderpage.ui gui/librarypage.ui gui/albumspage.ui gui/playlistspage.ui
|
||||
gui/filesettings.ui gui/interfacesettings.ui gui/playbacksettings.ui gui/serverplaybacksettings.ui gui/serversettings.ui
|
||||
gui/coverdialog.ui
|
||||
streams/streamspage.ui
|
||||
dynamic/dynamicpage.ui dynamic/dynamicrule.ui dynamic/dynamicrules.ui
|
||||
context/lyricsettings.ui
|
||||
context/lyricsettings.ui context/wikipediasettings.ui
|
||||
widgets/itemview.ui)
|
||||
|
||||
if (ENABLE_ONLINE_SERVICES)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "utils.h"
|
||||
#include "qtiocompressor/qtiocompressor.h"
|
||||
#include "musiclibrarymodel.h"
|
||||
#include "contextengine.h"
|
||||
#include <QTextBrowser>
|
||||
#include <QScrollBar>
|
||||
#include <QFile>
|
||||
@@ -53,10 +54,10 @@ enum Parts {
|
||||
|
||||
AlbumView::AlbumView(QWidget *p)
|
||||
: View(p)
|
||||
, triedWithFilter(false)
|
||||
, detailsReceived(0)
|
||||
, job(0)
|
||||
{
|
||||
engine=ContextEngine::create(this);
|
||||
connect(engine, SIGNAL(searchResult(QString,QString)), this, SLOT(searchResponse(QString,QString)));
|
||||
connect(Covers::self(), SIGNAL(cover(const Song &, const QImage &, const QString &)), SLOT(coverRetreived(const Song &, const QImage &, const QString &)));
|
||||
connect(Covers::self(), SIGNAL(coverUpdated(const Song &, const QImage &, const QString &)), SLOT(coverRetreived(const Song &, const QImage &, const QString &)));
|
||||
connect(text, SIGNAL(anchorClicked(QUrl)), SLOT(playSong(QUrl)));
|
||||
@@ -71,7 +72,7 @@ void AlbumView::update(const Song &song, bool force)
|
||||
{
|
||||
if (song.isEmpty()) {
|
||||
currentSong=song;
|
||||
cancel();
|
||||
engine->cancel();
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
@@ -84,7 +85,7 @@ void AlbumView::update(const Song &song, bool force)
|
||||
details.clear();
|
||||
trackList.clear();
|
||||
bio.clear();
|
||||
triedWithFilter=false;
|
||||
clear();
|
||||
detailsReceived=bioArtist==currentSong.artist ? ArtistBio : 0;
|
||||
setHeader(song.album.isEmpty() ? stdHeader : song.album);
|
||||
Covers::Image cImg=Covers::self()->requestImage(song);
|
||||
@@ -143,23 +144,25 @@ void AlbumView::getTrackListing()
|
||||
|
||||
void AlbumView::getDetails()
|
||||
{
|
||||
cancel();
|
||||
QString cachedFile=cacheFileName(Covers::fixArtist(currentSong.albumArtist()), currentSong.album, locale, false);
|
||||
if (QFile::exists(cachedFile)) {
|
||||
QFile f(cachedFile);
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::ReadOnly)) {
|
||||
QByteArray data=compressor.readAll();
|
||||
engine->cancel();
|
||||
foreach (const QString &lang, engine->getLangs()) {
|
||||
QString cachedFile=cacheFileName(Covers::fixArtist(currentSong.albumArtist()), currentSong.album, lang, false);
|
||||
if (QFile::exists(cachedFile)) {
|
||||
QFile f(cachedFile);
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::ReadOnly)) {
|
||||
QByteArray data=compressor.readAll();
|
||||
|
||||
if (!data.isEmpty()) {
|
||||
searchResponse(QString::fromUtf8(data));
|
||||
Utils::touchFile(cachedFile);
|
||||
return;
|
||||
if (!data.isEmpty()) {
|
||||
searchResponse(QString::fromUtf8(data), QString());
|
||||
Utils::touchFile(cachedFile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
search(currentSong.albumArtist()+" "+currentSong.album);
|
||||
engine->search(QStringList() << currentSong.albumArtist() << currentSong.album, ContextEngine::Album);
|
||||
}
|
||||
|
||||
void AlbumView::coverRetreived(const Song &s, const QImage &img, const QString &file)
|
||||
@@ -174,26 +177,22 @@ void AlbumView::coverRetreived(const Song &s, const QImage &img, const QString &
|
||||
}
|
||||
}
|
||||
|
||||
void AlbumView::searchResponse(const QString &resp)
|
||||
void AlbumView::searchResponse(const QString &resp, const QString &lang)
|
||||
{
|
||||
if (View::constAmbiguous==resp && !triedWithFilter) {
|
||||
triedWithFilter=true;
|
||||
search(currentSong.albumArtist()+" "+currentSong.album+" "+i18nc("Search pattern for an album", "(album|score|soundtrack)"));
|
||||
return;
|
||||
}
|
||||
|
||||
detailsReceived|=Details;
|
||||
if (All==detailsReceived) {
|
||||
hideSpinner();
|
||||
}
|
||||
|
||||
if (!resp.isEmpty() && View::constAmbiguous!=resp) {
|
||||
if (!resp.isEmpty()) {
|
||||
details=resp;
|
||||
QFile f(cacheFileName(Covers::fixArtist(currentSong.albumArtist()), currentSong.album, locale, true));
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::WriteOnly)) {
|
||||
compressor.write(resp.toUtf8().constData());
|
||||
if (!lang.isEmpty()) {
|
||||
QFile f(cacheFileName(Covers::fixArtist(currentSong.albumArtist()), currentSong.album, lang, true));
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::WriteOnly)) {
|
||||
compressor.write(resp.toUtf8().constData());
|
||||
}
|
||||
}
|
||||
updateDetails();
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ class QImage;
|
||||
class QNetworkReply;
|
||||
class QByteArray;
|
||||
class QUrl;
|
||||
class ContextEngine;
|
||||
|
||||
class AlbumView : public View
|
||||
{
|
||||
@@ -53,18 +54,17 @@ public Q_SLOTS:
|
||||
private:
|
||||
void getTrackListing();
|
||||
void getDetails();
|
||||
void searchResponse(const QString &resp);
|
||||
void searchResponse(const QString &resp, const QString &lang);
|
||||
void updateDetails(bool preservePos=false);
|
||||
void abort();
|
||||
|
||||
private:
|
||||
bool triedWithFilter;
|
||||
ContextEngine *engine;
|
||||
int detailsReceived;
|
||||
QString details;
|
||||
QString trackList;
|
||||
QString bioArtist;
|
||||
QString bio;
|
||||
QNetworkReply *job;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "musiclibrarymodel.h"
|
||||
#include "networkaccessmanager.h"
|
||||
#include "qtiocompressor/qtiocompressor.h"
|
||||
#include "contextengine.h"
|
||||
#include <QNetworkReply>
|
||||
#include <QApplication>
|
||||
#include <QTextBrowser>
|
||||
@@ -51,17 +52,18 @@ const QLatin1String ArtistView::constCacheDir("artists/");
|
||||
const QLatin1String ArtistView::constInfoExt(".html.gz");
|
||||
const QLatin1String ArtistView::constSimilarInfoExt(".txt");
|
||||
|
||||
static QString cacheFileName(const QString &artist, const QString &locale, bool similar, bool createDir)
|
||||
static QString cacheFileName(const QString &artist, const QString &lang, bool similar, bool createDir)
|
||||
{
|
||||
return Utils::cacheDir(ArtistView::constCacheDir, createDir)+
|
||||
Covers::encodeName(artist)+(similar ? "-similar" : ("."+locale))+(similar ? ArtistView::constSimilarInfoExt : ArtistView::constInfoExt);
|
||||
Covers::encodeName(artist)+(similar ? "-similar" : ("."+lang))+(similar ? ArtistView::constSimilarInfoExt : ArtistView::constInfoExt);
|
||||
}
|
||||
|
||||
ArtistView::ArtistView(QWidget *parent)
|
||||
: View(parent)
|
||||
, triedWithFilter(false)
|
||||
, currentSimilarJob(0)
|
||||
{
|
||||
engine=ContextEngine::create(this);
|
||||
connect(engine, SIGNAL(searchResult(QString,QString)), this, SLOT(searchResponse(QString,QString)));
|
||||
connect(Covers::self(), SIGNAL(artistImage(Song,QImage,QString)), SLOT(artistImage(Song,QImage,QString)));
|
||||
connect(text, SIGNAL(anchorClicked(QUrl)), SLOT(showArtist(QUrl)));
|
||||
Utils::clearOldCache(constCacheDir, constCacheAge);
|
||||
@@ -77,7 +79,7 @@ void ArtistView::update(const Song &s, bool force)
|
||||
{
|
||||
if (s.isEmpty()) {
|
||||
currentSong=s;
|
||||
cancel();
|
||||
engine->cancel();
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
@@ -106,7 +108,6 @@ void ArtistView::update(const Song &s, bool force)
|
||||
clear();
|
||||
biography.clear();
|
||||
similarArtists=QString();
|
||||
triedWithFilter=false;
|
||||
if (!currentSong.isEmpty()) {
|
||||
setHeader(currentSong.artist);
|
||||
|
||||
@@ -132,31 +133,33 @@ void ArtistView::artistImage(const Song &song, const QImage &i, const QString &f
|
||||
|
||||
void ArtistView::loadBio()
|
||||
{
|
||||
QString cachedFile=cacheFileName(currentSong.artist, locale, false, false);
|
||||
if (QFile::exists(cachedFile)) {
|
||||
QFile f(cachedFile);
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::ReadOnly)) {
|
||||
QString data=QString::fromUtf8(compressor.readAll());
|
||||
foreach (const QString &lang, engine->getLangs()) {
|
||||
QString cachedFile=cacheFileName(currentSong.artist, lang, false, false);
|
||||
if (QFile::exists(cachedFile)) {
|
||||
QFile f(cachedFile);
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::ReadOnly)) {
|
||||
QString data=QString::fromUtf8(compressor.readAll());
|
||||
|
||||
if (!data.isEmpty() && View::constAmbiguous!=data) {
|
||||
searchResponse(data);
|
||||
loadSimilar();
|
||||
setBio();
|
||||
Utils::touchFile(cachedFile);
|
||||
return;
|
||||
if (!data.isEmpty()) {
|
||||
searchResponse(data, QString());
|
||||
loadSimilar();
|
||||
setBio();
|
||||
Utils::touchFile(cachedFile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showSpinner();
|
||||
search(currentSong.artist);
|
||||
engine->search(QStringList() << currentSong.artist, ContextEngine::Artist);
|
||||
}
|
||||
|
||||
void ArtistView::loadSimilar()
|
||||
{
|
||||
QString cachedFile=cacheFileName(currentSong.artist, locale, true, false);
|
||||
QString cachedFile=cacheFileName(currentSong.artist, QString(), true, false);
|
||||
if (QFile::exists(cachedFile)) {
|
||||
QFile f(cachedFile);
|
||||
if (f.open(QIODevice::ReadOnly|QIODevice::Text)) {
|
||||
@@ -193,7 +196,7 @@ void ArtistView::handleSimilarReply()
|
||||
if (!artists.isEmpty()) {
|
||||
buildSimilar(artists);
|
||||
setBio();
|
||||
QFile f(cacheFileName(reply->property(constNameKey).toString(), locale, true, true));
|
||||
QFile f(cacheFileName(reply->property(constNameKey).toString(), QString(), true, true));
|
||||
if (f.open(QIODevice::WriteOnly|QIODevice::Text)) {
|
||||
QTextStream stream(&f);
|
||||
foreach (const QString &artist, artists) {
|
||||
@@ -266,7 +269,7 @@ void ArtistView::requestSimilar()
|
||||
|
||||
void ArtistView::abort()
|
||||
{
|
||||
cancel();
|
||||
engine->cancel();
|
||||
if (currentSimilarJob) {
|
||||
disconnect(currentSimilarJob, SIGNAL(finished()), this, SLOT(handleSimilarArtistsReply()));
|
||||
currentSimilarJob->abort();
|
||||
@@ -274,24 +277,20 @@ void ArtistView::abort()
|
||||
}
|
||||
}
|
||||
|
||||
void ArtistView::searchResponse(const QString &resp)
|
||||
void ArtistView::searchResponse(const QString &resp, const QString &lang)
|
||||
{
|
||||
if (View::constAmbiguous==resp && !triedWithFilter) {
|
||||
triedWithFilter=true;
|
||||
search(currentSong.artist+" "+i18nc("Search pattern for an artist or band", "(artist|band)"));
|
||||
return;
|
||||
}
|
||||
|
||||
biography=View::constAmbiguous==resp ? QString() : resp;
|
||||
biography=resp;
|
||||
emit haveBio(currentSong.artist, resp);
|
||||
hideSpinner();
|
||||
|
||||
if (!resp.isEmpty()) {
|
||||
QFile f(cacheFileName(currentSong.artist, locale, false, false));
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::WriteOnly)) {
|
||||
compressor.write(resp.toUtf8().constData());
|
||||
if (!lang.isEmpty()) {
|
||||
QFile f(cacheFileName(currentSong.artist, lang, false, false));
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::WriteOnly)) {
|
||||
compressor.write(resp.toUtf8().constData());
|
||||
}
|
||||
}
|
||||
loadSimilar();
|
||||
setBio();
|
||||
|
||||
@@ -33,6 +33,7 @@ class QNetworkReply;
|
||||
class QIODevice;
|
||||
class QImage;
|
||||
class QUrl;
|
||||
class ContextEngine;
|
||||
|
||||
class ArtistView : public View
|
||||
{
|
||||
@@ -62,7 +63,7 @@ private Q_SLOTS:
|
||||
|
||||
private:
|
||||
void loadBio();
|
||||
void searchResponse(const QString &resp);
|
||||
void searchResponse(const QString &resp, const QString &lang);
|
||||
void loadSimilar();
|
||||
void requestSimilar();
|
||||
QStringList parseSimilarResponse(const QByteArray &resp);
|
||||
@@ -70,7 +71,7 @@ private:
|
||||
void abort();
|
||||
|
||||
private:
|
||||
bool triedWithFilter;
|
||||
ContextEngine *engine;
|
||||
QString biography;
|
||||
QString similarArtists;
|
||||
QNetworkReply *currentSimilarJob;
|
||||
|
||||
71
context/contextengine.cpp
Normal file
71
context/contextengine.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Cantata
|
||||
*
|
||||
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "contextengine.h"
|
||||
#include "wikipediaengine.h"
|
||||
#include "wikipediasettings.h"
|
||||
#include <QNetworkReply>
|
||||
|
||||
ContextEngine * ContextEngine::create(QObject *parent)
|
||||
{
|
||||
return new WikipediaEngine(parent);
|
||||
}
|
||||
|
||||
ContextSettings * ContextEngine::settings(QWidget *parent)
|
||||
{
|
||||
return new WikipediaSettings(parent);
|
||||
}
|
||||
|
||||
ContextEngine::ContextEngine(QObject *p)
|
||||
: QObject(p)
|
||||
, job(0)
|
||||
{
|
||||
}
|
||||
|
||||
ContextEngine::~ContextEngine()
|
||||
{
|
||||
cancel();
|
||||
}
|
||||
|
||||
void ContextEngine::cancel()
|
||||
{
|
||||
if (job) {
|
||||
job->deleteLater();
|
||||
job=0;
|
||||
}
|
||||
}
|
||||
|
||||
QNetworkReply * ContextEngine::getReply(QObject *obj)
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply*>(obj);
|
||||
if (!reply) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
if (reply!=job) {
|
||||
return 0;
|
||||
}
|
||||
job=0;
|
||||
return reply;
|
||||
}
|
||||
77
context/contextengine.h
Normal file
77
context/contextengine.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Cantata
|
||||
*
|
||||
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CONTEXT_ENGINE_H
|
||||
#define CONTEXT_ENGINE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QWidget>
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
class ContextSettings : public QWidget {
|
||||
public:
|
||||
ContextSettings(QWidget *p=0) : QWidget(p) { }
|
||||
virtual ~ContextSettings() { }
|
||||
virtual void load()=0;
|
||||
virtual void save()=0;
|
||||
};
|
||||
|
||||
class ContextEngine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Mode {
|
||||
Artist,
|
||||
Album
|
||||
};
|
||||
|
||||
static void setPreferedLangs(const QStringList &l);
|
||||
static const QStringList & getPreferedLangs() { return preferredLangs; }
|
||||
static ContextEngine * create(QObject *parent);
|
||||
static ContextSettings * settings(QWidget *parent);
|
||||
|
||||
ContextEngine(QObject *p);
|
||||
virtual ~ContextEngine();
|
||||
|
||||
virtual const QStringList & getLangs()=0;
|
||||
void cancel();
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void search(const QStringList &query, Mode mode)=0;
|
||||
|
||||
Q_SIGNALS:
|
||||
void searchResult(const QString &html, const QString &lang);
|
||||
|
||||
protected:
|
||||
QNetworkReply * getReply(QObject *obj);
|
||||
|
||||
protected:
|
||||
static QStringList preferredLangs;
|
||||
QNetworkReply *job;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -231,7 +231,6 @@ void SongView::update(const Song &s, bool force)
|
||||
|
||||
if (s.isEmpty()) {
|
||||
currentSong=s;
|
||||
View::cancel();
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
248
context/view.cpp
248
context/view.cpp
@@ -24,7 +24,6 @@
|
||||
#include "view.h"
|
||||
#include "spinner.h"
|
||||
#include "networkaccessmanager.h"
|
||||
#include "settings.h"
|
||||
#include <QLabel>
|
||||
#include <QTextBrowser>
|
||||
#include <QImage>
|
||||
@@ -33,13 +32,10 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QLocale>
|
||||
|
||||
const QLatin1String View::constAmbiguous("-");
|
||||
|
||||
View::View(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, needToUpdate(false)
|
||||
, spinner(0)
|
||||
, job(0)
|
||||
{
|
||||
QVBoxLayout *layout=new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||
@@ -60,7 +56,6 @@ View::View(QWidget *parent)
|
||||
layout->addItem(new QSpacerItem(1, fontMetrics().height()/4, QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||
text->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setEditable(false);
|
||||
locale=Settings::self()->wikipediaLocale();
|
||||
}
|
||||
|
||||
void View::clear()
|
||||
@@ -134,248 +129,9 @@ void View::setEditable(bool e)
|
||||
text->viewport()->setAutoFillBackground(e);
|
||||
}
|
||||
|
||||
void View::searchResponse(const QString &r)
|
||||
void View::searchResponse(const QString &r, const QString &l)
|
||||
{
|
||||
Q_UNUSED(l)
|
||||
text->setText(r);
|
||||
}
|
||||
|
||||
void View::cancel()
|
||||
{
|
||||
if (job) {
|
||||
disconnect(job, SIGNAL(finished()), this, SLOT(googleAnswer()));
|
||||
job->deleteLater();
|
||||
job=0;
|
||||
}
|
||||
}
|
||||
|
||||
void View::search(const QString &query)
|
||||
{
|
||||
cancel();
|
||||
if (query.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QUrl url("http://www.google.com/search?as_q="+query+"&ft=i&num=1&as_qdr=all&pws=0&as_sitesearch="+locale+".wikipedia.org");
|
||||
|
||||
QNetworkRequest request(url);
|
||||
QString lang(QLocale::languageToString(QLocale::system().language()));
|
||||
request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; Linux i686; rv:6.0) Gecko/20100101 Firefox/6.0");
|
||||
if (!lang.isEmpty()) {
|
||||
request.setRawHeader("Accept-Language", lang.toAscii());
|
||||
}
|
||||
job = NetworkAccessManager::self()->get(request);
|
||||
connect(job, SIGNAL(finished()), this, SLOT(googleAnswer()));
|
||||
}
|
||||
|
||||
void View::googleAnswer()
|
||||
{
|
||||
QNetworkReply *reply=qobject_cast<QNetworkReply *>(sender());
|
||||
|
||||
if (!reply) {
|
||||
return;
|
||||
}
|
||||
reply->deleteLater();
|
||||
if (reply!=job) {
|
||||
return;
|
||||
}
|
||||
job=0;
|
||||
if (reply->error()) {
|
||||
searchResponse(QString());
|
||||
return;
|
||||
}
|
||||
|
||||
QString answer(QString::fromUtf8(reply->readAll()));
|
||||
int start = answer.indexOf("<h3");
|
||||
if (start > -1) {
|
||||
start = answer.indexOf("href=\"", start) + 6;
|
||||
start = answer.indexOf("http", start);
|
||||
int end = answer.indexOf("\"", start);
|
||||
end = qMin(end, answer.indexOf("&", start));
|
||||
answer = answer.mid(start, end - start);
|
||||
// For "Queensrÿche" google returns http://en.wikipedia.org/wiki/Queensr%25C3%25BFche
|
||||
// ...but (I think) this should be http://en.wikipedia.org/wiki/Queensr%C3%BFche
|
||||
// ...so, replace %25 with % :-)
|
||||
answer.replace("%25", "%");
|
||||
}
|
||||
else {
|
||||
answer.clear();
|
||||
}
|
||||
|
||||
if (!answer.contains("wikipedia.org")) {
|
||||
searchResponse(QString());
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
QUrl wiki;
|
||||
wiki.setEncodedUrl(answer.replace("/wiki/", "/wiki/Special:Export/").toUtf8());
|
||||
job = NetworkAccessManager::self()->get(wiki);
|
||||
job->setProperty("redirect", 0);
|
||||
connect(job, SIGNAL(finished()), this, SLOT(wikiAnswer()));
|
||||
}
|
||||
|
||||
static QString strip(const QString &string, QString open, QString close, QString inner=QString())
|
||||
{
|
||||
QString result;
|
||||
int next, /*lastLeft, */left = 0;
|
||||
int pos = string.indexOf(open);
|
||||
|
||||
if (pos < 0) {
|
||||
return string;
|
||||
}
|
||||
|
||||
if (inner.isEmpty()) {
|
||||
inner = open;
|
||||
}
|
||||
|
||||
while (pos > -1) {
|
||||
result += string.mid(left, pos - left);
|
||||
// lastLeft = left;
|
||||
left = string.indexOf(close, pos);
|
||||
if (left < 0) { // opens, but doesn't close
|
||||
break;
|
||||
} else {
|
||||
next = pos;
|
||||
while (next > -1 && left > -1) {
|
||||
// search for inner iterations
|
||||
int count = 0;
|
||||
int lastNext = next;
|
||||
while ((next = string.indexOf(inner, next+inner.length())) < left && next > -1) {
|
||||
// count inner section openers
|
||||
lastNext = next;
|
||||
++count;
|
||||
}
|
||||
next = lastNext; // set back next to last inside opener for next iteration
|
||||
|
||||
if (!count) { // no inner sections, skip
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i) { // shift section closers by inside section amount
|
||||
left = string.indexOf(close, left+close.length());
|
||||
}
|
||||
// "continue" - search for next inner section
|
||||
}
|
||||
|
||||
if (left < 0) { // section does not close, skip here
|
||||
break;
|
||||
}
|
||||
|
||||
left += close.length(); // extend close to next search start
|
||||
}
|
||||
|
||||
if (left < 0) { // section does not close, skip here
|
||||
break;
|
||||
}
|
||||
|
||||
pos = string.indexOf(open, left); // search next 1st level section opener
|
||||
}
|
||||
|
||||
if (left > -1) { // append last part
|
||||
result += string.mid(left);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void View::wikiAnswer()
|
||||
{
|
||||
static const int constMaxRedirects=3;
|
||||
QNetworkReply *reply=qobject_cast<QNetworkReply *>(sender());
|
||||
|
||||
if (!reply) {
|
||||
return;
|
||||
}
|
||||
reply->deleteLater();
|
||||
if (reply!=job) {
|
||||
return;
|
||||
}
|
||||
job=0;
|
||||
|
||||
QVariant redirect = reply->header(QNetworkRequest::LocationHeader);
|
||||
int numRirects=reply->property("redirect").toInt();
|
||||
if (redirect.isValid() && ++numRirects<constMaxRedirects) {
|
||||
job=NetworkAccessManager::self()->get(redirect.toString());
|
||||
job->setProperty("redirect", numRirects);
|
||||
connect(job, SIGNAL(finished()), this, SLOT(wikiAnswer()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply->error()) {
|
||||
searchResponse(QString());
|
||||
return;
|
||||
}
|
||||
|
||||
QString answer(QString::fromUtf8(reply->readAll()));
|
||||
if (answer.contains(QLatin1String("{{disambiguation}}"))) {
|
||||
searchResponse(constAmbiguous);
|
||||
return;
|
||||
}
|
||||
|
||||
int start = answer.indexOf('>', answer.indexOf("<text")) + 1;
|
||||
int end = answer.lastIndexOf(QRegExp("\\n[^\\n]*\\n\\{\\{reflist", Qt::CaseInsensitive));
|
||||
if (end < start) {
|
||||
end = INT_MAX;
|
||||
}
|
||||
int e = answer.lastIndexOf(QRegExp("\\n[^\\n]*\\n<references", Qt::CaseInsensitive));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
e = answer.lastIndexOf(QRegExp("\n==\\s*Sources\\s*=="));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
e = answer.lastIndexOf(QRegExp("\n==\\s*Notes\\s*=="));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
e = answer.lastIndexOf(QRegExp("\n==\\s*References\\s*=="));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
e = answer.lastIndexOf(QRegExp("\n==\\s*External links\\s*=="));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
if (end < start) {
|
||||
end = answer.lastIndexOf("</text");
|
||||
}
|
||||
|
||||
answer = answer.mid(start, end - start); // strip header/footer
|
||||
answer = strip(answer, "{{", "}}"); // strip wiki internal stuff
|
||||
answer.replace("<", "<").replace(">", ">");
|
||||
answer = strip(answer, "<!--", "-->"); // strip comments
|
||||
answer.remove(QRegExp("<ref[^>]*/>")); // strip inline refereces
|
||||
answer = strip(answer, "<ref", "</ref>", "<ref"); // strip refereces
|
||||
// answer = strip(answer, "<ref ", "</ref>", "<ref"); // strip argumented refereces
|
||||
answer = strip(answer, "[[File:", "]]", "[["); // strip images etc
|
||||
answer = strip(answer, "[[Image:", "]]", "[["); // strip images etc
|
||||
|
||||
answer.replace(QRegExp("\\[\\[[^\\[\\]]*\\|([^\\[\\]\\|]*)\\]\\]"), "\\1"); // collapse commented links
|
||||
answer.replace("[['", "[["); // Fixes '74 (e.g. 1974) causing errors!
|
||||
answer.remove("[[").remove("]]"); // remove wiki link "tags"
|
||||
|
||||
answer = answer.trimmed();
|
||||
|
||||
// answer.replace(QRegExp("\\n\\{\\|[^\\n]*wikitable[^\\n]*\\n!"), "\n<table><th>");
|
||||
|
||||
answer.replace("\n\n", "<br>");
|
||||
// answer.replace("\n\n", "</p><p align=\"justify\">");
|
||||
answer.replace(QRegExp("\\n'''([^\\n]*)'''\\n"), "<hr><b>\\1</b>\n");
|
||||
answer.replace(QRegExp("\\n\\{\\|[^\\n]*\\n"), "\n");
|
||||
answer.replace(QRegExp("\\n\\|[^\\n]*\\n"), "\n");
|
||||
answer.replace("\n*", "<br>");
|
||||
answer.replace("\n", "");
|
||||
answer.replace("'''", "¬").replace(QRegExp("¬([^¬]*)¬"), "<b>\\1</b>");
|
||||
answer.replace("''", "¬").replace(QRegExp("¬([^¬]*)¬"), "<i>\\1</i>");
|
||||
answer.replace("===", "¬").replace(QRegExp("¬([^¬]*)¬"), "<h3>\\1</h3>");
|
||||
answer.replace("==", "¬").replace(QRegExp("¬([^¬]*)¬"), "<h2>\\1</h2>");
|
||||
answer.replace("&nbsp;", " ");
|
||||
answer.replace("<br><h", "<h");
|
||||
answer.replace("</h2><br>", "</h2>");
|
||||
answer.replace("</h3><br>", "</h3>");
|
||||
answer.replace("<h3>=", "<h4>");
|
||||
answer.replace("</h3>=", "</h4>");
|
||||
answer.replace("br>;", "br>");
|
||||
answer.replace("h2>;", "h2>");
|
||||
answer.replace("h3>;", "h3>");
|
||||
searchResponse(answer);
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@ class View : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const QLatin1String constAmbiguous;
|
||||
|
||||
View(QWidget *p);
|
||||
|
||||
void clear();
|
||||
@@ -52,20 +50,12 @@ public:
|
||||
void showSpinner();
|
||||
void hideSpinner();
|
||||
void setEditable(bool e);
|
||||
|
||||
virtual void update(const Song &s, bool force)=0;
|
||||
virtual void searchResponse(const QString &r);
|
||||
void search(const QString &query);
|
||||
|
||||
protected Q_SLOTS:
|
||||
virtual void searchResponse(const QString &r, const QString &l);
|
||||
|
||||
protected:
|
||||
void cancel();
|
||||
|
||||
private Q_SLOTS:
|
||||
void googleAnswer();
|
||||
void wikiAnswer();
|
||||
|
||||
protected:
|
||||
QString locale;
|
||||
Song currentSong;
|
||||
QString stdHeader;
|
||||
QLabel *header;
|
||||
@@ -74,7 +64,6 @@ protected:
|
||||
bool needToUpdate;
|
||||
QSize picSize;
|
||||
Spinner *spinner;
|
||||
QNetworkReply *job;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
447
context/wikipediaengine.cpp
Normal file
447
context/wikipediaengine.cpp
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Cantata
|
||||
*
|
||||
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "wikipediaengine.h"
|
||||
#include "networkaccessmanager.h"
|
||||
#include "localize.h"
|
||||
#include "settings.h"
|
||||
#include <QNetworkReply>
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QUrlQuery>
|
||||
#endif
|
||||
#include <QXmlStreamReader>
|
||||
#include <QRegExp>
|
||||
#include <QDebug>
|
||||
|
||||
static const char * constModeProperty="mode";
|
||||
static const char * constLangProperty="lang";
|
||||
static const char * constRedirectsProperty="redirects";
|
||||
static const char * constQueryProperty="query";
|
||||
static const int constMaxRedirects=3;
|
||||
|
||||
static QString strip(const QString &string, QString open, QString close, QString inner=QString())
|
||||
{
|
||||
QString result;
|
||||
int next, /*lastLeft, */left = 0;
|
||||
int pos = string.indexOf(open);
|
||||
|
||||
if (pos < 0) {
|
||||
return string;
|
||||
}
|
||||
|
||||
if (inner.isEmpty()) {
|
||||
inner = open;
|
||||
}
|
||||
|
||||
while (pos > -1) {
|
||||
result += string.mid(left, pos - left);
|
||||
// lastLeft = left;
|
||||
left = string.indexOf(close, pos);
|
||||
if (left < 0) { // opens, but doesn't close
|
||||
break;
|
||||
} else {
|
||||
next = pos;
|
||||
while (next > -1 && left > -1) {
|
||||
// search for inner iterations
|
||||
int count = 0;
|
||||
int lastNext = next;
|
||||
while ((next = string.indexOf(inner, next+inner.length())) < left && next > -1) {
|
||||
// count inner section openers
|
||||
lastNext = next;
|
||||
++count;
|
||||
}
|
||||
next = lastNext; // set back next to last inside opener for next iteration
|
||||
|
||||
if (!count) { // no inner sections, skip
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i) { // shift section closers by inside section amount
|
||||
left = string.indexOf(close, left+close.length());
|
||||
}
|
||||
// "continue" - search for next inner section
|
||||
}
|
||||
|
||||
if (left < 0) { // section does not close, skip here
|
||||
break;
|
||||
}
|
||||
|
||||
left += close.length(); // extend close to next search start
|
||||
}
|
||||
|
||||
if (left < 0) { // section does not close, skip here
|
||||
break;
|
||||
}
|
||||
|
||||
pos = string.indexOf(open, left); // search next 1st level section opener
|
||||
}
|
||||
|
||||
if (left > -1) { // append last part
|
||||
result += string.mid(left);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static QString wikiToHtml(QString answer)
|
||||
{
|
||||
int start = answer.indexOf('>', answer.indexOf("<text")) + 1;
|
||||
int end = answer.lastIndexOf(QRegExp("\\n[^\\n]*\\n\\{\\{reflist", Qt::CaseInsensitive));
|
||||
if (end < start) {
|
||||
end = INT_MAX;
|
||||
}
|
||||
int e = answer.lastIndexOf(QRegExp("\\n[^\\n]*\\n<references", Qt::CaseInsensitive));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
e = answer.lastIndexOf(QRegExp("\n==\\s*Sources\\s*=="));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
e = answer.lastIndexOf(QRegExp("\n==\\s*Notes\\s*=="));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
e = answer.lastIndexOf(QRegExp("\n==\\s*References\\s*=="));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
e = answer.lastIndexOf(QRegExp("\n==\\s*External links\\s*=="));
|
||||
if (e > start && e < end) {
|
||||
end = e;
|
||||
}
|
||||
if (end < start) {
|
||||
end = answer.lastIndexOf("</text");
|
||||
}
|
||||
|
||||
answer = answer.mid(start, end - start); // strip header/footer
|
||||
answer = strip(answer, "{{", "}}"); // strip wiki internal stuff
|
||||
answer.replace("<", "<").replace(">", ">");
|
||||
answer = strip(answer, "<!--", "-->"); // strip comments
|
||||
answer.remove(QRegExp("<ref[^>]*/>")); // strip inline refereces
|
||||
answer = strip(answer, "<ref", "</ref>", "<ref"); // strip refereces
|
||||
// answer = strip(answer, "<ref ", "</ref>", "<ref"); // strip argumented refereces
|
||||
answer = strip(answer, "[[File:", "]]", "[["); // strip images etc
|
||||
answer = strip(answer, "[[Image:", "]]", "[["); // strip images etc
|
||||
|
||||
answer.replace(QRegExp("\\[\\[[^\\[\\]]*\\|([^\\[\\]\\|]*)\\]\\]"), "\\1"); // collapse commented links
|
||||
answer.replace("[['", "[["); // Fixes '74 (e.g. 1974) causing errors!
|
||||
answer.remove("[[").remove("]]"); // remove wiki link "tags"
|
||||
|
||||
answer = answer.trimmed();
|
||||
|
||||
// answer.replace(QRegExp("\\n\\{\\|[^\\n]*wikitable[^\\n]*\\n!"), "\n<table><th>");
|
||||
|
||||
answer.replace("\n\n", "<br>");
|
||||
// answer.replace("\n\n", "</p><p align=\"justify\">");
|
||||
answer.replace(QRegExp("\\n'''([^\\n]*)'''\\n"), "<hr><b>\\1</b>\n");
|
||||
answer.replace(QRegExp("\\n\\{\\|[^\\n]*\\n"), "\n");
|
||||
answer.replace(QRegExp("\\n\\|[^\\n]*\\n"), "\n");
|
||||
answer.replace("\n*", "<br>");
|
||||
answer.replace("\n", "");
|
||||
answer.replace("'''", "¬").replace(QRegExp("¬([^¬]*)¬"), "<b>\\1</b>");
|
||||
answer.replace("''", "¬").replace(QRegExp("¬([^¬]*)¬"), "<i>\\1</i>");
|
||||
answer.replace("===", "¬").replace(QRegExp("¬([^¬]*)¬"), "<h3>\\1</h3>");
|
||||
answer.replace("==", "¬").replace(QRegExp("¬([^¬]*)¬"), "<h2>\\1</h2>");
|
||||
answer.replace("&nbsp;", " ");
|
||||
answer.replace("<br><h", "<h");
|
||||
answer.replace("</h2><br>", "</h2>");
|
||||
answer.replace("</h3><br>", "</h3>");
|
||||
answer.replace("<h3>=", "<h4>");
|
||||
answer.replace("</h3>=", "</h4>");
|
||||
answer.replace("br>;", "br>");
|
||||
answer.replace("h2>;", "h2>");
|
||||
answer.replace("h3>;", "h3>");
|
||||
return answer;
|
||||
}
|
||||
|
||||
QStringList WikipediaEngine::preferredLangs;
|
||||
|
||||
WikipediaEngine::WikipediaEngine(QObject *p)
|
||||
: ContextEngine(p)
|
||||
{
|
||||
if (preferredLangs.isEmpty()) {
|
||||
setPreferedLangs(Settings::self()->wikipediaLangs());
|
||||
}
|
||||
}
|
||||
|
||||
void WikipediaEngine::setPreferedLangs(const QStringList &l)
|
||||
{
|
||||
preferredLangs=l;
|
||||
if (preferredLangs.isEmpty()) {
|
||||
preferredLangs.append("en");
|
||||
}
|
||||
}
|
||||
|
||||
void WikipediaEngine::search(const QStringList &query, Mode mode)
|
||||
{
|
||||
titles.clear();
|
||||
requestTitles(query, mode, preferredLangs.first());
|
||||
}
|
||||
|
||||
void WikipediaEngine::requestTitles(const QStringList &query, Mode mode, const QString &lang)
|
||||
{
|
||||
cancel();
|
||||
QUrl url("https://"+lang+".wikipedia.org/w/api.php");
|
||||
#if QT_VERSION < 0x050000
|
||||
QUrl &q=url;
|
||||
#else
|
||||
QUrlQuery q;
|
||||
#endif
|
||||
|
||||
q.addQueryItem(QLatin1String("action"), QLatin1String("query"));
|
||||
q.addQueryItem(QLatin1String("list"), QLatin1String("search"));
|
||||
q.addQueryItem(QLatin1String("srsearch"), query.join(" "));
|
||||
q.addQueryItem(QLatin1String("srprop"), QLatin1String("size") );
|
||||
q.addQueryItem(QLatin1String("srredirects"), QString::number(1));
|
||||
q.addQueryItem(QLatin1String("srlimit"), QString::number(20));
|
||||
q.addQueryItem(QLatin1String("format"), QLatin1String("xml"));
|
||||
#if QT_VERSION >= 0x050000
|
||||
url.setQuery(q);
|
||||
#endif
|
||||
|
||||
job=NetworkAccessManager::self()->get(url);
|
||||
job->setProperty(constModeProperty, (int)mode);
|
||||
job->setProperty(constLangProperty, lang);
|
||||
job->setProperty(constRedirectsProperty, 0);
|
||||
job->setProperty(constQueryProperty, query);
|
||||
qWarning() << "XXX requestTitles:" << url.toString();
|
||||
connect(job, SIGNAL(finished()), this, SLOT(parseTitles()));
|
||||
}
|
||||
|
||||
void WikipediaEngine::parseTitles()
|
||||
{
|
||||
QNetworkReply *reply = getReply(sender());
|
||||
if (!reply) {
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data=reply->readAll();
|
||||
if (QNetworkReply::NoError!=reply->error() || data.isEmpty()) {
|
||||
emit searchResult(QString(), QString());
|
||||
return;
|
||||
}
|
||||
|
||||
QString hostLang = reply->property(constLangProperty).toString();
|
||||
QStringList query = reply->property(constQueryProperty).toStringList();
|
||||
Mode mode=(Mode)reply->property(constModeProperty).toInt();
|
||||
QXmlStreamReader xml(data);
|
||||
|
||||
while (!xml.atEnd() && !xml.hasError()) {
|
||||
xml.readNext();
|
||||
if (xml.isStartElement() && QLatin1String("search")==xml.name()) {
|
||||
while (xml.readNextStartElement()) {
|
||||
if (QLatin1String("p")==xml.name()) {
|
||||
if (xml.attributes().hasAttribute(QLatin1String("title"))) {
|
||||
titles << xml.attributes().value(QLatin1String("title")).toString();
|
||||
}
|
||||
xml.skipCurrentElement();
|
||||
} else {
|
||||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (titles.isEmpty()) {
|
||||
QStringList refinePossibleLangs = preferredLangs.filter(QRegExp("^(en|fr|de|pl).*$") );
|
||||
int index = refinePossibleLangs.indexOf(hostLang);
|
||||
if (-1!=index && index<refinePossibleLangs.count()-1) {
|
||||
// Try next language!
|
||||
requestTitles(query, mode, refinePossibleLangs.value(index + 1).split(QLatin1Char(':')).back());
|
||||
} else {
|
||||
emit searchResult(QString(), QString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
getPage(query, mode, hostLang);
|
||||
}
|
||||
|
||||
static int indexOf(const QStringList &l, const QString &s)
|
||||
{
|
||||
for (int i=0; i<l.length(); ++i){
|
||||
qWarning() << "COMPARE" << l.at(i) << s << l.at(i).compare(s, Qt::CaseInsensitive);
|
||||
if (0==l.at(i).compare(s, Qt::CaseInsensitive)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void WikipediaEngine::getPage(const QStringList &query, Mode mode, const QString &lang)
|
||||
{
|
||||
QStringList queryCopy(query);
|
||||
QStringList queries;
|
||||
|
||||
while(!queryCopy.isEmpty()) {
|
||||
queries.append(queryCopy.join(" "));
|
||||
queryCopy.takeFirst();
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Amarok original - not working for me :-(
|
||||
qWarning() << "XXX Titles:" << titles;
|
||||
QString basePattern;
|
||||
switch (mode)
|
||||
{
|
||||
default:
|
||||
case Artist:
|
||||
basePattern=i18nc("Search pattern for an artist or band", ".*\\(.*(artist|band).*\\))").toLatin1();
|
||||
break;
|
||||
case Album:
|
||||
basePattern=i18nc("Search pattern for an album", ".*\\(.*(album|score|soundtrack).*\\)").toLatin1();
|
||||
break;
|
||||
}
|
||||
|
||||
int index=-1;
|
||||
foreach (const QString &q, queries) {
|
||||
QString pattern=q+basePattern;
|
||||
index = titles.indexOf(QRegExp(pattern, Qt::CaseInsensitive));
|
||||
qWarning() << "XXX Query[a]:" << q << pattern << index;
|
||||
if (-1==index) {
|
||||
QString q2=q;
|
||||
q2.remove(".");
|
||||
pattern=q2+basePattern;
|
||||
index = titles.indexOf(QRegExp(pattern, Qt::CaseInsensitive));
|
||||
qWarning() << "XXX Query[b]:" << q2 << pattern << index;
|
||||
}
|
||||
if (-1!=index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
QStringList patterns;
|
||||
switch (mode)
|
||||
{
|
||||
default:
|
||||
case Artist:
|
||||
patterns=i18nc("Search pattern for an artist or band, separated by |", "artist|band").split("|", QString::SkipEmptyParts);
|
||||
break;
|
||||
case Album:
|
||||
patterns=i18nc("Search pattern for an album, separated by |", "album|score|soundtrack").split("|", QString::SkipEmptyParts);
|
||||
break;
|
||||
}
|
||||
|
||||
qWarning() << "XXX Titles:" << titles;
|
||||
int index=-1;
|
||||
foreach (const QString &q, queries) {
|
||||
qWarning() << "XXX Query:" << q;
|
||||
qWarning() << "XXX - patterns";
|
||||
// First check original query with one of the patterns...
|
||||
foreach (const QString &pattern, patterns) {
|
||||
index=indexOf(titles, q+" ("+pattern+")");
|
||||
if (-1!=index) {
|
||||
qWarning() << "XXX match[a]" << index << q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (-1==index && q.contains(".")) {
|
||||
qWarning() << "XXX - patterns (no dots)";
|
||||
// Now try by removing all dots (A.S.A.P. -> ASAP)
|
||||
QString query2=q;
|
||||
query2.remove(".");
|
||||
foreach (const QString &pattern, patterns) {
|
||||
index=indexOf(titles, query2+" ("+pattern+")");
|
||||
if (-1!=index) {
|
||||
qWarning() << "XXX match[b]" << index << q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-1==index) {
|
||||
// Try without any pattern...
|
||||
qWarning() << "XXX - no pattern";
|
||||
index=indexOf(titles, q);
|
||||
if (-1!=index) {
|
||||
qWarning() << "XXX match[c]" << index << q;
|
||||
}
|
||||
}
|
||||
|
||||
if (-1==index && q.contains(".")) {
|
||||
// Try without any pattern, and no dots..
|
||||
qWarning() << "XXX - no pattern no dots";
|
||||
QString query2=q;
|
||||
query2.remove(".");
|
||||
index=indexOf(titles, query2);
|
||||
if (-1!=index) {
|
||||
qWarning() << "XXX match[d]" << index << q;
|
||||
}
|
||||
}
|
||||
if (-1!=index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// TODO: If we fail to find a match, prompt user???
|
||||
const QString title=titles.takeAt(-1==index ? 0 : index);
|
||||
QUrl url;
|
||||
url.setScheme(QLatin1String("https"));
|
||||
url.setHost(lang+".wikipedia.org");
|
||||
url.setPath("/wiki/Special:Export/"+title);
|
||||
job=NetworkAccessManager::self()->get(url);
|
||||
job->setProperty(constModeProperty, (int)mode);
|
||||
job->setProperty(constLangProperty, lang);
|
||||
job->setProperty(constQueryProperty, query);
|
||||
job->setProperty(constRedirectsProperty, 0);
|
||||
qWarning() << "XXX getPage:" << url.toString();
|
||||
connect(job, SIGNAL(finished()), this, SLOT(parsePage()));
|
||||
}
|
||||
|
||||
void WikipediaEngine::parsePage()
|
||||
{
|
||||
QNetworkReply *reply = getReply(sender());
|
||||
if (!reply) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant redirect = reply->header(QNetworkRequest::LocationHeader);
|
||||
int numRirects=reply->property(constRedirectsProperty).toInt();
|
||||
if (redirect.isValid() && ++numRirects<constMaxRedirects) {
|
||||
job=NetworkAccessManager::self()->get(redirect.toString());
|
||||
job->setProperty(constRedirectsProperty, numRirects);
|
||||
job->setProperty(constLangProperty, reply->property(constLangProperty));
|
||||
job->setProperty(constModeProperty, reply->property(constModeProperty));
|
||||
job->setProperty(constQueryProperty, reply->property(constQueryProperty));
|
||||
connect(job, SIGNAL(finished()), this, SLOT(parsePage()));
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data=reply->readAll();
|
||||
if (QNetworkReply::NoError!=reply->error() || data.isEmpty()) {
|
||||
emit searchResult(QString(), QString());
|
||||
return;
|
||||
}
|
||||
|
||||
QString answer(QString::fromUtf8(data));
|
||||
qWarning() << "XXX ANS:" << answer;
|
||||
if (answer.contains(QLatin1String("{{disambiguation}}")) || answer.contains(QLatin1String("{{disambig}}"))) { // i18n???
|
||||
getPage(reply->property(constQueryProperty).toStringList(), (Mode)reply->property(constModeProperty).toInt(),
|
||||
reply->property(constLangProperty).toString());
|
||||
return;
|
||||
}
|
||||
|
||||
emit searchResult(wikiToHtml(answer), reply->property(constLangProperty).toString());
|
||||
}
|
||||
273
context/wikipediasettings.cpp
Normal file
273
context/wikipediasettings.cpp
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Cantata
|
||||
*
|
||||
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "wikipediasettings.h"
|
||||
#include "wikipediaengine.h"
|
||||
#include "networkaccessmanager.h"
|
||||
#include "localize.h"
|
||||
#include "icon.h"
|
||||
#include "spinner.h"
|
||||
#include "settings.h"
|
||||
#include "qtiocompressor/qtiocompressor.h"
|
||||
#include "utils.h"
|
||||
#include <QNetworkReply>
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QUrlQuery>
|
||||
#endif
|
||||
#include <QXmlStreamReader>
|
||||
#include <QFile>
|
||||
|
||||
static QString localeFile() {
|
||||
return Utils::configDir(QString(), true)+"wikipedia-langs.xml.gz";
|
||||
}
|
||||
|
||||
WikipediaSettings::WikipediaSettings(QWidget *p)
|
||||
: ContextSettings(p)
|
||||
, needToUpdate(true)
|
||||
, job(0)
|
||||
, spinner(0)
|
||||
{
|
||||
setupUi(this);
|
||||
connect(upButton, SIGNAL(clicked()), SLOT(moveUp()));
|
||||
connect(downButton, SIGNAL(clicked()), SLOT(moveDown()));
|
||||
connect(reload, SIGNAL(clicked()), SLOT(getLangs()));
|
||||
connect(addButton, SIGNAL(clicked()), SLOT(add()));
|
||||
connect(removeButton, SIGNAL(clicked()), SLOT(remove()));
|
||||
connect(langs, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(currentLangChanged(QListWidgetItem*)));
|
||||
connect(preferredLangs, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(currentPreferredLangChanged(QListWidgetItem*)));
|
||||
upButton->setIcon(Icon("go-up"));
|
||||
downButton->setIcon(Icon("go-down"));
|
||||
addButton->setIcon(Icon("list-add"));
|
||||
removeButton->setIcon(Icon("list-remove"));
|
||||
|
||||
upButton->setEnabled(false);
|
||||
downButton->setEnabled(false);
|
||||
addButton->setEnabled(false);
|
||||
removeButton->setEnabled(false);
|
||||
}
|
||||
|
||||
void WikipediaSettings::showEvent(QShowEvent *e)
|
||||
{
|
||||
if (needToUpdate) {
|
||||
needToUpdate=false;
|
||||
QByteArray data;
|
||||
QString fileName=localeFile();
|
||||
if (QFile::exists(fileName)) {
|
||||
QFile f(fileName);
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::ReadOnly)) {
|
||||
data=compressor.readAll();
|
||||
}
|
||||
}
|
||||
|
||||
if (data.isEmpty()) {
|
||||
getLangs();
|
||||
} else {
|
||||
parseLangs(data);
|
||||
}
|
||||
}
|
||||
QWidget::showEvent(e);
|
||||
}
|
||||
|
||||
void WikipediaSettings::load()
|
||||
{
|
||||
}
|
||||
|
||||
void WikipediaSettings::save()
|
||||
{
|
||||
QStringList pref;
|
||||
for (int i=0; i<preferredLangs->count(); ++i) {
|
||||
pref.append(preferredLangs->item(i)->data(Qt::UserRole).toString());
|
||||
}
|
||||
if (pref.isEmpty()) {
|
||||
pref.append("en");
|
||||
}
|
||||
Settings::self()->saveWikipediaLangs(pref);
|
||||
}
|
||||
|
||||
void WikipediaSettings::cancel()
|
||||
{
|
||||
if (job) {
|
||||
disconnect(job, SIGNAL(finished()), this, SLOT(parseLangs()));
|
||||
job->deleteLater();
|
||||
job=0;
|
||||
}
|
||||
}
|
||||
|
||||
void WikipediaSettings::getLangs()
|
||||
{
|
||||
if (!spinner) {
|
||||
spinner=new Spinner(langs);
|
||||
spinner->setWidget(langs);
|
||||
}
|
||||
spinner->start();
|
||||
langs->clear();
|
||||
preferredLangs->clear();
|
||||
reload->setEnabled(false);
|
||||
cancel();
|
||||
QUrl url("https://en.wikipedia.org/w/api.php");
|
||||
#if QT_VERSION < 0x050000
|
||||
QUrl &q=url;
|
||||
#else
|
||||
QUrlQuery q;
|
||||
#endif
|
||||
|
||||
q.addQueryItem(QLatin1String("action"), QLatin1String("query"));
|
||||
q.addQueryItem(QLatin1String("meta"), QLatin1String("siteinfo"));
|
||||
q.addQueryItem(QLatin1String("siprop"), QLatin1String("interwikimap"));
|
||||
q.addQueryItem(QLatin1String("sifilteriw"), QLatin1String("local"));
|
||||
q.addQueryItem(QLatin1String("format"), QLatin1String("xml"));
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
url.setQuery(q);
|
||||
#endif
|
||||
|
||||
job=NetworkAccessManager::self()->get(url);
|
||||
connect(job, SIGNAL(finished()), this, SLOT(parseLangs()));
|
||||
}
|
||||
|
||||
void WikipediaSettings::parseLangs()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||
if (!reply) {
|
||||
return;
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
if (reply!=job) {
|
||||
return;
|
||||
}
|
||||
job=0;
|
||||
parseLangs(reply->readAll());
|
||||
}
|
||||
|
||||
void WikipediaSettings::parseLangs(const QByteArray &data)
|
||||
{
|
||||
QStringList preferred=WikipediaEngine::getPreferedLangs();
|
||||
QXmlStreamReader xml(data);
|
||||
QMap<int, QListWidgetItem *> prefMap;
|
||||
|
||||
while (!xml.atEnd() && !xml.hasError()) {
|
||||
xml.readNext();
|
||||
if( xml.isStartElement() && QLatin1String("iw")==xml.name()) {
|
||||
const QXmlStreamAttributes &a = xml.attributes();
|
||||
if (a.hasAttribute(QLatin1String("prefix")) && a.hasAttribute(QLatin1String("language")) && a.hasAttribute(QLatin1String("url"))) {
|
||||
// The urlPrefix is the lang code infront of the wikipedia host
|
||||
// url. It is mostly the same as the "prefix" attribute but in
|
||||
// some weird cases they differ, so we can't just use "prefix".
|
||||
QString prefix=QUrl(a.value(QLatin1String("url")).toString()).host().remove(QLatin1String(".wikipedia.org"));
|
||||
int index=preferred.indexOf(prefix);
|
||||
QListWidgetItem *item = new QListWidgetItem(-1==index ? langs : preferredLangs);
|
||||
item->setText(QString("[%1] %2").arg(a.value(QLatin1String("prefix")).toString()).arg(a.value(QLatin1String("language")).toString()));
|
||||
item->setData(Qt::UserRole, prefix);
|
||||
if (-1!=index) {
|
||||
prefMap[index]=item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMap<int, QListWidgetItem *>::ConstIterator it(prefMap.constBegin());
|
||||
QMap<int, QListWidgetItem *>::ConstIterator end(prefMap.constEnd());
|
||||
for (; it!=end; ++it) {
|
||||
int row=preferredLangs->row(it.value());
|
||||
if (row!=it.key()) {
|
||||
preferredLangs->insertItem(it.key(), preferredLangs->takeItem(row));
|
||||
}
|
||||
}
|
||||
QFile f(localeFile());
|
||||
QtIOCompressor compressor(&f);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (compressor.open(QIODevice::WriteOnly)) {
|
||||
compressor.write(data);
|
||||
}
|
||||
|
||||
reload->setEnabled(true);
|
||||
if (spinner) {
|
||||
spinner->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void WikipediaSettings::currentLangChanged(QListWidgetItem *item)
|
||||
{
|
||||
addButton->setEnabled(item);
|
||||
}
|
||||
|
||||
void WikipediaSettings::currentPreferredLangChanged(QListWidgetItem *item)
|
||||
{
|
||||
if (!item) {
|
||||
upButton->setEnabled(false);
|
||||
downButton->setEnabled(false);
|
||||
removeButton->setEnabled(false);
|
||||
} else {
|
||||
const int row = langs->row(item);
|
||||
upButton->setEnabled(row != 0);
|
||||
downButton->setEnabled(row != langs->count() - 1);
|
||||
}
|
||||
removeButton->setEnabled(item);
|
||||
}
|
||||
|
||||
void WikipediaSettings::moveUp()
|
||||
{
|
||||
move(-1);
|
||||
}
|
||||
|
||||
void WikipediaSettings::moveDown()
|
||||
{
|
||||
move(+1);
|
||||
}
|
||||
|
||||
void WikipediaSettings::add()
|
||||
{
|
||||
int index=langs->currentRow();
|
||||
if (index<0 || index>langs->count()) {
|
||||
return;
|
||||
}
|
||||
QListWidgetItem *item = langs->takeItem(index);
|
||||
QListWidgetItem *newItem=new QListWidgetItem(preferredLangs);
|
||||
newItem->setText(item->text());
|
||||
newItem->setData(Qt::UserRole, item->data(Qt::UserRole));
|
||||
delete item;
|
||||
}
|
||||
|
||||
void WikipediaSettings::remove()
|
||||
{
|
||||
int index=preferredLangs->currentRow();
|
||||
if (index<0 || index>preferredLangs->count()) {
|
||||
return;
|
||||
}
|
||||
QListWidgetItem *item = preferredLangs->takeItem(index);
|
||||
QListWidgetItem *newItem=new QListWidgetItem(langs);
|
||||
newItem->setText(item->text());
|
||||
newItem->setData(Qt::UserRole, item->data(Qt::UserRole));
|
||||
delete item;
|
||||
}
|
||||
|
||||
void WikipediaSettings::move(int d)
|
||||
{
|
||||
const int row = preferredLangs->currentRow();
|
||||
QListWidgetItem *item = preferredLangs->takeItem(row);
|
||||
preferredLangs->insertItem(row + d, item);
|
||||
preferredLangs->setCurrentRow(row + d);
|
||||
}
|
||||
66
context/wikipediasettings.h
Normal file
66
context/wikipediasettings.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Cantata
|
||||
*
|
||||
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef WIKIPEDIA_SETTINGS_H
|
||||
#define WIKIPEDIA_SETTINGS_H
|
||||
|
||||
#include "contextengine.h"
|
||||
#include "ui_wikipediasettings.h"
|
||||
|
||||
class QNetworkReply;
|
||||
class QShowEvent;
|
||||
class Spinner;
|
||||
|
||||
class WikipediaSettings : public ContextSettings, private Ui::WikipediaSettings
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WikipediaSettings(QWidget *p);
|
||||
|
||||
void load();
|
||||
void save();
|
||||
void cancel();
|
||||
void showEvent(QShowEvent *e);
|
||||
|
||||
private Q_SLOTS:
|
||||
void getLangs();
|
||||
void parseLangs();
|
||||
void moveUp();
|
||||
void moveDown();
|
||||
void move(int d);
|
||||
void add();
|
||||
void remove();
|
||||
void currentLangChanged(QListWidgetItem *item);
|
||||
void currentPreferredLangChanged(QListWidgetItem *item);
|
||||
|
||||
private:
|
||||
void parseLangs(const QByteArray &data);
|
||||
|
||||
private:
|
||||
bool needToUpdate;
|
||||
QNetworkReply *job;
|
||||
Spinner *spinner;
|
||||
};
|
||||
|
||||
#endif
|
||||
164
context/wikipediasettings.ui
Normal file
164
context/wikipediasettings.ui
Normal file
@@ -0,0 +1,164 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>WikipediaSettings</class>
|
||||
<widget class="QWidget" name="WikipediaSettings">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>437</width>
|
||||
<height>362</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Choose the wikipedia languages you want to use when searching for artist and album information.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Available:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Selected:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" rowspan="6">
|
||||
<widget class="QListWidget" name="langs">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>74</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="2" rowspan="6">
|
||||
<widget class="QListWidget" name="preferredLangs">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3" rowspan="2">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>89</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1" rowspan="2">
|
||||
<widget class="QToolButton" name="addButton">
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3" rowspan="2">
|
||||
<widget class="QToolButton" name="upButton">
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" rowspan="2">
|
||||
<widget class="QToolButton" name="removeButton">
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="3">
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>73</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="6" column="3">
|
||||
<widget class="QToolButton" name="downButton">
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>73</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QPushButton" name="reload">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>langs</tabstop>
|
||||
<tabstop>addButton</tabstop>
|
||||
<tabstop>removeButton</tabstop>
|
||||
<tabstop>preferredLangs</tabstop>
|
||||
<tabstop>upButton</tabstop>
|
||||
<tabstop>downButton</tabstop>
|
||||
<tabstop>reload</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -33,6 +33,7 @@
|
||||
#ifdef TAGLIB_FOUND
|
||||
#include "httpserversettings.h"
|
||||
#endif
|
||||
#include "contextengine.h"
|
||||
#include "lyricsettings.h"
|
||||
#include "cachesettings.h"
|
||||
#include "localize.h"
|
||||
@@ -66,6 +67,7 @@ PreferencesDialog::PreferencesDialog(QWidget *parent)
|
||||
playback = new PlaybackSettings(widget);
|
||||
files = new FileSettings(widget);
|
||||
interface = new InterfaceSettings(widget);
|
||||
context = ContextEngine::settings(widget);
|
||||
lyrics = new LyricSettings(widget);
|
||||
cache = new CacheSettings(widget);
|
||||
server->load();
|
||||
@@ -89,6 +91,8 @@ PreferencesDialog::PreferencesDialog(QWidget *parent)
|
||||
http=0;
|
||||
}
|
||||
#endif
|
||||
widget->addPage(context, i18n("Context"), Icons::contextIcon, i18n("Context View Settings"));
|
||||
context->load();
|
||||
widget->addPage(lyrics, i18n("Lyrics"), Icons::lyricsIcon, i18n("Lyrics Settings"));
|
||||
#if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND
|
||||
audiocd = new AudioCdSettings(widget);
|
||||
@@ -140,6 +144,7 @@ void PreferencesDialog::writeSettings()
|
||||
#if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND
|
||||
audiocd->save();
|
||||
#endif
|
||||
context->save();
|
||||
lyrics->save();
|
||||
Settings::self()->save();
|
||||
emit settingsSaved();
|
||||
|
||||
@@ -36,6 +36,7 @@ class ServerPlaybackSettings;
|
||||
class PlaybackSettings;
|
||||
class FileSettings;
|
||||
class InterfaceSettings;
|
||||
class ContextSettings;
|
||||
class LyricSettings;
|
||||
#ifdef TAGLIB_FOUND
|
||||
class HttpServerSettings;
|
||||
@@ -73,6 +74,7 @@ private:
|
||||
PlaybackSettings *playback;
|
||||
FileSettings *files;
|
||||
InterfaceSettings *interface;
|
||||
ContextSettings *context;
|
||||
LyricSettings *lyrics;
|
||||
#ifdef TAGLIB_FOUND
|
||||
HttpServerSettings *http;
|
||||
|
||||
@@ -452,9 +452,10 @@ QStringList Settings::lyricProviders()
|
||||
return GET_STRINGLIST("lyricProviders", def);
|
||||
}
|
||||
|
||||
QString Settings::wikipediaLocale()
|
||||
QStringList Settings::wikipediaLangs()
|
||||
{
|
||||
return GET_STRING("wikipediaLocale", "en");
|
||||
QStringList def=QStringList() << "en";
|
||||
return GET_STRINGLIST("wikipediaLangs", def);
|
||||
}
|
||||
|
||||
|
||||
@@ -857,9 +858,9 @@ void Settings::saveLyricProviders(const QStringList &v)
|
||||
SET_VALUE_MOD(lyricProviders)
|
||||
}
|
||||
|
||||
void Settings::saveWikipediaLocale(const QString &v)
|
||||
void Settings::saveWikipediaLangs(const QStringList &v)
|
||||
{
|
||||
SET_VALUE_MOD(wikipediaLocale)
|
||||
SET_VALUE_MOD(wikipediaLangs)
|
||||
}
|
||||
|
||||
void Settings::savePage(const QString &v)
|
||||
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
bool groupSingle();
|
||||
bool groupMultiple();
|
||||
QStringList lyricProviders();
|
||||
QString wikipediaLocale();
|
||||
QStringList wikipediaLangs();
|
||||
QString page();
|
||||
QStringList hiddenPages();
|
||||
bool gnomeMediaKeys();
|
||||
@@ -204,7 +204,7 @@ public:
|
||||
void saveGroupSingle(bool v);
|
||||
void saveGroupMultiple(bool v);
|
||||
void saveLyricProviders(const QStringList &v);
|
||||
void saveWikipediaLocale(const QString &v);
|
||||
void saveWikipediaLangs(const QStringList &v);
|
||||
void savePage(const QString &v);
|
||||
void saveHiddenPages(const QStringList &v);
|
||||
void saveGnomeMediaKeys(bool v);
|
||||
|
||||
@@ -331,6 +331,7 @@ Icon Icons::streamsIcon;
|
||||
#ifdef ENABLE_ONLINE_SERVICES
|
||||
Icon Icons::onlineIcon;
|
||||
#endif
|
||||
Icon Icons::contextIcon;
|
||||
Icon Icons::lyricsIcon;
|
||||
Icon Icons::infoIcon;
|
||||
#ifdef ENABLE_DEVICES_SUPPORT
|
||||
@@ -626,9 +627,19 @@ void Icons::initToolbarIcons(const QColor &color, bool forceLight)
|
||||
QColor col=QApplication::palette().color(QPalette::Active, QPalette::ButtonText);
|
||||
infoIcon=loadSidebarIcon("info", col, col);
|
||||
}
|
||||
|
||||
if (infoIcon.isNull()) {
|
||||
infoIcon=Icon("dialog-information");
|
||||
}
|
||||
|
||||
#if !defined ENABLE_KDE_SUPPORT && !defined Q_OS_WIN
|
||||
if (QIcon::themeName()==QLatin1String("gnome")) {
|
||||
QColor col=QApplication::palette().color(QPalette::Active, QPalette::ButtonText);
|
||||
contextIcon=loadSidebarIcon("info", col, col);
|
||||
} else
|
||||
#endif
|
||||
contextIcon=Icon("dialog-information");
|
||||
|
||||
if (toolbarPrevIcon.isNull()) {
|
||||
toolbarPrevIcon=Icon::getMediaIcon("media-skip-backward");
|
||||
} else {
|
||||
|
||||
@@ -77,6 +77,7 @@ namespace Icons
|
||||
#ifdef ENABLE_ONLINE_SERVICES
|
||||
extern Icon onlineIcon;
|
||||
#endif
|
||||
extern Icon contextIcon;
|
||||
extern Icon lyricsIcon;
|
||||
extern Icon infoIcon;
|
||||
#ifdef ENABLE_DEVICES_SUPPORT
|
||||
|
||||
Reference in New Issue
Block a user