1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-07-31 11:20:22 +02:00

* Added basic search widget.

This commit is contained in:
Christian Muehlhaeuser
2011-06-04 20:47:45 +02:00
parent 34d9a723dd
commit 2e9dc42696
15 changed files with 281 additions and 42 deletions

View File

@@ -122,6 +122,7 @@ SET( tomahawkUI ${tomahawkUI}
diagnosticsdialog.ui
stackedsettingsdialog.ui
proxydialog.ui
searchwidget.ui
audiocontrols.ui
)

View File

@@ -161,6 +161,7 @@ set( libSources
utils/xspfgenerator.cpp
widgets/newplaylistwidget.cpp
widgets/searchwidget.cpp
widgets/playlisttypeselectordlg.cpp
widgets/welcomewidget.cpp
widgets/welcomeplaylistmodel.cpp
@@ -325,6 +326,7 @@ set( libHeaders
utils/xspfgenerator.h
widgets/newplaylistwidget.h
widgets/searchwidget.h
widgets/playlisttypeselectordlg.h
widgets/welcomewidget.h
widgets/welcomeplaylistmodel.h
@@ -343,6 +345,7 @@ set( libHeaders_NoMOC
set( libUI ${libUI}
widgets/playlisttypeselectordlg.ui
widgets/newplaylistwidget.ui
widgets/searchwidget.ui
widgets/welcomewidget.ui
widgets/infowidgets/sourceinfowidget.ui
playlist/topbar/topbar.ui

View File

@@ -36,23 +36,35 @@ DatabaseCommand_Resolve::DatabaseCommand_Resolve( const query_ptr& query )
void
DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
{
QList<Tomahawk::result_ptr> res;
if ( !m_query->resultHint().isEmpty() )
{
qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
Tomahawk::result_ptr result = lib->resultFromHint( m_query );
/* qDebug() << "Result null:" << result.isNull();
qDebug() << "Collection null:" << result->collection().isNull();
qDebug() << "Source null:" << result->collection()->source().isNull();*/
/* qDebug() << "Result null:" << result.isNull();
* qDebug() << "Collection null:" << result->collection().isNull();
* qDebug() << "Source null:" << result->collection()->source().isNull();*/
if ( !result.isNull() && !result->collection().isNull() && result->collection()->source()->isOnline() )
{
QList<Tomahawk::result_ptr> res;
res << result;
emit results( m_query->id(), res );
return;
}
}
if ( m_query->isFullTextQuery() )
fullTextResolve( lib );
else
resolve( lib );
}
void
DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
{
QList<Tomahawk::result_ptr> res;
/*
Resolving is a 2 stage process.
1) find list of trk/art/alb IDs that are reasonable matches to the metadata given
@@ -67,7 +79,7 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
QList< int > tracks = lib->searchTable( "track", m_query->track(), 10 );
QList< int > albums = lib->searchTable( "album", m_query->album(), 10 );
if( artists.length() == 0 || tracks.length() == 0 )
if ( artists.length() == 0 || tracks.length() == 0 )
{
qDebug() << "No candidates found in first pass, aborting resolve" << m_query->artist() << m_query->track();
emit results( m_query->id(), res );
@@ -83,6 +95,9 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
foreach( int i, tracks )
trksl.append( QString::number( i ) );
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
QString sql = QString( "SELECT "
"url, mtime, size, md5, mimetype, duration, bitrate, file_join.artist, file_join.album, file_join.track, "
"artist.name as artname, "
@@ -98,10 +113,9 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
"artist.id = file_join.artist AND "
"track.id = file_join.track AND "
"file.id = file_join.file AND "
"file_join.artist IN (%1) AND "
"file_join.track IN (%2)" )
.arg( artsl.join( "," ) )
.arg( trksl.join( "," ) );
"(%1 AND %2)" )
.arg( artsToken )
.arg( trksToken );
files_query.prepare( sql );
files_query.exec();
@@ -160,7 +174,136 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
float score = how_similar( m_query, result );
result->setScore( score );
if( score < MINSCORE )
if ( m_query->fullTextQuery().isEmpty() && score < MINSCORE )
continue;
result->setCollection( s->collection() );
res << result;
}
emit results( m_query->id(), res );
}
void
DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
{
QList<Tomahawk::result_ptr> res;
/*
* Resolving is a 2 stage process.
* 1) find list of trk/art/alb IDs that are reasonable matches to the metadata given
* 2) find files in database by permitted sources and calculate score, ignoring
* results that are less than MINSCORE
*/
typedef QPair<int, float> scorepair_t;
// STEP 1
QList< int > artists = lib->searchTable( "artist", m_query->fullTextQuery(), 10 );
QList< int > tracks = lib->searchTable( "track", m_query->fullTextQuery(), 10 );
QList< int > albums = lib->searchTable( "album", m_query->fullTextQuery(), 10 );
if ( artists.length() == 0 && tracks.length() == 0 && albums.length() == 0 )
{
qDebug() << "No candidates found in first pass, aborting resolve" << m_query->artist() << m_query->track();
emit results( m_query->id(), res );
return;
}
// STEP 2
TomahawkSqlQuery files_query = lib->newquery();
QStringList artsl, trksl, albsl;
foreach( int i, artists )
artsl.append( QString::number( i ) );
foreach( int i, tracks )
trksl.append( QString::number( i ) );
foreach( int i, albums )
albsl.append( QString::number( i ) );
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
QString albsToken = QString( "file_join.album IN (%1)" ).arg( albsl.join( "," ) );
QString sql = QString( "SELECT "
"url, mtime, size, md5, mimetype, duration, bitrate, file_join.artist, file_join.album, file_join.track, "
"artist.name as artname, "
"album.name as albname, "
"track.name as trkname, "
"file.source, "
"file_join.albumpos, "
"artist.id as artid, "
"album.id as albid "
"FROM file, file_join, artist, track "
"LEFT JOIN album ON album.id = file_join.album "
"WHERE "
"artist.id = file_join.artist AND "
"track.id = file_join.track AND "
"file.id = file_join.file AND "
"(%1 OR %2 OR %3)" )
.arg( artists.length() > 0 ? artsToken : QString( "0" ) )
.arg( tracks.length() > 0 ? trksToken : QString( "0" ) )
.arg( albums.length() > 0 ? albsToken : QString( "0" ) );
files_query.prepare( sql );
files_query.exec();
while( files_query.next() )
{
Tomahawk::result_ptr result( new Tomahawk::Result() );
source_ptr s;
const QString url_str = files_query.value( 0 ).toString();
if( files_query.value( 13 ).toUInt() == 0 )
{
s = SourceList::instance()->getLocal();
result->setUrl( url_str );
}
else
{
s = SourceList::instance()->get( files_query.value( 13 ).toUInt() );
if( s.isNull() )
{
qDebug() << "WTF: Could not find source" << files_query.value( 13 ).toUInt();
continue;
}
result->setUrl( QString( "servent://%1\t%2" ).arg( s->userName() ).arg( url_str ) );
}
Tomahawk::artist_ptr artist = Tomahawk::Artist::get( files_query.value( 15 ).toUInt(), files_query.value( 10 ).toString() );
Tomahawk::album_ptr album = Tomahawk::Album::get( files_query.value( 16 ).toUInt(), files_query.value( 11 ).toString(), artist );
result->setModificationTime( files_query.value( 1 ).toUInt() );
result->setSize( files_query.value( 2 ).toUInt() );
result->setMimetype( files_query.value( 4 ).toString() );
result->setDuration( files_query.value( 5 ).toUInt() );
result->setBitrate( files_query.value( 6 ).toUInt() );
result->setArtist( artist );
result->setAlbum( album );
result->setTrack( files_query.value( 12 ).toString() );
result->setRID( uuid() );
result->setAlbumPos( files_query.value( 14 ).toUInt() );
result->setId( files_query.value( 9 ).toUInt() );
result->setYear( files_query.value( 17 ).toUInt() );
TomahawkSqlQuery attrQuery = lib->newquery();
QVariantMap attr;
attrQuery.prepare( "SELECT k, v FROM track_attributes WHERE id = ?" );
attrQuery.bindValue( 0, result->dbid() );
attrQuery.exec();
while ( attrQuery.next() )
{
attr[ attrQuery.value( 0 ).toString() ] = attrQuery.value( 1 ).toString();
}
result->setAttributes( attr );
float score = how_similar( m_query, result );
result->setScore( score );
if ( m_query->fullTextQuery().isEmpty() && score < MINSCORE )
continue;
result->setCollection( s->collection() );

View File

@@ -44,6 +44,9 @@ signals:
public slots:
private:
void fullTextResolve( DatabaseImpl* lib );
void resolve( DatabaseImpl* lib );
Tomahawk::query_ptr m_query;
float how_similar( const Tomahawk::query_ptr& q, const Tomahawk::result_ptr& r );

View File

@@ -190,7 +190,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
m_rids.insert( r->id(), r );
}
if ( q->solved() )
if ( q->solved() && !q->isFullTextQuery() )
{
// qDebug() << "FINISHED RESOLVING EARLY" << q->toString();
q->onResolvingFinished();
@@ -206,7 +206,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
if ( decQIDState( q ) == 0 )
{
if ( !q->solved() )
if ( !q->solved() || q->isFullTextQuery() )
q->onResolvingFinished();
if ( m_qidsTimeout.contains( q->id() ) )

View File

@@ -33,7 +33,7 @@
class ClearButton;
class SearchButton;
class SearchLineEdit : public LineEdit
class DLLEXPORT SearchLineEdit : public LineEdit
{
Q_OBJECT

View File

@@ -174,7 +174,7 @@ TrackProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParen
if ( q->numResults() )
r = q->results().first();
if ( !m_showOfflineResults && !r.isNull() && !r->collection()->source()->isOnline() )
if ( !m_showOfflineResults && !r.isNull() && !r->isOnline() )
return false;
if ( filterRegExp().isEmpty() )

View File

@@ -42,6 +42,17 @@ Query::get( const QString& artist, const QString& track, const QString& album, c
}
query_ptr
Query::get( const QString& query, const QID& qid )
{
query_ptr q = query_ptr( new Query( query, qid ) );
if ( !qid.isEmpty() )
Pipeline::instance()->resolve( q );
return q;
}
Query::Query( const QString& artist, const QString& track, const QString& album, const QID& qid )
: m_solved( false )
, m_playable( false )
@@ -59,6 +70,21 @@ Query::Query( const QString& artist, const QString& track, const QString& album,
}
Query::Query( const QString& query, const QID& qid )
: m_solved( false )
, m_playable( false )
, m_resolveFinished( false )
, m_qid( qid )
, m_fullTextQuery( query )
, m_duration( -1 )
{
if ( !qid.isEmpty() )
{
connect( Database::instance(), SIGNAL( indexReady() ), SLOT( refreshResults() ), Qt::QueuedConnection );
}
}
void
Query::addResults( const QList< Tomahawk::result_ptr >& newresults )
{

View File

@@ -46,7 +46,10 @@ friend class ::DatabaseCommand_LoadPlaylistEntries;
public:
static query_ptr get( const QString& artist, const QString& track, const QString& album, const QID& qid = QString() );
static query_ptr get( const QString& query, const QID& qid );
explicit Query( const QString& artist, const QString& track, const QString& album, const QID& qid );
explicit Query( const QString& query, const QID& qid );
/// returns list of all results so far
QList< result_ptr > results() const;
@@ -64,6 +67,7 @@ public:
/// true when any result has been found (score may be less than 1.0)
bool playable() const { return m_playable; }
bool isFullTextQuery() const { return !m_fullTextQuery.isEmpty(); }
bool resolvingFinished() const { return m_resolveFinished; }
unsigned int lastPipelineWeight() const { return m_lastpipelineweight; }
@@ -83,6 +87,7 @@ public:
QString artist() const { return m_artist; }
QString album() const { return m_album; }
QString track() const { return m_track; }
QString fullTextQuery() const { return m_fullTextQuery; }
int duration() const { return m_duration; }
signals:
@@ -118,6 +123,8 @@ private:
QString m_artist;
QString m_album;
QString m_track;
QString m_fullTextQuery;
int m_duration;
QString m_resultHint;

View File

@@ -630,6 +630,7 @@ ViewManager::setPage( ViewPage* page, bool trackHistory )
updateView();
}
bool
ViewManager::isNewPlaylistPageVisible() const
{

View File

@@ -125,11 +125,9 @@ NewPlaylistWidget::suggestionsFound()
m_suggestionsModel = new PlaylistModel( ui->suggestionsView );
ui->suggestionsView->setPlaylistModel( m_suggestionsModel );
QList<Tomahawk::query_ptr> ql;
foreach( const Tomahawk::query_ptr& query, m_queries )
{
m_suggestionsModel->append( query );
ql.append( query );
}
loader->deleteLater();

View File

@@ -75,11 +75,24 @@ QtScriptResolver::resolve( const Tomahawk::query_ptr& query )
}
// qDebug() << Q_FUNC_INFO << query->toString();
QString eval = QString( "resolve( '%1', '%2', '%3', '%4' );" )
QString eval;
if ( !query->isFullTextQuery() )
{
eval = QString( "resolve( '%1', '%2', '%3', '%4' );" )
.arg( query->id().replace( "'", "\\'" ) )
.arg( query->artist().replace( "'", "\\'" ) )
.arg( query->album().replace( "'", "\\'" ) )
.arg( query->track().replace( "'", "\\'" ) );
}
else
{
eval = QString( "resolve( '%1', '%2', '%3', '%4' );" )
.arg( query->id().replace( "'", "\\'" ) )
.arg( query->fullTextQuery().replace( "'", "\\'" ) )
.arg( QString() )
.arg( QString() );
}
QList< Tomahawk::result_ptr > results;

View File

@@ -208,12 +208,22 @@ ScriptResolver::resolve( const Tomahawk::query_ptr& query )
{
QVariantMap m;
m.insert( "_msgtype", "rq" );
if ( query->isFullTextQuery() )
{
m.insert( "fulltext", query->fullTextQuery() );
m.insert( "artist", query->artist() );
m.insert( "track", query->fullTextQuery() );
m.insert( "qid", query->id() );
}
else
{
m.insert( "artist", query->artist() );
m.insert( "track", query->track() );
m.insert( "qid", query->id() );
}
const QByteArray msg = m_serializer.serialize( QVariant( m ) );
// qDebug() << "ASKING SCRIPT RESOLVER TO RESOLVE:" << msg;
sendMsg( msg );
}

View File

@@ -18,6 +18,7 @@
#include "tomahawkwindow.h"
#include "ui_tomahawkwindow.h"
#include "ui_searchwidget.h"
#include "config.h"
@@ -28,6 +29,7 @@
#include <QInputDialog>
#include <QPixmap>
#include <QPropertyAnimation>
#include <QLineEdit>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
@@ -50,6 +52,7 @@
#include "utils/widgetdragfilter.h"
#include "utils/xspfloader.h"
#include "widgets/newplaylistwidget.h"
#include "widgets/searchwidget.h"
#include "widgets/playlisttypeselectordlg.h"
#include "audiocontrols.h"
@@ -74,6 +77,7 @@ using namespace Tomahawk;
TomahawkWindow::TomahawkWindow( QWidget* parent )
: QMainWindow( parent )
, ui( new Ui::TomahawkWindow )
, m_searchWidget( new Ui::SearchWidget )
, m_audioControls( new AudioControls( this ) )
, m_trayIcon( new TomahawkTrayIcon( this ) )
, m_sourcetree( 0 )
@@ -92,7 +96,9 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
connect( m_audioControls, SIGNAL( playPressed() ), pm, SLOT( onPlayClicked() ) );
connect( m_audioControls, SIGNAL( pausePressed() ), pm, SLOT( onPauseClicked() ) );
m_searchBox = new QWidget();
ui->setupUi( this );
m_searchWidget->setupUi( m_searchBox );
delete ui->sidebarWidget;
delete ui->playlistWidget;
@@ -186,6 +192,14 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
m_forwardAvailable = toolbar->addAction( QIcon( RESPATH "images/forward.png" ), tr( "Forward" ), ViewManager::instance(), SLOT( historyForward() ) );
m_forwardAvailable->setToolTip( tr( "Go forward one page" ) );
m_searchWidget->searchEdit->setStyleSheet( "QLineEdit { border: 1px solid gray; border-radius: 6px; margin-right: 2px; }" );
#ifdef Q_WS_MAC
ui->filterEdit->setAttribute( Qt::WA_MacShowFocusRect, 0 );
#endif
connect( m_searchWidget->searchEdit, SIGNAL( returnPressed() ), SLOT( onSearch() ) );
toolbar->addWidget( m_searchBox );
statusBar()->addPermanentWidget( m_audioControls, 1 );
// propagate sip menu
@@ -488,14 +502,17 @@ TomahawkWindow::createPlaylist()
PlaylistTypeSelectorDlg playlistSelectorDlg;
int successfulReturn = playlistSelectorDlg.exec();
if ( !playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn ) {
if ( !playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn )
{
// only show if none is shown yet
if( !ViewManager::instance()->isNewPlaylistPageVisible() ) {
if ( !ViewManager::instance()->isNewPlaylistPageVisible() )
{
ViewManager::instance()->show( new NewPlaylistWidget() );
}
} else if ( playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn ) {
}
else if ( playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn )
{
// create Auto Playlist
QString playlistName = playlistSelectorDlg.playlistName();
APP->mainWindow()->createAutomaticPlaylist( playlistName );
@@ -600,13 +617,23 @@ TomahawkWindow::checkForUpdates()
}
void
TomahawkWindow::onSearch()
{
ViewManager::instance()->show( new SearchWidget( m_searchWidget->searchEdit->text() ) );
m_searchWidget->searchEdit->setText( QString() );
}
void
TomahawkWindow::minimize()
{
if ( isMinimized() )
{
showNormal();
} else {
}
else
{
showMinimized();
}
}
@@ -618,7 +645,9 @@ TomahawkWindow::maximize()
if ( isMaximized() )
{
showNormal();
} else {
}
else
{
showMaximized();
}
}

View File

@@ -38,6 +38,7 @@ class TomahawkTrayIcon;
namespace Ui
{
class TomahawkWindow;
class SearchWidget;
}
class TomahawkWindow : public QMainWindow
@@ -88,6 +89,8 @@ private slots:
void onSipPluginAdded( SipPlugin* p );
void onSipPluginRemoved( SipPlugin* p );
void onSearch();
void minimize();
void maximize();
@@ -97,6 +100,8 @@ private:
void setupSignals();
Ui::TomahawkWindow* ui;
Ui::SearchWidget* m_searchWidget;
QWidget* m_searchBox;
AudioControls* m_audioControls;
TomahawkTrayIcon* m_trayIcon;
SourceTreeView* m_sourcetree;