mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-06 14:16:32 +02:00
Add completion for artists with echonest artist/suggest path
This commit is contained in:
@@ -26,6 +26,8 @@
|
|||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include "EchonestGenerator.h"
|
#include "EchonestGenerator.h"
|
||||||
|
#include <qcompleter.h>
|
||||||
|
#include <qstringlistmodel.h>
|
||||||
|
|
||||||
|
|
||||||
Tomahawk::EchonestControl::EchonestControl( const QString& selectedType, const QStringList& typeSelectors, QObject* parent )
|
Tomahawk::EchonestControl::EchonestControl( const QString& selectedType, const QStringList& typeSelectors, QObject* parent )
|
||||||
@@ -146,6 +148,8 @@ Tomahawk::EchonestControl::updateWidgets()
|
|||||||
|
|
||||||
input->setPlaceholderText( "Artist name" );
|
input->setPlaceholderText( "Artist name" );
|
||||||
input->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Fixed );
|
input->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Fixed );
|
||||||
|
input->setCompleter( new QCompleter( QStringList(), input ) );
|
||||||
|
input->completer()->setCaseSensitivity( Qt::CaseInsensitive );
|
||||||
|
|
||||||
connect( match, SIGNAL( currentIndexChanged(int) ), this, SLOT( updateData() ) );
|
connect( match, SIGNAL( currentIndexChanged(int) ), this, SLOT( updateData() ) );
|
||||||
connect( match, SIGNAL( currentIndexChanged(int) ), this, SIGNAL( changed() ) );
|
connect( match, SIGNAL( currentIndexChanged(int) ), this, SIGNAL( changed() ) );
|
||||||
@@ -153,6 +157,7 @@ Tomahawk::EchonestControl::updateWidgets()
|
|||||||
connect( input, SIGNAL( editingFinished() ), this, SLOT( editingFinished() ) );
|
connect( input, SIGNAL( editingFinished() ), this, SLOT( editingFinished() ) );
|
||||||
connect( input, SIGNAL( textEdited( QString ) ), &m_editingTimer, SLOT( stop() ) );
|
connect( input, SIGNAL( textEdited( QString ) ), &m_editingTimer, SLOT( stop() ) );
|
||||||
connect( input, SIGNAL( textEdited( QString ) ), &m_delayedEditTimer, SLOT( start() ) );
|
connect( input, SIGNAL( textEdited( QString ) ), &m_delayedEditTimer, SLOT( start() ) );
|
||||||
|
connect( input, SIGNAL( textEdited( QString ) ), this, SLOT( artistTextEdited( QString ) ) );
|
||||||
|
|
||||||
match->hide();
|
match->hide();
|
||||||
input->hide();
|
input->hide();
|
||||||
@@ -552,6 +557,78 @@ Tomahawk::EchonestControl::editTimerFired()
|
|||||||
m_cacheData = m_data.second;
|
m_cacheData = m_data.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Tomahawk::EchonestControl::artistTextEdited( const QString& text )
|
||||||
|
{
|
||||||
|
// if the user is editing an artist field, try to help him out and suggest from echonest
|
||||||
|
QLineEdit* l = qobject_cast<QLineEdit*>( m_input.data() );
|
||||||
|
Q_ASSERT( l );
|
||||||
|
// l->setCompleter( new QCompleter( this ) ); // clear
|
||||||
|
|
||||||
|
foreach( QNetworkReply* r, m_suggestWorkers ) {
|
||||||
|
r->abort();
|
||||||
|
r->deleteLater();
|
||||||
|
}
|
||||||
|
m_suggestWorkers.clear();
|
||||||
|
|
||||||
|
if( !text.isEmpty() ) {
|
||||||
|
if( m_suggestCache.contains( text ) ) {
|
||||||
|
addArtistSuggestions( m_suggestCache[ text ] );
|
||||||
|
} else { // gotta look it up
|
||||||
|
QNetworkReply* r = Echonest::Artist::suggest( text );
|
||||||
|
qDebug() << "Asking echonest for suggestions to help our completion..." << r->url().toString();
|
||||||
|
r->setProperty( "curtext", text );
|
||||||
|
|
||||||
|
m_suggestWorkers.insert( r );
|
||||||
|
connect( r, SIGNAL( finished() ), this, SLOT( suggestFinished() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Tomahawk::EchonestControl::suggestFinished()
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
|
||||||
|
Q_ASSERT( r );
|
||||||
|
QLineEdit* l = qobject_cast<QLineEdit*>( m_input.data() );
|
||||||
|
Q_ASSERT( l );
|
||||||
|
|
||||||
|
m_suggestWorkers.remove( r );
|
||||||
|
|
||||||
|
if( r->error() != QNetworkReply::NoError )
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString origText = r->property( "curtext" ).toString();
|
||||||
|
if( origText != l->text() ) { // user might have kept on typing, then ignore
|
||||||
|
qDebug() << "Text changed meanwhile, stopping suggestion parsing";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList suggestions;
|
||||||
|
try {
|
||||||
|
Echonest::Artists artists = Echonest::Artist::parseSuggest( r );
|
||||||
|
foreach( const Echonest::Artist& artist, artists )
|
||||||
|
suggestions << artist.name();
|
||||||
|
} catch( Echonest::ParseError& e ) {
|
||||||
|
qWarning() << "libechonest failed to parse this artist/suggest call..." << e.errorType() << e.what();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_suggestCache[ origText ] = suggestions;
|
||||||
|
addArtistSuggestions( suggestions );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Tomahawk::EchonestControl::addArtistSuggestions( const QStringList& suggestions )
|
||||||
|
{
|
||||||
|
// if the user is editing an artist field, try to help him out and suggest from echonest
|
||||||
|
QLineEdit* l = qobject_cast<QLineEdit*>( m_input.data() );
|
||||||
|
Q_ASSERT( l );
|
||||||
|
|
||||||
|
l->completer()->setModel( new QStringListModel( suggestions, l->completer() ) );
|
||||||
|
l->completer()->complete();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Tomahawk::EchonestControl::calculateSummary()
|
Tomahawk::EchonestControl::calculateSummary()
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
*
|
*
|
||||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
*
|
*
|
||||||
* Tomahawk is free software: you can redistribute it and/or modify
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
@@ -26,65 +26,73 @@
|
|||||||
|
|
||||||
namespace Tomahawk
|
namespace Tomahawk
|
||||||
{
|
{
|
||||||
|
|
||||||
class EchonestControl : public DynamicControl
|
class EchonestControl : public DynamicControl
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
virtual QWidget* inputField();
|
virtual QWidget* inputField();
|
||||||
virtual QWidget* matchSelector();
|
virtual QWidget* matchSelector();
|
||||||
|
|
||||||
/// Converts this to an echonest suitable parameter
|
/// Converts this to an echonest suitable parameter
|
||||||
Echonest::DynamicPlaylist::PlaylistParamData toENParam() const;
|
Echonest::DynamicPlaylist::PlaylistParamData toENParam() const;
|
||||||
|
|
||||||
virtual QString input() const;
|
virtual QString input() const;
|
||||||
virtual QString match() const;
|
virtual QString match() const;
|
||||||
virtual QString matchString() const;
|
virtual QString matchString() const;
|
||||||
virtual QString summary() const;
|
virtual QString summary() const;
|
||||||
|
|
||||||
virtual void setInput(const QString& input);
|
virtual void setInput(const QString& input);
|
||||||
virtual void setMatch(const QString& match);
|
virtual void setMatch(const QString& match);
|
||||||
|
|
||||||
/// DO NOT USE IF YOU ARE NOT A DBCMD
|
/// DO NOT USE IF YOU ARE NOT A DBCMD
|
||||||
EchonestControl( const QString& type, const QStringList& typeSelectors, QObject* parent = 0 );
|
EchonestControl( const QString& type, const QStringList& typeSelectors, QObject* parent = 0 );
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void setSelectedType ( const QString& type );
|
virtual void setSelectedType ( const QString& type );
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateData();
|
void updateData();
|
||||||
void editingFinished();
|
void editingFinished();
|
||||||
void editTimerFired();
|
void editTimerFired();
|
||||||
|
|
||||||
|
void artistTextEdited( const QString& );
|
||||||
|
void suggestFinished();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateWidgets();
|
void updateWidgets();
|
||||||
void updateWidgetsFromData();
|
void updateWidgetsFromData();
|
||||||
|
|
||||||
// utility
|
// utility
|
||||||
void setupMinMaxWidgets( Echonest::DynamicPlaylist::PlaylistParam min, Echonest::DynamicPlaylist::PlaylistParam max, const QString& leftL, const QString& rightL, int maxRange );
|
void setupMinMaxWidgets( Echonest::DynamicPlaylist::PlaylistParam min, Echonest::DynamicPlaylist::PlaylistParam max, const QString& leftL, const QString& rightL, int maxRange );
|
||||||
void updateFromComboAndSlider( bool smooth = false );
|
void updateFromComboAndSlider( bool smooth = false );
|
||||||
void updateFromLabelAndCombo();
|
void updateFromLabelAndCombo();
|
||||||
|
|
||||||
void updateToComboAndSlider( bool smooth = false );
|
void updateToComboAndSlider( bool smooth = false );
|
||||||
void updateToLabelAndCombo();
|
void updateToLabelAndCombo();
|
||||||
|
|
||||||
|
void addArtistSuggestions( const QStringList& suggestions );
|
||||||
|
|
||||||
void calculateSummary();
|
void calculateSummary();
|
||||||
|
|
||||||
Echonest::DynamicPlaylist::PlaylistParam m_currentType;
|
Echonest::DynamicPlaylist::PlaylistParam m_currentType;
|
||||||
int m_overrideType;
|
int m_overrideType;
|
||||||
|
|
||||||
QWeakPointer< QWidget > m_input;
|
QWeakPointer< QWidget > m_input;
|
||||||
QWeakPointer< QWidget > m_match;
|
QWeakPointer< QWidget > m_match;
|
||||||
QString m_matchData;
|
QString m_matchData;
|
||||||
QString m_matchString;
|
QString m_matchString;
|
||||||
QString m_summary;
|
QString m_summary;
|
||||||
|
|
||||||
QTimer m_editingTimer;
|
QTimer m_editingTimer;
|
||||||
QTimer m_delayedEditTimer;
|
QTimer m_delayedEditTimer;
|
||||||
|
|
||||||
Echonest::DynamicPlaylist::PlaylistParamData m_data;
|
Echonest::DynamicPlaylist::PlaylistParamData m_data;
|
||||||
QVariant m_cacheData;
|
QVariant m_cacheData;
|
||||||
|
|
||||||
|
QSet< QNetworkReply* > m_suggestWorkers;
|
||||||
|
QHash< QString, QStringList > m_suggestCache;
|
||||||
|
|
||||||
friend class EchonestGenerator;
|
friend class EchonestGenerator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user