diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5186ddd2b..6d12bff02 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,6 +39,7 @@ SET( tomahawkSources ${tomahawkSources} musicscanner.cpp shortcuthandler.cpp + globalactionmanager.cpp scanmanager.cpp tomahawkapp.cpp main.cpp @@ -81,6 +82,7 @@ SET( tomahawkHeaders ${tomahawkHeaders} musicscanner.h scanmanager.h shortcuthandler.h + globalactionmanager.h ) IF(LIBLASTFM_FOUND) diff --git a/src/globalactionmanager.cpp b/src/globalactionmanager.cpp new file mode 100644 index 000000000..db20bd663 --- /dev/null +++ b/src/globalactionmanager.cpp @@ -0,0 +1,341 @@ +/* + Copyright (C) 2011 Leo Franchi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "globalactionmanager.h" + +#include "utils/xspfloader.h" +#include "sourcelist.h" +#include "playlist/dynamic/GeneratorInterface.h" +#include "viewmanager.h" +#include "playlist/topbar/topbar.h" +#include "pipeline.h" +#include "database/localcollection.h" +#include "playlist/playlistview.h" + +#include +#include + +GlobalActionManager* GlobalActionManager::s_instance = 0; + +GlobalActionManager* +GlobalActionManager::instance() +{ + if( !s_instance ) + s_instance = new GlobalActionManager; + + return s_instance; +} + + +GlobalActionManager::GlobalActionManager( QObject* parent ) + : QObject( parent ) +{ + +} + +GlobalActionManager::~GlobalActionManager() +{} + +bool +GlobalActionManager::parseTomahawkLink( const QString& url ) +{ + if( url.contains( "tomahawk://" ) ) { + QString cmd = url.mid( 11 ); + qDebug() << "Parsing tomahawk link command" << cmd; + + QString cmdType = cmd.split( "/" ).first(); + QUrl u( cmd ); + + // for backwards compatibility + if( cmdType == "load" ) { + if( u.hasQueryItem( "xspf" ) ) { + QUrl xspf = QUrl::fromUserInput( u.queryItemValue( "xspf" ) ); + XSPFLoader* l = new XSPFLoader( true, this ); + qDebug() << "Loading spiff:" << xspf.toString(); + l->load( xspf ); + connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) ); + + return true; + } + } + + if( cmdType == "playlist" ) { + return handlePlaylistCommand( u ); + } else if( cmdType == "collection" ) { + return handleCollectionCommand( u ); + } else if( cmdType == "queue" ) { + return handleQueueCommand( u ); + } else if( cmdType == "station" ) { + return handleStationCommand( u ); + } else if( cmdType == "search" ) { + return handleSearchCommand( u ); + } else if( cmdType == "play" ) { + return handlePlayCommand( u ); + } else { + qDebug() << "Tomahawk link not supported, command not known!" << cmdType << u.path(); + return false; + } + } else { + qDebug() << "Not a tomahawk:// link!"; + return false; + } +} + +bool +GlobalActionManager::handlePlaylistCommand( const QUrl& url ) +{ + QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command + if( parts.isEmpty() ) { + qDebug() << "No specific playlist command:" << url.toString(); + return false; + } + + if( parts[ 0 ] == "import" ) { + if( !url.hasQueryItem( "xspf" ) ) { + qDebug() << "No xspf to load.."; + return false; + } + QUrl xspf = QUrl( url.queryItemValue( "xspf" ) ); + QString title = url.hasQueryItem( "title" ) ? url.queryItemValue( "title" ) : QString(); + XSPFLoader* l= new XSPFLoader( true, this ); + l->setOverrideTitle( title ); + l->load( xspf ); + connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) ); + + } else if( parts [ 0 ] == "new" ) { + if( !url.hasQueryItem( "title" ) ) { + qDebug() << "New playlist command needs a title..."; + return false; + } + Tomahawk::playlist_ptr pl = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), url.queryItemValue( "title" ), QString(), QString(), false ); + pl->createNewRevision( uuid(), pl->currentrevision(), QList< Tomahawk::plentry_ptr >() ); + ViewManager::instance()->show( pl ); + } else if( parts[ 0 ] == "add" ) { + if( !url.hasQueryItem( "playlistid" ) || !url.hasQueryItem( "track" ) || !url.hasQueryItem( "artist" ) ) { + qDebug() << "Add to playlist command needs playlistid, track, and artist..." << url.toString(); + return false; + } + // TODO implement. Let the user select what playlist to add to + return false; + } + + return false; +} + +bool +GlobalActionManager::handleCollectionCommand( const QUrl& url ) +{ + QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command + if( parts.isEmpty() ) { + qDebug() << "No specific collection command:" << url.toString(); + return false; + } + + if( parts[ 0 ] == "add" ) { + // TODO implement + } + + return false; +} + +bool +GlobalActionManager::handleQueueCommand( const QUrl& url ) +{ + QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command + if( parts.isEmpty() ) { + qDebug() << "No specific queue command:" << url.toString(); + return false; + } + + if( parts[ 0 ] == "add" ) { + if( parts.size() > 1 && parts[ 1 ] == "track" ) { + QPair< QString, QString > pair; + foreach( pair, url.queryItems() ) { + if( pair.first != "url" ) + continue; + QUrl track = QUrl::fromUserInput( pair.second ); + if( track.isLocalFile() ) { // it's local, so we see if it's in the DB and load it if so + // TODO + } else { // give it a web result hint + // TODO actually read the tags + QFileInfo info( track.path() ); + Tomahawk::query_ptr q = Tomahawk::Query::get( QString(), info.baseName(), QString() ); + q->setResultHint( track.toString() ); + Tomahawk::Pipeline::instance()->resolve( q, true ); + + ViewManager::instance()->queue()->model()->append( q ); + ViewManager::instance()->showQueue(); + } + return true; + } + } else { + qDebug() << "Only queue/add/track is support at the moment, got:" << parts; + return false; + } + } + + return false; +} + +bool +GlobalActionManager::handleSearchCommand( const QUrl& url ) +{ + // open the super collection and set this as the search filter + QStringList query; + if( url.hasQueryItem( "artist" ) ) + query << url.queryItemValue( "artist" ); + if( url.hasQueryItem( "album" ) ) + query << url.queryItemValue( "album" ); + if( url.hasQueryItem( "track" ) ) + query << url.queryItemValue( "track" ); + QString queryStr = query.join( " " ); + + if( queryStr.isEmpty() ) + return false; + + ViewManager::instance()->showSuperCollection(); + ViewManager::instance()->topbar()->setFilter( queryStr ); + return true; +} + +bool +GlobalActionManager::handleStationCommand( const QUrl& url ) +{ + QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command + if( parts.isEmpty() ) { + qDebug() << "No specific station command:" << url.toString(); + return false; + } + + if( parts[ 0 ] == "create" ) { + if( !url.hasQueryItem( "title" ) || !url.hasQueryItem( "type" ) ) { + qDebug() << "Station create command needs title and type..." << url.toString(); + return false; + } + QString title = url.queryItemValue( "title" ); + QString type = url.queryItemValue( "type" ); + Tomahawk::dynplaylist_ptr pl = Tomahawk::DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), title, QString(), QString(), Tomahawk::OnDemand, false, type ); + QList< Tomahawk::dyncontrol_ptr > controls; + QPair< QString, QString > param; + foreach( param, url.queryItems() ) { + if( param.first == "artist" ) { + Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist" ); + c->setInput( param.second ); + c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistRadioType ) ); + controls << c; + } /*else if( param.first == "hotttnesss" ) { TODO + Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist" ); + c->setInput( param.second ); + c->setMatch( 0 ); + controls << c; + } */ + } + pl->createNewRevision( uuid(), pl->currentrevision(), type, controls ); + return true; + } + + return false; +} + +bool +GlobalActionManager::handlePlayCommand( const QUrl& url ) +{ + QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command + if( parts.isEmpty() ) { + qDebug() << "No specific play command:" << url.toString(); + return false; + } + + if( parts[ 0 ] == "track" ) { + QPair< QString, QString > pair; + QString title, artist, album, urlStr; + foreach( pair, url.queryItems() ) { + if( pair.first == "track" ) + title = pair.second; + else if( pair.first == "artist" ) + artist = pair.second; + else if( pair.first == "album" ) + album = pair.second; + else if( pair.first == "url" ) + urlStr = pair.second; + } + Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album ); + if( !urlStr.isEmpty() ) + q->setResultHint( urlStr ); + Tomahawk::Pipeline::instance()->resolve( q, true ); + + // now we add it to the special "bookmarks" playlist, creating it if it doesn't exist. if nothing is playing, start playing the track + QSharedPointer< LocalCollection > col = SourceList::instance()->getLocal()->collection().dynamicCast< LocalCollection >(); + Tomahawk::playlist_ptr bookmarkpl = col->bookmarksPlaylist(); + if( bookmarkpl.isNull() ) { // create it and do the deed then + m_waitingToBookmark = q; + col->createBookmarksPlaylist(); + connect( col.data(), SIGNAL( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ), this, SLOT( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ) ); + } else { + doBookmark( bookmarkpl, q ); + } + + return true; + } + + return false; +} + +void +GlobalActionManager::bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl ) +{ + doBookmark( pl, m_waitingToBookmark ); +} + +void +GlobalActionManager::doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q ) +{ + Tomahawk::plentry_ptr e( new Tomahawk::PlaylistEntry ); + e->setGuid( uuid() ); + + if ( q->results().count() ) + e->setDuration( q->results().at( 0 )->duration() ); + else + e->setDuration( 0 ); + + e->setLastmodified( 0 ); + e->setAnnotation( "" ); // FIXME + e->setQuery( q ); + + pl->createNewRevision( uuid(), pl->currentrevision(), QList< Tomahawk::plentry_ptr >( pl->entries() ) << e ); + connect( pl.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( showPlaylist() ) ); + + m_toShow = pl; + m_waitingToBookmark.clear(); + + // if nothing is playing, lets start this + // TODO +// if( !AudioEngine::instance()->isPlaying() ) +} + +void +GlobalActionManager::showPlaylist() +{ + if( m_toShow.isNull() ) + return; + + ViewManager::instance()->show( m_toShow ); + + m_toShow.clear(); +} + diff --git a/src/globalactionmanager.h b/src/globalactionmanager.h new file mode 100644 index 000000000..d038b066d --- /dev/null +++ b/src/globalactionmanager.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2011 Leo Franchi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef GLOBALACTIONMANAGER_H +#define GLOBALACTIONMANAGER_H + +#include "playlist.h" + +#include +#include + +class GlobalActionManager : public QObject +{ + Q_OBJECT +public: + static GlobalActionManager* instance(); + virtual ~GlobalActionManager(); + +public slots: + bool parseTomahawkLink( const QString& link ); + +private slots: + void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl ); + void showPlaylist(); + +private: + explicit GlobalActionManager( QObject* parent = 0 ); + void doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q ); + + bool handlePlaylistCommand( const QUrl& url ); + bool handleCollectionCommand(const QUrl& url ); + bool handleQueueCommand(const QUrl& url ); + bool handleStationCommand(const QUrl& url ); + bool handleSearchCommand(const QUrl& url ); + bool handlePlayCommand(const QUrl& url ); + + Tomahawk::query_ptr m_waitingToBookmark; + Tomahawk::playlist_ptr m_toShow; + + static GlobalActionManager* s_instance; +}; + +#endif // GLOBALACTIONMANAGER_H diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 7d811569e..c15c598b2 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -21,6 +21,7 @@ set( libSources artist.cpp album.cpp collection.cpp + webcollection.cpp playlist.cpp resolver.cpp query.cpp @@ -37,6 +38,7 @@ set( libSources database/database.cpp database/fuzzyindex.cpp database/databasecollection.cpp + database/localcollection.cpp database/databaseworker.cpp database/databaseimpl.cpp database/databaseresolver.cpp @@ -65,7 +67,6 @@ set( libSources database/databasecommand_renameplaylist.cpp database/databasecommand_loadops.cpp database/databasecommand_updatesearchindex.cpp - database/databasecollection.cpp database/databasecommand_setdynamicplaylistrevision.cpp database/databasecommand_createdynamicplaylist.cpp database/databasecommand_loaddynamicplaylist.cpp @@ -174,6 +175,7 @@ set( libHeaders aclsystem.h collection.h + webcollection.h query.h resolver.h result.h @@ -222,6 +224,7 @@ set( libHeaders database/databasecommand_loadops.h database/databasecommand_updatesearchindex.h database/databasecollection.h + database/localcollection.h database/databasecommand_setdynamicplaylistrevision.h database/databasecommand_createdynamicplaylist.h database/databasecommand_loaddynamicplaylist.h diff --git a/src/libtomahawk/database/databasecommand_resolve.cpp b/src/libtomahawk/database/databasecommand_resolve.cpp index f6f2b1c42..7e474c06f 100644 --- a/src/libtomahawk/database/databasecommand_resolve.cpp +++ b/src/libtomahawk/database/databasecommand_resolve.cpp @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -41,7 +41,7 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) { qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint(); - Tomahawk::result_ptr result = lib->result( m_query->resultHint() ); + Tomahawk::result_ptr result = lib->resultFromHint( m_query ); if ( !result.isNull() && result->collection()->source()->isOnline() ) { res << result; diff --git a/src/libtomahawk/database/databasecommand_setplaylistrevision.cpp b/src/libtomahawk/database/databasecommand_setplaylistrevision.cpp index 62eec9d6e..cceced691 100644 --- a/src/libtomahawk/database/databasecommand_setplaylistrevision.cpp +++ b/src/libtomahawk/database/databasecommand_setplaylistrevision.cpp @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -60,7 +60,7 @@ DatabaseCommand_SetPlaylistRevision::postCommitHook() qDebug() << "Source has gone offline, not emitting to GUI."; return; } - + if ( m_localOnly ) return; @@ -149,6 +149,8 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib ) QString resultHint; if ( !e->query()->results().isEmpty() ) resultHint = e->query()->results().first()->url(); + else if ( !e->query()->resultHint().isEmpty() ) + resultHint = e->query()->resultHint(); adde.bindValue( 0, e->guid() ); adde.bindValue( 1, m_playlistguid ); diff --git a/src/libtomahawk/database/databaseimpl.cpp b/src/libtomahawk/database/databaseimpl.cpp index e052368f0..f18270948 100644 --- a/src/libtomahawk/database/databaseimpl.cpp +++ b/src/libtomahawk/database/databaseimpl.cpp @@ -528,8 +528,9 @@ DatabaseImpl::album( int id ) Tomahawk::result_ptr -DatabaseImpl::result( const QString& url ) +DatabaseImpl::resultFromHint( const Tomahawk::query_ptr& origquery ) { + QString url = origquery->resultHint(); TomahawkSqlQuery query = newquery(); Tomahawk::source_ptr s; Tomahawk::result_ptr res; @@ -552,7 +553,18 @@ DatabaseImpl::result( const QString& url ) else { // Q_ASSERT( false ); - qDebug() << "We don't support non-servent / non-file result-hints yet."; +// qDebug() << "We don't support non-servent / non-file result-hints yet."; + res = Tomahawk::result_ptr( new Tomahawk::Result() ); + s = SourceList::instance()->webSource(); + res->setUrl( url ); + res->setCollection( s->collection() ); + res->setRID( uuid() ); + res->setScore( 1.0 ); + res->setArtist( Tomahawk::artist_ptr( new Tomahawk::Artist( 0, origquery->artist() ) ) ); + res->setAlbum( Tomahawk::album_ptr( new Tomahawk::Album( 0, origquery->album(), res->artist() ) ) ); + res->setTrack( origquery->track() ); + res->setDuration( origquery->duration() ); + res->setFriendlySource( url ); return res; } diff --git a/src/libtomahawk/database/databaseimpl.h b/src/libtomahawk/database/databaseimpl.h index f3551b634..243f04edd 100644 --- a/src/libtomahawk/database/databaseimpl.h +++ b/src/libtomahawk/database/databaseimpl.h @@ -64,7 +64,7 @@ public: QVariantMap album( int id ); QVariantMap track( int id ); Tomahawk::result_ptr file( int fid ); - Tomahawk::result_ptr result( const QString& url ); + Tomahawk::result_ptr resultFromHint( const Tomahawk::query_ptr& query ); static bool scorepairSorter( const QPair& left, const QPair& right ) { diff --git a/src/libtomahawk/database/localcollection.cpp b/src/libtomahawk/database/localcollection.cpp new file mode 100644 index 000000000..f843870ed --- /dev/null +++ b/src/libtomahawk/database/localcollection.cpp @@ -0,0 +1,54 @@ +/* + Copyright (C) 2011 Leo Franchi + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#include "localcollection.h" +#include + +#define MAGIC_BOOKMARK_GUID "_bookmarkplaylist" + +LocalCollection::LocalCollection( const Tomahawk::source_ptr& source, QObject* parent ) + : DatabaseCollection( source, parent ) +{ + +} + +Tomahawk::playlist_ptr +LocalCollection::bookmarksPlaylist() +{ + return playlist( MAGIC_BOOKMARK_GUID ); +} + +void +LocalCollection::createBookmarksPlaylist() +{ + if( bookmarksPlaylist().isNull() ) { + Tomahawk::playlist_ptr p = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), MAGIC_BOOKMARK_GUID, tr( "Bookmarks" ), tr( "Saved tracks" ), QString(), false ); +// connect( p.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( loaded( Tomahawk::PlaylistRevision ) ), Qt::QueuedConnection ); + connect( p.data(), SIGNAL( created() ), this, SLOT( created() ), Qt::QueuedConnection ); + +// p->createNewRevision( uuid(), p->currentrevision(), QList< Tomahawk::plentry_ptr >() ); + } +} + +void +LocalCollection::created() +{ + emit bookmarkPlaylistCreated( bookmarksPlaylist() ); +} diff --git a/src/libtomahawk/database/localcollection.h b/src/libtomahawk/database/localcollection.h new file mode 100644 index 000000000..e9ebccf24 --- /dev/null +++ b/src/libtomahawk/database/localcollection.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2011 Leo Franchi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef LOCALCOLLECTION_H +#define LOCALCOLLECTION_H + +#include "databasecollection.h" +#include "dllmacro.h" +#include "playlist.h" + +class DLLEXPORT LocalCollection : public DatabaseCollection +{ + Q_OBJECT +public: + explicit LocalCollection( const Tomahawk::source_ptr& source, QObject* parent = 0 ); + + // gets the playlist used for storing stuff from the web, if it already exists. if the returned playlist + // is invalid ask to create and listen to the signal + Tomahawk::playlist_ptr bookmarksPlaylist(); + void createBookmarksPlaylist(); + +signals: + void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& p ); + +private slots: + void created(); + +}; + +#endif // LOCALCOLLECTION_H diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp index 5122f8260..5b6481a6f 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp +++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp @@ -30,7 +30,7 @@ using namespace Tomahawk; DynamicPlaylist::DynamicPlaylist(const Tomahawk::source_ptr& author, const QString& type ) - : Playlist(author) +: Playlist(author) { qDebug() << Q_FUNC_INFO << "JSON"; m_generator = geninterface_ptr( GeneratorFactory::create( type ) ); @@ -54,7 +54,7 @@ DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& src, bool shared, int lastmod, const QString& guid ) - : Playlist( src, currentrevision, title, info, creator, createdOn, shared, lastmod, guid ) +: Playlist( src, currentrevision, title, info, creator, createdOn, shared, lastmod, guid ) { qDebug() << "Creating Dynamic Playlist 1"; // TODO instantiate generator @@ -72,7 +72,7 @@ DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& author, const QString& type, GeneratorMode mode, bool shared ) - : Playlist ( author, guid, title, info, creator, shared ) +: Playlist ( author, guid, title, info, creator, shared ) { qDebug() << "Creating Dynamic Playlist 2"; m_generator = geninterface_ptr( GeneratorFactory::create( type ) ); @@ -113,15 +113,15 @@ DynamicPlaylist::setMode( int mode ) dynplaylist_ptr DynamicPlaylist::create( const Tomahawk::source_ptr& author, - const QString& guid, - const QString& title, - const QString& info, - const QString& creator, - GeneratorMode mode, - bool shared ) + const QString& guid, + const QString& title, + const QString& info, + const QString& creator, + GeneratorMode mode, + bool shared, + const QString& type +) { - // default generator - QString type = ""; dynplaylist_ptr dynplaylist = dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared ) ); DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist ); @@ -148,10 +148,10 @@ DynamicPlaylist::createNewRevision( const QString& newUuid ) // create a new revision that will be a static playlist, as it has entries void DynamicPlaylist::createNewRevision( const QString& newrev, - const QString& oldrev, - const QString& type, - const QList< dyncontrol_ptr>& controls, - const QList< plentry_ptr >& entries ) + const QString& oldrev, + const QString& type, + const QList< dyncontrol_ptr>& controls, + const QList< plentry_ptr >& entries ) { // get the newly added tracks QList< plentry_ptr > added = newEntries( entries ); @@ -162,29 +162,29 @@ DynamicPlaylist::createNewRevision( const QString& newrev, // no conflict resolution or partial updating for controls. all or nothing baby - // source making the change (local user in this case) - source_ptr author = SourceList::instance()->getLocal(); - // command writes new rev to DB and calls setRevision, which emits our signal - DatabaseCommand_SetDynamicPlaylistRevision* cmd = - new DatabaseCommand_SetDynamicPlaylistRevision( author, - guid(), - newrev, - oldrev, - orderedguids, - added, - entries, - type, - Static, - controls ); - Database::instance()->enqueue( QSharedPointer( cmd ) ); + // source making the change (local user in this case) + source_ptr author = SourceList::instance()->getLocal(); + // command writes new rev to DB and calls setRevision, which emits our signal + DatabaseCommand_SetDynamicPlaylistRevision* cmd = + new DatabaseCommand_SetDynamicPlaylistRevision( author, + guid(), + newrev, + oldrev, + orderedguids, + added, + entries, + type, + Static, + controls ); + Database::instance()->enqueue( QSharedPointer( cmd ) ); } // create a new revision that will be an ondemand playlist, as it has no entries void DynamicPlaylist::createNewRevision( const QString& newrev, - const QString& oldrev, - const QString& type, - const QList< dyncontrol_ptr>& controls ) + const QString& oldrev, + const QString& type, + const QList< dyncontrol_ptr>& controls ) { // can skip the entry stuff. just overwrite with new info source_ptr author = SourceList::instance()->getLocal(); @@ -237,7 +237,7 @@ DynamicPlaylist::loadRevision( const QString& rev ) bool ) ) ); } - Database::instance()->enqueue( QSharedPointer( cmd ) ); + Database::instance()->enqueue( QSharedPointer( cmd ) ); } bool @@ -257,8 +257,8 @@ DynamicPlaylist::reportCreated( const Tomahawk::dynplaylist_ptr& self ) Q_ASSERT( !author().isNull() ); Q_ASSERT( !author()->collection().isNull() ); // will emit Collection::playlistCreated(...) -// qDebug() << "Creating dynplaylist belonging to:" << author().data() << author().isNull(); -// qDebug() << "REPORTING DYNAMIC PLAYLIST CREATED:" << this << author()->friendlyName(); + // qDebug() << "Creating dynplaylist belonging to:" << author().data() << author().isNull(); + // qDebug() << "REPORTING DYNAMIC PLAYLIST CREATED:" << this << author()->friendlyName(); if( self->mode() == Static ) author()->collection()->addAutoPlaylist( self ); else @@ -339,33 +339,33 @@ void DynamicPlaylist::setRevision( const QString& rev, setCurrentrevision( rev ); } // qDebug() << "EMITTING REVISION LOADED 1!"; - emit dynamicRevisionLoaded( dpr ); + emit dynamicRevisionLoaded( dpr ); } void DynamicPlaylist::setRevision( const QString& rev, - const QList< QString >& neworderedguids, - const QList< QString >& oldorderedguids, - const QString& type, - const QList< QVariantMap>& controlsV, - bool is_newest_rev, - const QMap< QString, Tomahawk::plentry_ptr >& addedmap, - bool applied ) + const QList< QString >& neworderedguids, + const QList< QString >& oldorderedguids, + const QString& type, + const QList< QVariantMap>& controlsV, + bool is_newest_rev, + const QMap< QString, Tomahawk::plentry_ptr >& addedmap, + bool applied ) { if( QThread::currentThread() != thread() ) { QMetaObject::invokeMethod( this, - "setRevision", - Qt::BlockingQueuedConnection, - Q_ARG( QString, rev ), - Q_ARG( QList , neworderedguids ), - Q_ARG( QList , oldorderedguids ), - Q_ARG( QString , type ), - QGenericArgument( "QList< QVariantMap > " , (const void*)&controlsV ), - Q_ARG( bool, is_newest_rev ), - QGenericArgument( "QMap< QString,Tomahawk::plentry_ptr > " , (const void*)&addedmap ), - Q_ARG( bool, applied ) ); + "setRevision", + Qt::BlockingQueuedConnection, + Q_ARG( QString, rev ), + Q_ARG( QList , neworderedguids ), + Q_ARG( QList , oldorderedguids ), + Q_ARG( QString , type ), + QGenericArgument( "QList< QVariantMap > " , (const void*)&controlsV ), + Q_ARG( bool, is_newest_rev ), + QGenericArgument( "QMap< QString,Tomahawk::plentry_ptr > " , (const void*)&addedmap ), + Q_ARG( bool, applied ) ); return; } @@ -416,10 +416,10 @@ void DynamicPlaylist::setRevision( const QString& rev, void DynamicPlaylist::setRevision( const QString& rev, - bool is_newest_rev, - const QString& type, - const QList< QVariantMap >& controlsV, - bool applied ) + bool is_newest_rev, + const QString& type, + const QList< QVariantMap >& controlsV, + bool applied ) { if( QThread::currentThread() != thread() ) { diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h index 7db146fd1..c53c96dd2 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h +++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h @@ -82,7 +82,8 @@ public: const QString& info, const QString& creator, GeneratorMode mode, - bool shared + bool shared, + const QString& type = QString() ); static bool remove( const dynplaylist_ptr& playlist ); diff --git a/src/libtomahawk/sourcelist.cpp b/src/libtomahawk/sourcelist.cpp index 917a96c00..0f3576808 100644 --- a/src/libtomahawk/sourcelist.cpp +++ b/src/libtomahawk/sourcelist.cpp @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -55,6 +55,18 @@ SourceList::getLocal() return m_local; } +void +SourceList::setWebSource( const source_ptr& websrc ) +{ + m_dummy = websrc; +} + +const +source_ptr SourceList::webSource() const +{ + return m_dummy; +} + void SourceList::loadSources() diff --git a/src/libtomahawk/sourcelist.h b/src/libtomahawk/sourcelist.h index 3ec7304ef..7073f713d 100644 --- a/src/libtomahawk/sourcelist.h +++ b/src/libtomahawk/sourcelist.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -40,6 +40,9 @@ public: const Tomahawk::source_ptr& getLocal(); void setLocal( const Tomahawk::source_ptr& localSrc ); + void setWebSource( const Tomahawk::source_ptr& websrc ); + const Tomahawk::source_ptr webSource() const; + void removeAllRemote(); QList sources( bool onlyOnline = false ) const; @@ -57,7 +60,7 @@ signals: private slots: void setSources( const QList& sources ); void sourceSynced(); - + private: void loadSources(); void add( const Tomahawk::source_ptr& source ); @@ -66,8 +69,9 @@ private: QMap< int, QString > m_sources_id2name; Tomahawk::source_ptr m_local; + Tomahawk::source_ptr m_dummy; mutable QMutex m_mut; // mutable so const methods can use a lock - + static SourceList* s_instance; }; diff --git a/src/libtomahawk/utils/xspfloader.cpp b/src/libtomahawk/utils/xspfloader.cpp index d8b31d40d..9b1543375 100644 --- a/src/libtomahawk/utils/xspfloader.cpp +++ b/src/libtomahawk/utils/xspfloader.cpp @@ -29,6 +29,12 @@ using namespace Tomahawk; +void +XSPFLoader::setOverrideTitle( const QString& newTitle ) +{ + m_overrideTitle = newTitle; +} + void XSPFLoader::load( const QUrl& url ) @@ -116,13 +122,15 @@ XSPFLoader::gotBody() m_title = origTitle; if ( m_title.isEmpty() ) m_title = tr( "New Playlist" ); + if( !m_overrideTitle.isEmpty() ) + m_title = m_overrideTitle; bool shownError = false; for ( unsigned int i = 0; i < tracklist.length(); i++ ) { QDomNode e = tracklist.at( i ); - QString artist, album, track, duration, annotation; + QString artist, album, track, duration, annotation, url; QDomElement n = e.firstChildElement(); for ( ; !n.isNull(); n = n.nextSiblingElement() ) { if (n.namespaceURI() == m_NS && n.localName() == "duration") { @@ -135,6 +143,8 @@ XSPFLoader::gotBody() album = n.text(); } else if (n.namespaceURI() == m_NS && n.localName() == "title") { track = n.text(); + } else if (n.namespaceURI() == m_NS && n.localName() == "url") { + url = n.text(); } } @@ -154,6 +164,8 @@ XSPFLoader::gotBody() p->setQuery( Tomahawk::Query::get( artist, track, album, uuid() ) ); p->query()->setDuration( duration.toInt() / 1000 ); + if( !url.isEmpty() ) + p->query()->setResultHint( url ); m_entries << p; } diff --git a/src/libtomahawk/utils/xspfloader.h b/src/libtomahawk/utils/xspfloader.h index 39e5088f7..e058faf22 100644 --- a/src/libtomahawk/utils/xspfloader.h +++ b/src/libtomahawk/utils/xspfloader.h @@ -53,6 +53,7 @@ public: QList< Tomahawk::plentry_ptr > entries() const { return m_entries; } + void setOverrideTitle( const QString& newTitle ); signals: void failed(); void ok( const Tomahawk::playlist_ptr& ); @@ -70,7 +71,7 @@ private: void gotBody(); bool m_autoCreate; - QString m_NS; + QString m_NS,m_overrideTitle; QList< Tomahawk::plentry_ptr > m_entries; QString m_title, m_info, m_creator; diff --git a/src/libtomahawk/viewmanager.h b/src/libtomahawk/viewmanager.h index e8a68f67b..3366f91a7 100644 --- a/src/libtomahawk/viewmanager.h +++ b/src/libtomahawk/viewmanager.h @@ -67,6 +67,7 @@ public: QWidget* widget() const { return m_widget; } PlaylistView* queue() const; + TopBar* topbar() const { return m_topbar; } bool isSuperCollectionVisible() const; bool isNewPlaylistPageVisible() const; @@ -76,14 +77,6 @@ public: Tomahawk::ViewPage* pageForInterface( PlaylistInterface* interface ) const; int positionInHistory( Tomahawk::ViewPage* page ) const; - // Returns the shown viewpage - Tomahawk::ViewPage* show( const Tomahawk::playlist_ptr& playlist ); - Tomahawk::ViewPage* show( const Tomahawk::dynplaylist_ptr& playlist ); - Tomahawk::ViewPage* show( const Tomahawk::artist_ptr& artist ); - Tomahawk::ViewPage* show( const Tomahawk::album_ptr& album ); - Tomahawk::ViewPage* show( const Tomahawk::collection_ptr& collection ); - Tomahawk::ViewPage* show( const Tomahawk::source_ptr& source ); - Tomahawk::ViewPage* show( Tomahawk::ViewPage* page ); Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; } @@ -127,6 +120,14 @@ public slots: Tomahawk::ViewPage* showWelcomePage(); void showCurrentTrack(); + // Returns the shown viewpage + Tomahawk::ViewPage* show( const Tomahawk::playlist_ptr& playlist ); + Tomahawk::ViewPage* show( const Tomahawk::dynplaylist_ptr& playlist ); + Tomahawk::ViewPage* show( const Tomahawk::artist_ptr& artist ); + Tomahawk::ViewPage* show( const Tomahawk::album_ptr& album ); + Tomahawk::ViewPage* show( const Tomahawk::collection_ptr& collection ); + Tomahawk::ViewPage* show( const Tomahawk::source_ptr& source ); + void historyBack(); void historyForward(); void showHistory( int historyPosition ); diff --git a/src/libtomahawk/webcollection.cpp b/src/libtomahawk/webcollection.cpp new file mode 100644 index 000000000..80a8785de --- /dev/null +++ b/src/libtomahawk/webcollection.cpp @@ -0,0 +1,32 @@ +/* + Copyright (C) 2011 Leo Franchi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#include "webcollection.h" + +using namespace Tomahawk; + +WebCollection::WebCollection( const source_ptr& source, const QString& name, QObject* parent ) + : Collection( source, name, parent ) +{ + +} + +WebCollection::~WebCollection() +{ +} diff --git a/src/libtomahawk/webcollection.h b/src/libtomahawk/webcollection.h new file mode 100644 index 000000000..ba016f023 --- /dev/null +++ b/src/libtomahawk/webcollection.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2011 Leo Franchi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef WEBCOLLECTION_H +#define WEBCOLLECTION_H + +#include "collection.h" +#include "dllmacro.h" + +namespace Tomahawk +{ + +class DLLEXPORT WebCollection : public Collection +{ + Q_OBJECT +public: + WebCollection( const source_ptr& source, const QString& name = QString(), QObject* parent = 0 ); + virtual ~WebCollection(); + + virtual void removeTracks( const QDir& ) {} + virtual void addTracks( const QList< QVariant >& ) {} +}; + + +} + +#endif // WEBCOLLECTION_H diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 67a06fc54..5f0da76d8 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -48,6 +48,9 @@ #include "shortcuthandler.h" #include "scanmanager.h" #include "tomahawksettings.h" +#include "globalactionmanager.h" +#include "webcollection.h" +#include "database/localcollection.h" #include "audio/audioengine.h" #include "utils/xspfloader.h" @@ -147,7 +150,6 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) , m_database( 0 ) , m_scanManager( 0 ) , m_audioEngine( 0 ) - , m_sipHandler( 0 ) , m_servent( 0 ) , m_shortcutHandler( 0 ) , m_mainwindow( 0 ) @@ -166,13 +168,13 @@ TomahawkApp::init() { qsrand( QTime( 0, 0, 0 ).secsTo( QTime::currentTime() ) ); - #ifdef TOMAHAWK_HEADLESS +#ifdef TOMAHAWK_HEADLESS m_headless = true; - #else +#else m_mainwindow = 0; m_headless = arguments().contains( "--headless" ); setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) ); - #endif +#endif registerMetaTypes(); @@ -193,12 +195,12 @@ TomahawkApp::init() GeneratorFactory::registerFactory( "echonest", new EchonestFactory ); // Register shortcut handler for this platform - #ifdef Q_WS_MAC +#ifdef Q_WS_MAC m_shortcutHandler = new MacShortcutHandler( this ); Tomahawk::setShortcutHandler( static_cast( m_shortcutHandler) ); Tomahawk::setApplicationHandler( this ); - #endif +#endif // Connect up shortcuts if ( m_shortcutHandler ) @@ -252,7 +254,7 @@ TomahawkApp::init() qDebug() << "Init SIP system."; m_sipHandler = new SipHandler( this ); - #ifndef TOMAHAWK_HEADLESS +#ifndef TOMAHAWK_HEADLESS if ( !m_headless ) { qDebug() << "Init MainWindow."; @@ -260,7 +262,7 @@ TomahawkApp::init() m_mainwindow->setWindowTitle( "Tomahawk" ); m_mainwindow->show(); } - #endif +#endif qDebug() << "Init Local Collection."; initLocalCollection(); @@ -295,7 +297,6 @@ TomahawkApp::~TomahawkApp() } m_scriptResolvers.clear(); - delete m_sipHandler; delete m_servent; delete m_scanManager; #ifndef TOMAHAWK_HEADLESS @@ -322,7 +323,6 @@ TomahawkApp::audioControls() } #endif - void TomahawkApp::registerMetaTypes() { @@ -460,12 +460,19 @@ void TomahawkApp::initLocalCollection() { source_ptr src( new Source( 0, "My Collection" ) ); - collection_ptr coll( new DatabaseCollection( src ) ); + collection_ptr coll( new LocalCollection( src ) ); src->addCollection( coll ); SourceList::instance()->setLocal( src ); // src->collection()->tracks(); + // dummy source/collection for web-based result-hints. + source_ptr dummy( new Source( -1, "" ) ); + dummy->setOnline(); + collection_ptr dummycol( new WebCollection( dummy ) ); + dummy->addCollection( dummycol ); + SourceList::instance()->setWebSource( dummy ); + // to make the stats signal be emitted by our local source // this will update the sidebar, etc. DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( src ); @@ -495,13 +502,14 @@ TomahawkApp::setupSIP() //FIXME: jabber autoconnect is really more, now that there is sip -- should be renamed and/or split out of jabber-specific settings if( !arguments().contains( "--nosip" ) && TomahawkSettings::instance()->jabberAutoConnect() ) { - #ifdef GLOOX_FOUND +#ifdef GLOOX_FOUND m_xmppBot = new XMPPBot( this ); - #endif +#endif qDebug() << "Connecting SIP classes"; m_sipHandler->connectPlugins( true ); // m_sipHandler->setProxy( *TomahawkUtils::proxy() ); + } } @@ -518,28 +526,22 @@ TomahawkApp::activate() bool TomahawkApp::loadUrl( const QString& url ) { - if( url.contains( "tomahawk://" ) ) { - QString cmd = url.mid( 11 ); - qDebug() << "tomahawk!s" << cmd; - if( cmd.startsWith( "load/?" ) ) { - cmd = cmd.mid( 6 ); - qDebug() << "loading.." << cmd; - if( cmd.startsWith( "xspf=" ) ) { - XSPFLoader* l = new XSPFLoader( true, this ); - qDebug() << "Loading spiff:" << cmd.mid( 5 ); - l->load( QUrl( cmd.mid( 5 ) ) ); - } - } - } else { + if( url.startsWith( "tomahawk://" ) ) + return GlobalActionManager::instance()->parseTomahawkLink( url ); + else + { QFile f( url ); QFileInfo info( f ); if( f.exists() && info.suffix() == "xspf" ) { XSPFLoader* l = new XSPFLoader( true, this ); qDebug() << "Loading spiff:" << url; l->load( QUrl::fromUserInput( url ) ); + + return true; } } - return true; + + return false; } @@ -553,6 +555,7 @@ TomahawkApp::instanceStarted( KDSingleApplicationGuard::Instance instance ) return; } - loadUrl( instance.arguments.at( 1 ) ); + QString arg1 = instance.arguments[ 1 ]; + loadUrl( arg1 ); }