1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-23 01:09:42 +01:00

Merge branch 'dragndrop'

This commit is contained in:
Leo Franchi 2011-08-05 07:57:26 -04:00
commit 98030c9b05
17 changed files with 498 additions and 325 deletions

View File

@ -167,6 +167,7 @@ set( libSources
utils/xspfloader.cpp
utils/xspfgenerator.cpp
utils/jspfloader.cpp
utils/spotifyparser.cpp
widgets/newplaylistwidget.cpp
widgets/searchwidget.cpp
@ -338,6 +339,7 @@ set( libHeaders
utils/xspfloader.h
utils/xspfgenerator.h
utils/jspfloader.h
utils/spotifyparser.h
widgets/newplaylistwidget.h
widgets/searchwidget.h
@ -427,7 +429,7 @@ IF( APPLE )
widgets/maclineedit.mm
utils/tomahawkutils_mac.mm )
SET( libHeaders ${libHeaders}
SET( libHeaders ${libHeaders}
infosystem/infoplugins/mac/adiumplugin.h
widgets/maclineedit.h )

View File

@ -22,6 +22,7 @@
#include <QClipboard>
#include <QUrl>
#include "artist.h"
#include "album.h"
#include "sourcelist.h"
#include "pipeline.h"
@ -42,9 +43,13 @@
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include "utils/jspfloader.h"
#include <QMimeData>
#include "utils/spotifyparser.h"
GlobalActionManager* GlobalActionManager::s_instance = 0;
using namespace Tomahawk;
GlobalActionManager*
GlobalActionManager::instance()
{
@ -54,18 +59,17 @@ GlobalActionManager::instance()
return s_instance;
}
GlobalActionManager::GlobalActionManager( QObject* parent )
: QObject( parent )
{
m_mimeTypes << "application/tomahawk.query.list" << "application/tomahawk.plentry.list" << "application/tomahawk.result.list" << "text/plain";
}
GlobalActionManager::~GlobalActionManager()
{}
QUrl
GlobalActionManager::openLinkFromQuery( const Tomahawk::query_ptr& query ) const
GlobalActionManager::openLinkFromQuery( const query_ptr& query ) const
{
QString title, artist, album;
@ -100,9 +104,9 @@ GlobalActionManager::openLink( const QString& title, const QString& artist, cons
}
QString
GlobalActionManager::copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist )
GlobalActionManager::copyPlaylistToClipboard( const dynplaylist_ptr& playlist )
{
QUrl link( QString( "%1/%2/create/" ).arg( hostname() ).arg( playlist->mode() == Tomahawk::OnDemand ? "station" : "autoplaylist" ) );
QUrl link( QString( "%1/%2/create/" ).arg( hostname() ).arg( playlist->mode() == OnDemand ? "station" : "autoplaylist" ) );
if( playlist->generator()->type() != "echonest" ) {
tLog() << "Only echonest generators are supported";
@ -112,8 +116,8 @@ GlobalActionManager::copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& p
link.addEncodedQueryItem( "type", "echonest" );
link.addQueryItem( "title", playlist->title() );
QList< Tomahawk::dyncontrol_ptr > controls = playlist->generator()->controls();
foreach( const Tomahawk::dyncontrol_ptr& c, controls ) {
QList< dyncontrol_ptr > controls = playlist->generator()->controls();
foreach( const dyncontrol_ptr& c, controls ) {
if( c->selectedType() == "Artist" ) {
if( c->match().toInt() == Echonest::DynamicPlaylist::ArtistType )
link.addQueryItem( "artist_limitto", c->input() );
@ -142,7 +146,7 @@ GlobalActionManager::copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& p
}
void
GlobalActionManager::savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename )
GlobalActionManager::savePlaylistToFile( const playlist_ptr& playlist, const QString& filename )
{
XSPFGenerator* g = new XSPFGenerator( playlist, this );
g->setProperty( "filename", filename );
@ -169,7 +173,7 @@ GlobalActionManager::xspfCreated( const QByteArray& xspf )
void
GlobalActionManager::copyToClipboard( const Tomahawk::query_ptr& query ) const
GlobalActionManager::copyToClipboard( const query_ptr& query ) const
{
QClipboard* cb = QApplication::clipboard();
cb->setText( openLinkFromQuery( query ).toEncoded() );
@ -199,7 +203,7 @@ GlobalActionManager::parseTomahawkLink( const QString& url )
return true;
} else if( u.hasQueryItem( "jspf" ) ) {
QUrl jspf = QUrl::fromUserInput( u.queryItemValue( "jspf" ) );
Tomahawk::JSPFLoader* l = new Tomahawk::JSPFLoader( true, this );
JSPFLoader* l = new JSPFLoader( true, this );
tDebug() << "Loading jspiff:" << jspf.toString();
l->load( jspf );
connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) );
@ -262,7 +266,7 @@ GlobalActionManager::handlePlaylistCommand( const QUrl& url )
tLog() << "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 );
playlist_ptr pl = Playlist::create( SourceList::instance()->getLocal(), uuid(), url.queryItemValue( "title" ), QString(), QString(), false );
ViewManager::instance()->show( pl );
} else if( parts[ 0 ] == "add" ) {
if( !url.hasQueryItem( "playlistid" ) || !url.hasQueryItem( "title" ) || !url.hasQueryItem( "artist" ) ) {
@ -305,7 +309,7 @@ GlobalActionManager::handleOpenCommand(const QUrl& url)
}
void
GlobalActionManager::handleOpenTrack ( const Tomahawk::query_ptr& q )
GlobalActionManager::handleOpenTrack ( const query_ptr& q )
{
ViewManager::instance()->queue()->model()->append( q );
ViewManager::instance()->showQueue();
@ -355,10 +359,10 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
}
if( !title.isEmpty() || !artist.isEmpty() || !album.isEmpty() ) { // an individual; query to add to queue
Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), false );
query_ptr q = Query::get( artist, title, album, uuid(), false );
if( !urlStr.isEmpty() )
q->setResultHint( urlStr );
Tomahawk::Pipeline::instance()->resolve( q, true );
Pipeline::instance()->resolve( q, true );
handleOpenTrack( q );
return true;
@ -373,10 +377,10 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
// TODO
} else { // give it a web result hint
QFileInfo info( track.path() );
Tomahawk::query_ptr q = Tomahawk::Query::get( QString(), info.baseName(), QString(), uuid(), false );
query_ptr q = Query::get( QString(), info.baseName(), QString(), uuid(), false );
q->setResultHint( track.toString() );
Tomahawk::Pipeline::instance()->resolve( q, true );
Pipeline::instance()->resolve( q, true );
ViewManager::instance()->queue()->model()->append( q );
ViewManager::instance()->showQueue();
@ -415,139 +419,139 @@ GlobalActionManager::handleAutoPlaylistCommand( const QUrl& url )
return !loadDynamicPlaylist( url, false ).isNull();
}
Tomahawk::dynplaylist_ptr
dynplaylist_ptr
GlobalActionManager::loadDynamicPlaylist( const QUrl& url, bool station )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
tLog() << "No specific station command:" << url.toString();
return Tomahawk::dynplaylist_ptr();
return dynplaylist_ptr();
}
if( parts[ 0 ] == "create" ) {
if( !url.hasQueryItem( "title" ) || !url.hasQueryItem( "type" ) ) {
tLog() << "Station create command needs title and type..." << url.toString();
return Tomahawk::dynplaylist_ptr();
return dynplaylist_ptr();
}
QString title = url.queryItemValue( "title" );
QString type = url.queryItemValue( "type" );
Tomahawk::GeneratorMode m = Tomahawk::Static;
GeneratorMode m = Static;
if( station )
m = Tomahawk::OnDemand;
m = OnDemand;
Tomahawk::dynplaylist_ptr pl = Tomahawk::DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), title, QString(), QString(), m, false, type );
dynplaylist_ptr pl = DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), title, QString(), QString(), m, false, type );
pl->setMode( m );
QList< Tomahawk::dyncontrol_ptr > controls;
QList< dyncontrol_ptr > controls;
QPair< QString, QString > param;
foreach( param, url.queryItems() ) {
if( param.first == "artist" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist" );
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 == "artist_limitto" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist" );
dyncontrol_ptr c = pl->generator()->createControl( "Artist" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistType ) );
controls << c;
} else if( param.first == "description" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist Description" );
dyncontrol_ptr c = pl->generator()->createControl( "Artist Description" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistDescriptionType ) );
controls << c;
} else if( param.first == "variety" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Variety" );
dyncontrol_ptr c = pl->generator()->createControl( "Variety" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Variety ) );
controls << c;
} else if( param.first.startsWith( "tempo" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Tempo" );
dyncontrol_ptr c = pl->generator()->createControl( "Tempo" );
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinTempo + extra ) );
controls << c;
} else if( param.first.startsWith( "duration" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Duration" );
dyncontrol_ptr c = pl->generator()->createControl( "Duration" );
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinDuration + extra ) );
controls << c;
} else if( param.first.startsWith( "loudness" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Loudness" );
dyncontrol_ptr c = pl->generator()->createControl( "Loudness" );
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinLoudness + extra ) );
controls << c;
} else if( param.first.startsWith( "danceability" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Danceability" );
dyncontrol_ptr c = pl->generator()->createControl( "Danceability" );
int extra = param.first.endsWith( "_max" ) ? 1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinDanceability + extra ) );
controls << c;
} else if( param.first.startsWith( "energy" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Energy" );
dyncontrol_ptr c = pl->generator()->createControl( "Energy" );
int extra = param.first.endsWith( "_max" ) ? 1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinEnergy + extra ) );
controls << c;
} else if( param.first.startsWith( "artist_familiarity" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist Familiarity" );
dyncontrol_ptr c = pl->generator()->createControl( "Artist Familiarity" );
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinFamiliarity + extra ) );
controls << c;
} else if( param.first.startsWith( "artist_hotttnesss" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist Hotttnesss" );
dyncontrol_ptr c = pl->generator()->createControl( "Artist Hotttnesss" );
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinHotttnesss + extra ) );
controls << c;
} else if( param.first.startsWith( "song_hotttnesss" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Song Hotttnesss" );
dyncontrol_ptr c = pl->generator()->createControl( "Song Hotttnesss" );
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::SongMinHotttnesss + extra ) );
controls << c;
} else if( param.first.startsWith( "longitude" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Longitude" );
dyncontrol_ptr c = pl->generator()->createControl( "Longitude" );
int extra = param.first.endsWith( "_max" ) ? 1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinLongitude + extra ) );
controls << c;
} else if( param.first.startsWith( "latitude" ) ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Latitude" );
dyncontrol_ptr c = pl->generator()->createControl( "Latitude" );
int extra = param.first.endsWith( "_max" ) ? 1 : 0;
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinLatitude + extra ) );
controls << c;
} else if( param.first == "key" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Key" );
dyncontrol_ptr c = pl->generator()->createControl( "Key" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Key ) );
controls << c;
} else if( param.first == "mode" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Mode" );
dyncontrol_ptr c = pl->generator()->createControl( "Mode" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Mode ) );
controls << c;
} else if( param.first == "mood" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Mood" );
dyncontrol_ptr c = pl->generator()->createControl( "Mood" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Mood ) );
controls << c;
} else if( param.first == "style" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Style" );
dyncontrol_ptr c = pl->generator()->createControl( "Style" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Style ) );
controls << c;
} else if( param.first == "song" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Song" );
dyncontrol_ptr c = pl->generator()->createControl( "Song" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::SongRadioType ) );
controls << c;
}
}
if( m == Tomahawk::OnDemand )
if( m == OnDemand )
pl->createNewRevision( uuid(), pl->currentrevision(), type, controls );
else
pl->createNewRevision( uuid(), pl->currentrevision(), type, controls, pl->entries() );
@ -555,7 +559,7 @@ GlobalActionManager::loadDynamicPlaylist( const QUrl& url, bool station )
return pl;
}
return Tomahawk::dynplaylist_ptr();
return dynplaylist_ptr();
}
@ -587,10 +591,10 @@ GlobalActionManager::handlePlayCommand( const QUrl& url )
else if( pair.first == "url" )
urlStr = pair.second;
}
Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album );
query_ptr q = Query::get( artist, title, album );
if( !urlStr.isEmpty() )
q->setResultHint( urlStr );
Tomahawk::Pipeline::instance()->resolve( q, true );
Pipeline::instance()->resolve( q, true );
m_waitingToPlay = q;
connect( q.data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( waitingForResolved( bool ) ) );
@ -622,14 +626,14 @@ bool GlobalActionManager::handleBookmarkCommand(const QUrl& url)
else if( pair.first == "url" )
urlStr = pair.second;
}
Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album );
query_ptr q = Query::get( artist, title, album );
if( !urlStr.isEmpty() )
q->setResultHint( urlStr );
Tomahawk::Pipeline::instance()->resolve( q, true );
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();
playlist_ptr bookmarkpl = col->bookmarksPlaylist();
if( bookmarkpl.isNull() ) { // create it and do the deed then
m_waitingToBookmark = q;
col->createBookmarksPlaylist();
@ -647,16 +651,16 @@ bool GlobalActionManager::handleBookmarkCommand(const QUrl& url)
void
GlobalActionManager::bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl )
GlobalActionManager::bookmarkPlaylistCreated( const playlist_ptr& pl )
{
Q_ASSERT( !m_waitingToBookmark.isNull() );
doBookmark( pl, m_waitingToBookmark );
}
void
GlobalActionManager::doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q )
GlobalActionManager::doBookmark( const playlist_ptr& pl, const query_ptr& q )
{
Tomahawk::plentry_ptr e( new Tomahawk::PlaylistEntry );
plentry_ptr e( new PlaylistEntry );
e->setGuid( uuid() );
if ( q->results().count() )
@ -668,7 +672,7 @@ GlobalActionManager::doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahaw
e->setAnnotation( "" ); // FIXME
e->setQuery( q );
pl->createNewRevision( uuid(), pl->currentrevision(), QList< Tomahawk::plentry_ptr >( pl->entries() ) << e );
pl->createNewRevision( uuid(), pl->currentrevision(), QList< plentry_ptr >( pl->entries() ) << e );
connect( pl.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( showPlaylist() ) );
m_toShow = pl;
@ -712,82 +716,111 @@ GlobalActionManager::hostname() const
return QString( "http://toma.hk" );
}
/// SPOTIFY URL HANDLING
/// QMIMEDATA HANDLING
bool
GlobalActionManager::parseSpotifyLink( const QString& link )
QStringList
GlobalActionManager::mimeTypes() const
{
if( !link.contains( "track" ) ) // we only support track links atm
return false;
// we need Spotify URIs such as spotify:track:XXXXXX, so if we by chance get a http://open.spotify.com url, convert it
QString uri = link;
if( link.contains( "open.spotify.com" ) )
{
QString hash = link;
hash.replace( "http://open.spotify.com/track/", "" );
uri = QString( "spotify:track:%1" ).arg( hash );
}
tLog() << "Parsing Spotify Track URI:" << uri;
QUrl url = QUrl( QString( "http://ws.spotify.com/lookup/1/.json?uri=%1" ).arg( uri ) );
tDebug() << "Looking up..." << url.toString();
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
connect( reply, SIGNAL( finished() ), this, SLOT( spotifyTrackLookupFinished() ) );
return true; // all we know now
return m_mimeTypes;
}
bool
GlobalActionManager::acceptsMimeData( const QMimeData* data )
{
if ( data->hasFormat( "application/tomahawk.query.list" )
|| data->hasFormat( "application/tomahawk.plentry.list" )
|| data->hasFormat( "application/tomahawk.result.list" ) )
{
return true;
}
// crude check for spotify data
if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "spotify" ) )
return true;
return false;
}
void
GlobalActionManager::spotifyTrackLookupFinished()
GlobalActionManager::tracksFromMimeData( const QMimeData* data )
{
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( r );
if( r->error() == QNetworkReply::NoError )
if ( data->hasFormat( "application/tomahawk.query.list" ) )
emit tracks( tracksFromQueryList( data ) );
else if ( data->hasFormat( "application/tomahawk.result.list" ) )
emit tracks( tracksFromResultList( data ) );
else if ( data->hasFormat( "text/plain" ) )
{
QJson::Parser p;
bool ok;
QVariantMap res = p.parse( r, &ok ).toMap();
QString plainData = QString::fromUtf8( data->data( "text/plain" ).constData() );
tDebug() << "Got text/plain mime data:" << data->data( "text/plain" ) << "decoded to:" << plainData;
if( plainData.contains( "open.spotify.com") ||
plainData.contains( "spotify:track" ) )
{
QStringList tracks = plainData.split( "\n" );
if( !ok )
{
tLog() << "Failed to parse json from Spotify track lookup:" << p.errorString() << "On line" << p.errorLine();
return;
} else if( !res.contains( "track" ) )
{
tLog() << "No 'track' item in the spotify track lookup result... not doing anything";
return;
tDebug() << "Got a list of spotify urls!" << tracks;
SpotifyParser* spot = new SpotifyParser( tracks, this );
connect( spot, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ) );
}
// lets parse this baby
QVariantMap t = res.value( "track" ).toMap();
QString title, artist, album;
title = t.value( "name", QString() ).toString();
// TODO for now only take the first artist
if( t.contains( "artists" ) && t[ "artists" ].canConvert< QVariantList >() && t[ "artists" ].toList().size() > 0 )
artist = t[ "artists" ].toList().first().toMap().value( "name", QString() ).toString();
if( t.contains( "album" ) && t[ "album" ].canConvert< QVariantMap >() )
album = t[ "album" ].toMap().value( "name", QString() ).toString();
if( title.isEmpty() && artist.isEmpty() ) // don't have enough...
{
tLog() << "Didn't get an artist and track name from spotify, not enough to build a query on. Aborting" << title << artist << album;
return;
}
Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), true );
handleOpenTrack( q );
} else
{
tLog() << "Error in network request to Spotify for track decoding:" << r->errorString();
}
}
QList< query_ptr >
GlobalActionManager::tracksFromQueryList( const QMimeData* data )
{
QList< query_ptr > queries;
QByteArray itemData = data->data( "application/tomahawk.query.list" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
while ( !stream.atEnd() )
{
qlonglong qptr;
stream >> qptr;
query_ptr* query = reinterpret_cast<query_ptr*>(qptr);
if ( query && !query->isNull() )
{
tDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track();
queries << *query;
}
}
return queries;
}
QList< query_ptr >
GlobalActionManager::tracksFromResultList( const QMimeData* data )
{
QList< query_ptr > queries;
QByteArray itemData = data->data( "application/tomahawk.result.list" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
while ( !stream.atEnd() )
{
qlonglong qptr;
stream >> qptr;
result_ptr* result = reinterpret_cast<result_ptr*>(qptr);
if ( result && !result->isNull() )
{
tDebug() << "Dropped result item:" << result->data()->artist()->name() << "-" << result->data()->track();
query_ptr q = result->data()->toQuery();
q->addResults( QList< result_ptr >() << *result );
queries << q;
}
}
return queries;
}
/// SPOTIFY URL HANDLING
bool
GlobalActionManager::openSpotifyLink( const QString& link )
{
SpotifyParser* spot = new SpotifyParser( link, this );
connect( spot, SIGNAL( track( Tomahawk::query_ptr ) ), this, SLOT( handleOpenTrack( Tomahawk::query_ptr ) ) );
return true;
}

View File

@ -28,6 +28,9 @@
#include <QObject>
#include <QUrl>
/**
* Handles global actions such as parsing and creation of links, mime data handling, etc
*/
class DLLEXPORT GlobalActionManager : public QObject
{
Q_OBJECT
@ -38,32 +41,47 @@ public:
QUrl openLinkFromQuery( const Tomahawk::query_ptr& query ) const;
QUrl openLink( const QString& title, const QString& artist, const QString& album ) const;
// spotify
bool parseSpotifyLink( const QString& link );
/// Takes a spotify link and performs the default open action on it
bool openSpotifyLink( const QString& link );
void copyToClipboard( const Tomahawk::query_ptr& query ) const;
QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist );
void savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename );
/**
* QMimeData helpers
*
* Call this to parse the tracks in a QMimeData object to query_ptrs. This will parse internal tomahawk
* data as well as all other formats supported (spotify, etc).
*
* Connect to tracks( QList< query_ptr> ); for the extracted tracks.
*/
bool acceptsMimeData( const QMimeData* data );
void tracksFromMimeData( const QMimeData* data );
QStringList mimeTypes() const;
public slots:
bool parseTomahawkLink( const QString& link );
void waitingForResolved( bool );
Tomahawk::dynplaylist_ptr loadDynamicPlaylist( const QUrl& url, bool station );
signals:
/// QMimeData parsing results
void tracks( const QList< Tomahawk::query_ptr >& tracks );
private slots:
void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl );
void showPlaylist();
void xspfCreated( const QByteArray& xspf );
// SPOTIFY
void spotifyTrackLookupFinished();
void handleOpenTrack( const Tomahawk::query_ptr& qry );
private:
explicit GlobalActionManager( QObject* parent = 0 );
void doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q );
/// handle opening of urls
bool handlePlaylistCommand( const QUrl& url );
bool handleCollectionCommand(const QUrl& url );
bool handleQueueCommand(const QUrl& url );
@ -73,16 +91,19 @@ private:
bool handlePlayCommand(const QUrl& url );
bool handleBookmarkCommand(const QUrl& url );
bool handleOpenCommand(const QUrl& url );
void handleOpenTrack( const Tomahawk::query_ptr& qry );
bool doQueueAdd( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems );
/// handle parsing mime data
QList< Tomahawk::query_ptr > tracksFromQueryList( const QMimeData* d );
QList< Tomahawk::query_ptr > tracksFromResultList( const QMimeData* d );
QString hostname() const;
Tomahawk::playlist_ptr m_toShow;
Tomahawk::query_ptr m_waitingToBookmark;
Tomahawk::query_ptr m_waitingToPlay;
QStringList m_mimeTypes;
static GlobalActionManager* s_instance;
};

View File

@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -27,6 +27,7 @@
#include "database/databasecommand_playbackhistory.h"
#include "dynamic/GeneratorInterface.h"
#include "utils/logger.h"
#include "globalactionmanager.h"
using namespace Tomahawk;
@ -38,6 +39,9 @@ PlaylistModel::PlaylistModel( QObject* parent )
{
qDebug() << Q_FUNC_INFO;
m_dropStorage.parent = QPersistentModelIndex();
m_dropStorage.row = -10;
setReadOnly( false );
}
@ -168,7 +172,7 @@ PlaylistModel::clear()
{
if ( rowCount( QModelIndex() ) )
{
emit loadingFinished();;
emit loadingFinished();
emit beginResetModel();
delete m_rootItem;
@ -355,16 +359,32 @@ PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int r
if ( action == Qt::IgnoreAction || isReadOnly() )
return true;
if ( !data->hasFormat( "application/tomahawk.query.list" )
&& !data->hasFormat( "application/tomahawk.plentry.list" )
&& !data->hasFormat( "application/tomahawk.result.list" ) )
if ( !GlobalActionManager::instance()->acceptsMimeData( data ) )
return false;
m_dropStorage.row = row;
m_dropStorage.parent = QPersistentModelIndex( parent );
m_dropStorage.action = action;
connect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
GlobalActionManager::instance()->tracksFromMimeData( data );
return true;
}
void
PlaylistModel::parsedDroppedTracks( QList< query_ptr > tracks )
{
if ( m_dropStorage.row == -10 ) // nope
return;
disconnect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
int beginRow;
if ( row != -1 )
beginRow = row;
else if ( parent.isValid() )
beginRow = parent.row();
if ( m_dropStorage.row != -1 )
beginRow = m_dropStorage.row;
else if ( m_dropStorage.parent.isValid() )
beginRow = m_dropStorage.parent.row();
else
beginRow = rowCount( QModelIndex() );
@ -373,51 +393,10 @@ PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int r
if ( currentItem().isValid() )
currentuuid = itemFromIndex( currentItem() )->query()->id();
QList<Tomahawk::query_ptr> queries;
if ( data->hasFormat( "application/tomahawk.result.list" ) )
if ( tracks.count() )
{
QByteArray itemData = data->data( "application/tomahawk.result.list" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
while ( !stream.atEnd() )
{
qlonglong qptr;
stream >> qptr;
Tomahawk::result_ptr* result = reinterpret_cast<Tomahawk::result_ptr*>(qptr);
if ( result && !result->isNull() )
{
qDebug() << "Dropped result item:" << result->data()->artist() << "-" << result->data()->track();
query_ptr q = result->data()->toQuery();
q->addResults( QList< result_ptr >() << *result );
queries << q;
}
}
}
if ( data->hasFormat( "application/tomahawk.query.list" ) )
{
QByteArray itemData = data->data( "application/tomahawk.query.list" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
while ( !stream.atEnd() )
{
qlonglong qptr;
stream >> qptr;
Tomahawk::query_ptr* query = reinterpret_cast<Tomahawk::query_ptr*>(qptr);
if ( query && !query->isNull() )
{
qDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track() << action;
queries << *query;
}
}
}
if ( queries.count() )
{
emit beginInsertRows( QModelIndex(), beginRow, beginRow + queries.count() - 1 );
foreach( const Tomahawk::query_ptr& query, queries )
emit beginInsertRows( QModelIndex(), beginRow, beginRow + tracks.count() - 1 );
foreach( const Tomahawk::query_ptr& query, tracks )
{
plentry_ptr e( new PlaylistEntry() );
e->setGuid( uuid() );
@ -441,11 +420,12 @@ PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int r
}
emit endInsertRows();
if ( action == Qt::CopyAction )
if ( m_dropStorage.action == Qt::CopyAction )
onPlaylistChanged( true );
}
return true;
m_dropStorage.parent = QPersistentModelIndex();
m_dropStorage.row = -10;
}

View File

@ -39,6 +39,12 @@ class DLLEXPORT PlaylistModel : public TrackModel
{
Q_OBJECT
typedef struct {
int row;
QPersistentModelIndex parent;
Qt::DropAction action;
} DropStorageData;
public:
explicit PlaylistModel( QObject* parent = 0 );
~PlaylistModel();
@ -84,6 +90,7 @@ private slots:
void onTracksAdded( const QList<Tomahawk::query_ptr>& tracks );
void onTracksInserted( unsigned int row, const QList<Tomahawk::query_ptr>& tracks );
void parsedDroppedTracks( QList<Tomahawk::query_ptr> );
void trackResolved( bool );
@ -93,6 +100,8 @@ private:
Tomahawk::playlist_ptr m_playlist;
bool m_waitForUpdate, m_isTemporary;
QList< Tomahawk::Query* > m_waitingForResolved;
DropStorageData m_dropStorage;
};
#endif // PLAYLISTMODEL_H

View File

@ -34,6 +34,7 @@
#include "dynamic/widgets/LoadingSpinner.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#include <globalactionmanager.h>
using namespace Tomahawk;
@ -214,9 +215,7 @@ TrackView::dragEnterEvent( QDragEnterEvent* event )
qDebug() << Q_FUNC_INFO;
QTreeView::dragEnterEvent( event );
if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" )
|| event->mimeData()->hasFormat( "application/tomahawk.plentry.list" )
|| event->mimeData()->hasFormat( "application/tomahawk.result.list" ) )
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
{
m_dragging = true;
m_dropRect = QRect();
@ -238,9 +237,7 @@ TrackView::dragMoveEvent( QDragMoveEvent* event )
return;
}
if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" )
|| event->mimeData()->hasFormat( "application/tomahawk.plentry.list" )
|| event->mimeData()->hasFormat( "application/tomahawk.result.list" ) )
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
{
setDirtyRegion( m_dropRect );
const QPoint pos = event->pos();
@ -274,20 +271,7 @@ TrackView::dropEvent( QDropEvent* event )
}
else
{
if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" ) )
{
const QPoint pos = event->pos();
const QModelIndex index = indexAt( pos );
qDebug() << "Drop Event accepted at row:" << index.row();
event->acceptProposedAction();
if ( !model()->isReadOnly() )
{
model()->dropMimeData( event->mimeData(), event->proposedAction(), index.row(), 0, index.parent() );
}
}
else if ( event->mimeData()->hasFormat( "application/tomahawk.result.list" ) )
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
{
const QPoint pos = event->pos();
const QModelIndex index = indexAt( pos );

View File

@ -0,0 +1,147 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk 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 3 of the License, or
* (at your option) any later version.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "spotifyparser.h"
#include "utils/logger.h"
#include "utils/tomahawkutils.h"
#include "query.h"
#include <qjson/parser.h>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
using namespace Tomahawk;
SpotifyParser::SpotifyParser( const QStringList& trackUrls, QObject* parent )
: QObject ( parent )
, m_single( false )
{
foreach ( const QString& url, trackUrls )
lookupTrack( url );
}
SpotifyParser::SpotifyParser( const QString& trackUrl, QObject* parent )
: QObject ( parent )
, m_single( true )
{
lookupTrack( trackUrl );
}
SpotifyParser::~SpotifyParser()
{
}
void
SpotifyParser::lookupTrack( const QString& link )
{
if ( !link.contains( "track" ) ) // we only support track links atm
return;
// we need Spotify URIs such as spotify:track:XXXXXX, so if we by chance get a http://open.spotify.com url, convert it
QString uri = link;
if ( link.contains( "open.spotify.com" ) )
{
QString hash = link;
hash.replace( "http://open.spotify.com/track/", "" );
uri = QString( "spotify:track:%1" ).arg( hash );
}
tLog() << "Parsing Spotify Track URI:" << uri;
QUrl url = QUrl( QString( "http://ws.spotify.com/lookup/1/.json?uri=%1" ).arg( uri ) );
tDebug() << "Looking up..." << url.toString();
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
connect( reply, SIGNAL( finished() ), this, SLOT( spotifyTrackLookupFinished() ) );
m_queries.insert( reply );
}
void
SpotifyParser::spotifyTrackLookupFinished()
{
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( r );
m_queries.remove( r );
r->deleteLater();
if ( r->error() == QNetworkReply::NoError )
{
QJson::Parser p;
bool ok;
QVariantMap res = p.parse( r, &ok ).toMap();
if ( !ok )
{
tLog() << "Failed to parse json from Spotify track lookup:" << p.errorString() << "On line" << p.errorLine();
checkFinished();
return;
} else if ( !res.contains( "track" ) )
{
tLog() << "No 'track' item in the spotify track lookup result... not doing anything";
checkFinished();
return;
}
// lets parse this baby
QVariantMap t = res.value( "track" ).toMap();
QString title, artist, album;
title = t.value( "name", QString() ).toString();
// TODO for now only take the first artist
if ( t.contains( "artists" ) && t[ "artists" ].canConvert< QVariantList >() && t[ "artists" ].toList().size() > 0 )
artist = t[ "artists" ].toList().first().toMap().value( "name", QString() ).toString();
if ( t.contains( "album" ) && t[ "album" ].canConvert< QVariantMap >() )
album = t[ "album" ].toMap().value( "name", QString() ).toString();
if ( title.isEmpty() && artist.isEmpty() ) // don't have enough...
{
tLog() << "Didn't get an artist and track name from spotify, not enough to build a query on. Aborting" << title << artist << album;
return;
}
Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), true );
m_tracks << q;
} else
{
tLog() << "Error in network request to Spotify for track decoding:" << r->errorString();
}
checkFinished();
}
void
SpotifyParser::checkFinished()
{
if ( m_queries.isEmpty() ) // we're done
{
if ( m_single && !m_tracks.isEmpty() )
emit track( m_tracks.first() );
else if ( !m_single && !m_tracks.isEmpty() )
emit tracks( m_tracks );
deleteLater();
}
}

View File

@ -0,0 +1,64 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk 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 3 of the License, or
* (at your option) any later version.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SPOTIFY_PARSER_H
#define SPOTIFY_PARSER_H
#include "dllmacro.h"
#include "typedefs.h"
#include <QObject>
#include <QSet>
#include <QtCore/QStringList>
class QNetworkReply;
namespace Tomahawk
{
/**
* Small class to parse spotify links into query_ptrs
*
* Connect to the signals to get the results
*/
class DLLEXPORT SpotifyParser : public QObject
{
Q_OBJECT
public:
explicit SpotifyParser( const QString& trackUrl, QObject* parent = 0 );
explicit SpotifyParser( const QStringList& trackUrls, QObject* parent = 0 );
virtual ~SpotifyParser();
signals:
void track( const Tomahawk::query_ptr& track );
void tracks( const QList< Tomahawk::query_ptr > tracks );
private slots:
void spotifyTrackLookupFinished();
private:
void lookupTrack( const QString& track );
void checkFinished();
bool m_single;
QList< query_ptr > m_tracks;
QSet< QNetworkReply* > m_queries;
};
}
#endif

View File

@ -28,6 +28,7 @@
#include "widgets/playlisttypeselectordlg.h"
#include <playlist/dynamic/GeneratorInterface.h>
#include "utils/logger.h"
#include <globalactionmanager.h>
using namespace Tomahawk;
@ -121,12 +122,7 @@ CategoryAddItem::icon() const
bool
CategoryAddItem::willAcceptDrag( const QMimeData* data ) const
{
if ( ( m_categoryType == SourcesModel::PlaylistsCategory || m_categoryType == SourcesModel::StationsCategory ) &&
(
data->hasFormat( "application/tomahawk.query.list" ) ||
data->hasFormat( "application/tomahawk.result.list" )
)
)
if ( ( m_categoryType == SourcesModel::PlaylistsCategory || m_categoryType == SourcesModel::StationsCategory ) && GlobalActionManager::instance()->acceptsMimeData( data ) )
{
return true;
}
@ -138,78 +134,43 @@ bool
CategoryAddItem::dropMimeData( const QMimeData* data, Qt::DropAction )
{
// Create a new playlist seeded with these items
if ( data->hasFormat( "application/tomahawk.query.list" ) || data->hasFormat( "application/tomahawk.result.list" ) ) {
connect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
GlobalActionManager::instance()->tracksFromMimeData( data );
QList< Tomahawk::query_ptr > queries;
return true;
}
if ( data->hasFormat( "application/tomahawk.query.list" ) ) {
QByteArray itemData = data->data( "application/tomahawk.query.list" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
void
CategoryAddItem::parsedDroppedTracks( const QList< query_ptr >& tracks )
{
disconnect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
if( m_categoryType == SourcesModel::PlaylistsCategory ) {
while ( !stream.atEnd() )
{
qlonglong qptr;
stream >> qptr;
playlist_ptr newpl = Playlist::create( SourceList::instance()->getLocal(), uuid(), "New Playlist", "", SourceList::instance()->getLocal()->friendlyName(), false, tracks );
ViewManager::instance()->show( newpl );
Tomahawk::query_ptr* query = reinterpret_cast<Tomahawk::query_ptr*>(qptr);
if ( query && !query->isNull() )
{
qDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track();
queries << *query;
}
}
} else if( data->hasFormat( "application/tomahawk.result.list" ) ) {
QByteArray itemData = data->data( "application/tomahawk.result.list" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
// Give a shot to try to rename it. The playlist has to be created first. ugly.
QTimer::singleShot( 300, APP->mainWindow()->sourceTreeView(), SLOT( renamePlaylist() ) );
} else if( m_categoryType == SourcesModel::StationsCategory ) {
// seed the playlist with these song filters
QString name = tracks.isEmpty() ? tr( "New Station" ) : tr( "%1 Station" ).arg( tracks.first()->track() );
dynplaylist_ptr newpl = DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), name, "", SourceList::instance()->getLocal()->friendlyName(), OnDemand, false );
newpl->setMode( OnDemand );
while ( !stream.atEnd() )
{
qlonglong qptr;
stream >> qptr;
Tomahawk::result_ptr* result = reinterpret_cast<Tomahawk::result_ptr*>(qptr);
if ( result && !result->isNull() )
{
qDebug() << "Dropped result item:" << result->data()->artist() << "-" << result->data()->track();
query_ptr q = result->data()->toQuery();
q->addResults( QList< result_ptr >() << *result );
queries << q;
}
}
// now we want to add each query as a song filter...
QList< dyncontrol_ptr > contrls;
foreach( const Tomahawk::query_ptr& q, tracks ) {
dyncontrol_ptr c = newpl->generator()->createControl( "Song" );
c->setInput( QString( "%1 %2" ).arg( q->track() ).arg( q->artist() ) );
contrls << c;
}
if( m_categoryType == SourcesModel::PlaylistsCategory ) {
newpl->createNewRevision( uuid(), newpl->currentrevision(), newpl->type(), contrls );
playlist_ptr newpl = Playlist::create( SourceList::instance()->getLocal(), uuid(), "New Playlist", "", SourceList::instance()->getLocal()->friendlyName(), false, queries );
ViewManager::instance()->show( newpl );
// Give a shot to try to rename it. The playlist has to be created first. ugly.
QTimer::singleShot( 300, APP->mainWindow()->sourceTreeView(), SLOT( renamePlaylist() ) );
} else if( m_categoryType == SourcesModel::StationsCategory ) {
// seed the playlist with these song filters
QString name = queries.isEmpty() ? tr( "New Station" ) : tr( "%1 Station" ).arg( queries.first()->track() );
dynplaylist_ptr newpl = DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), name, "", SourceList::instance()->getLocal()->friendlyName(), OnDemand, false );
newpl->setMode( OnDemand );
// now we want to add each query as a song filter...
QList< dyncontrol_ptr > contrls;
foreach( const Tomahawk::query_ptr& q, queries ) {
dyncontrol_ptr c = newpl->generator()->createControl( "Song" );
c->setInput( QString( "%1 %2" ).arg( q->track() ).arg( q->artist() ) );
contrls << c;
}
newpl->createNewRevision( uuid(), newpl->currentrevision(), newpl->type(), contrls );
ViewManager::instance()->show( newpl );
// Give a shot to try to rename it. The playlist has to be created first. ugly.
QTimer::singleShot( 300, APP->mainWindow()->sourceTreeView(), SLOT( renamePlaylist() ) );
}
return true;
ViewManager::instance()->show( newpl );
// Give a shot to try to rename it. The playlist has to be created first. ugly.
QTimer::singleShot( 300, APP->mainWindow()->sourceTreeView(), SLOT( renamePlaylist() ) );
}
return false;
}

View File

@ -35,6 +35,9 @@ public:
virtual bool willAcceptDrag(const QMimeData* data) const;
virtual bool dropMimeData(const QMimeData* data, Qt::DropAction action);
private slots:
void parsedDroppedTracks( const QList< Tomahawk::query_ptr >& tracks );
private:
SourcesModel::CategoryType m_categoryType;
};

View File

@ -25,6 +25,7 @@
#include "collectionitem.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#include "globalactionmanager.h"
using namespace Tomahawk;
@ -138,56 +139,23 @@ PlaylistItem::dropMimeData( const QMimeData* data, Qt::DropAction action )
data->data( "application/tomahawk.playlist.id" ) == m_playlist->guid() )
return false; // don't allow dropping on ourselves
if ( data->hasFormat( "application/tomahawk.result.list" ) )
{
QByteArray itemData = data->data( "application/tomahawk.result.list" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
connect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
GlobalActionManager::instance()->tracksFromMimeData( data );
while ( !stream.atEnd() )
{
qlonglong qptr;
stream >> qptr;
// TODO cant' know if it works or not yet...
return true;
}
Tomahawk::result_ptr* result = reinterpret_cast<Tomahawk::result_ptr*>(qptr);
if ( result && !result->isNull() )
{
qDebug() << "Dropped result item:" << result->data()->artist() << "-" << result->data()->track();
query_ptr q = result->data()->toQuery();
q->addResults( QList< result_ptr >() << *result );
queries << q;
}
}
}
if ( data->hasFormat( "application/tomahawk.query.list" ) )
{
QByteArray itemData = data->data( "application/tomahawk.query.list" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
while ( !stream.atEnd() )
{
qlonglong qptr;
stream >> qptr;
Tomahawk::query_ptr* query = reinterpret_cast<Tomahawk::query_ptr*>(qptr);
if ( query && !query->isNull() )
{
qDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track();
queries << *query;
}
}
}
if ( queries.count() && !m_playlist.isNull() && m_playlist->author()->isLocal() )
void
PlaylistItem::parsedDroppedTracks( const QList< query_ptr >& tracks)
{
disconnect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
if ( tracks.count() && !m_playlist.isNull() && m_playlist->author()->isLocal() )
{
qDebug() << "on playlist:" << m_playlist->title() << m_playlist->guid() << m_playlist->currentrevision();
m_playlist->addEntries( queries, m_playlist->currentrevision() );
return true;
m_playlist->addEntries( tracks, m_playlist->currentrevision() );
}
return false;
}

View File

@ -43,6 +43,7 @@ protected:
private slots:
void onPlaylistLoaded( Tomahawk::PlaylistRevision revision );
void onPlaylistChanged();
void parsedDroppedTracks( const QList<Tomahawk::query_ptr>& tracks );
private:
bool m_loaded;

View File

@ -32,6 +32,7 @@
#include "viewmanager.h"
#include "utils/logger.h"
#include "globalactionmanager.h"
using namespace Tomahawk;
@ -179,10 +180,7 @@ SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role
QStringList
SourcesModel::mimeTypes() const
{
QStringList types;
types << "application/tomahawk.query.list";
types << "application/tomahawk.result.list";
return types;
return GlobalActionManager::instance()->mimeTypes();
}
@ -216,7 +214,11 @@ SourcesModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int ro
Qt::DropActions
SourcesModel::supportedDropActions() const
{
#ifdef Q_OS_MAC
return Qt::CopyAction | Qt::MoveAction;
#else
return Qt::CopyAction;
#endif
}

View File

@ -431,8 +431,7 @@ SourceTreeView::dragEnterEvent( QDragEnterEvent* event )
qDebug() << Q_FUNC_INFO;
QTreeView::dragEnterEvent( event );
if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" )
|| event->mimeData()->hasFormat( "application/tomahawk.result.list" ) )
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
{
m_dragging = true;
m_dropRect = QRect();
@ -460,8 +459,7 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event )
bool accept = false;
QTreeView::dragMoveEvent( event );
if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" )
|| event->mimeData()->hasFormat( "application/tomahawk.result.list" ) )
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
{
setDirtyRegion( m_dropRect );
const QPoint pos = event->pos();

View File

@ -516,7 +516,7 @@ TomahawkApp::loadUrl( const QString& url )
if ( url.startsWith( "tomahawk://" ) )
return GlobalActionManager::instance()->parseTomahawkLink( url );
else if ( url.contains( "open.spotify.com" ) || url.contains( "spotify:track" ) )
return GlobalActionManager::instance()->parseSpotifyLink( url );
return GlobalActionManager::instance()->openSpotifyLink( url );
else
{
QFile f( url );