1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-24 14:42:53 +02:00

start actually implementing tomahawk-side spotify sync

This commit is contained in:
Leo Franchi
2012-03-18 23:16:49 -04:00
parent ac274a50d3
commit f2c3edb8fe
8 changed files with 419 additions and 60 deletions

View File

@@ -119,8 +119,6 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
setConfiguration( config );
sync();
qDebug() << "SET SPOTIFY CREDS:" << credentials().value( "username" ) << credentials().value( "password" );
return;
}
@@ -128,10 +126,11 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
const QString qid = msg.value( "qid" ).toString();
if ( m_qidToSlotMap.contains( qid ) )
{
const QString& slot = m_qidToSlotMap[ qid ];
QObject* receiver = m_qidToSlotMap[ qid ].first;
const QString& slot = m_qidToSlotMap[ qid ].second;
m_qidToSlotMap.remove( qid );
QMetaObject::invokeMethod( this, slot.toLatin1(), Q_ARG( QString, msgType ), Q_ARG( QVariantMap, msg ) );
QMetaObject::invokeMethod( receiver, slot.toLatin1(), Q_ARG( QString, msgType ), Q_ARG( QVariantMap, msg ) );
}
else if ( msgType == "allPlaylists" )
{
@@ -160,6 +159,63 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists );
}
}
else if ( msgType == "tracksAdded" )
{
const QString plid = msg.value( "playlistid" ).toString();
// We should already be syncing this playlist if we get updates for it
Q_ASSERT( m_updaters.contains( plid ) );
if ( !m_updaters.contains( plid ) )
return;
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
Q_ASSERT( updater->sync() );
const int startPos = msg.value( "startPosition" ).toInt();
const QVariantList tracksList = msg.value( "tracks" ).toList();
const QString newRev = msg.value( "revid" ).toString();
const QString oldRev = msg.value( "oldRev" ).toString();
updater->spotifyTracksAdded( tracksList, startPos, newRev, oldRev );
}
else if ( msgType == "tracksRemoved" )
{
const QString plid = msg.value( "playlistid" ).toString();
// We should already be syncing this playlist if we get updates for it
Q_ASSERT( m_updaters.contains( plid ) );
if ( !m_updaters.contains( plid ) )
return;
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
Q_ASSERT( updater->sync() );
const QVariantList tracksList = msg.value( "tracks" ).toList();
const QString newRev = msg.value( "revid" ).toString();
const QString oldRev = msg.value( "oldRev" ).toString();
updater->spotifyTracksRemoved( tracksList, newRev, oldRev );
}
else if ( msgType == "tracksMoved" )
{
const QString plid = msg.value( "playlistid" ).toString();
// We should already be syncing this playlist if we get updates for it
Q_ASSERT( m_updaters.contains( plid ) );
if ( !m_updaters.contains( plid ) )
return;
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
Q_ASSERT( updater->sync() );
const QVariantList tracksList = msg.value( "tracks" ).toList();
const QString newRev = msg.value( "revid" ).toString();
const QString oldRev = msg.value( "oldRev" ).toString();
updater->spotifyTracksMoved( tracksList, newRev, oldRev );
}
else if ( msgType == "playlists" )
{
// QList< Tomahawk::query_ptr > tracks;
@@ -245,7 +301,7 @@ SpotifyAccount::saveConfig()
msg[ "playlistid" ] = pl->plid;
msg[ "sync" ] = pl->sync;
sendMessage( msg, "startPlaylistSyncWithPlaylist" );
sendMessage( msg, this, "startPlaylistSyncWithPlaylist" );
}
else
stopPlaylistSync( pl );
@@ -260,30 +316,43 @@ SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVa
qDebug() << Q_FUNC_INFO << "Got full spotify playlist body, creating a tomahawk playlist and enabling sync!!";
const QString id = msg.value( "id" ).toString();
const QString name = msg.value( "name" ).toString();
const QString revid = msg.value( "revid" ).toString();
qDebug() << "Starting sync with pl:" << id << name;
QVariantList tracks = msg.value( "tracks" ).toList();
// create a list of query/plentries directly
QList< query_ptr > queries;
foreach ( const QVariant& trackV, tracks )
QList< query_ptr > queries = SpotifyPlaylistUpdater::variantToQueries( tracks );
/**
* Begin syncing a playlist. Two options:
* 1) This is a playlist that has never been synced to tomahawk. Create a new one
* and attach a new SpotifyPlaylistUpdater to it
* 2) This was previously synced, and has since been unsynced. THe playlist is still around
* with an inactive SpotifyPlaylistUpdater, so just enable it and bring it up to date by merging current with new
* TODO: show a warning( "Do you want to overwrite with spotify's version?" )
*/
if ( m_updaters.contains( id ) )
{
const QVariantMap trackMap = trackV.toMap();
qDebug() << "Adding spotify track to new tomahawk playlist:" << trackMap.value( "track" ).toString() << trackMap.value( "artist" ).toString() << trackMap.value( "album" ).toString();
query_ptr q = Query::get( trackMap.value( "artist" ).toString(), trackMap.value( "track" ).toString(), trackMap.value( "album" ).toString(), uuid(), false );
q->setProperty( "spotifytrackid", trackMap.value( "id" ) );
queries << q;
Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before
m_updaters[ id ]->setSync( true );
// m_updaters[ id ]->
// TODO
}
else
{
playlist_ptr plPtr = Tomahawk::Playlist::create( SourceList::instance()->getLocal(),
uuid(),
name,
QString(),
QString(),
false,
queries );
playlist_ptr plPtr = Tomahawk::Playlist::create( SourceList::instance()->getLocal(),
uuid(),
name,
QString(),
QString(),
false,
queries );
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( this, plPtr );
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( this, revid, id, plPtr );
updater->setSync( true );
m_updaters[ id ] = updater;
}
}
@@ -341,12 +410,12 @@ SpotifyAccount::addPlaylist( const QString &qid, const QString& title, QList< To
void
SpotifyAccount::sendMessage( const QVariantMap &m, const QString& slot )
SpotifyAccount::sendMessage( const QVariantMap &m, QObject* obj, const QString& slot )
{
QVariantMap msg = m;
const QString qid = QUuid::createUuid().toString().replace( "{", "" ).replace( "}", "" );
m_qidToSlotMap[ qid ] = slot;
m_qidToSlotMap[ qid ] = qMakePair( obj, slot );
msg[ "qid" ] = qid;
m_spotifyResolver.data()->sendMessage( msg );
@@ -354,30 +423,16 @@ SpotifyAccount::sendMessage( const QVariantMap &m, const QString& slot )
void
SpotifyAccount::fetchFullPlaylist( SpotifyPlaylistInfo* playlist )
SpotifyAccount::registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater )
{
m_updaters[ plId ] = updater;
}
void
SpotifyAccount::startPlaylistSync( SpotifyPlaylistInfo* playlist )
SpotifyAccount::fetchFullPlaylist( SpotifyPlaylistInfo* playlist )
{
/**
* Begin syncing a playlist. Two options:
* 1) This is a playlist that has never been synced to tomahawk. Create a new one
* and attach a new SpotifyPlaylistUpdater to it
* 2) This was previously synced, and has since been unsynced. THe playlist is still around
* with an inactive SpotifyPlaylistUpdater, so just enable it and bring it up to date.
*/
if ( m_updaters.contains( playlist->plid ) )
{
// update and re-sync
}
else
{
}
}
@@ -395,5 +450,5 @@ SpotifyAccount::loadPlaylists()
// TODO cache this and only get changed?
QVariantMap msg;
msg[ "_msgtype" ] = "getAllPlaylists";
sendMessage( msg, "allPlaylistsLoaded" );
sendMessage( msg, this, "allPlaylistsLoaded" );
}

View File

@@ -93,6 +93,9 @@ public:
Tomahawk::playlist_ptr playlist;
};*/
void sendMessage( const QVariantMap& msg, QObject* receiver, const QString& slot );
void registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater );
private slots:
void resolverMessage( const QString& msgType, const QVariantMap& msg );
@@ -103,9 +106,7 @@ private slots:
private:
void init();
void loadPlaylists();
void sendMessage( const QVariantMap& msg, const QString& slot );
void startPlaylistSync( SpotifyPlaylistInfo* playlist );
void stopPlaylistSync( SpotifyPlaylistInfo* playlist );
void fetchFullPlaylist( SpotifyPlaylistInfo* playlist );
@@ -114,7 +115,7 @@ private:
QWeakPointer<SpotifyAccountConfig> m_configWidget;
QWeakPointer<ScriptResolver> m_spotifyResolver;
QMap<QString, QString> m_qidToSlotMap;
QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap;
// List of synced spotify playlists in config UI
QList< SpotifyPlaylistInfo* > m_allSpotifyPlaylists;

View File

@@ -40,15 +40,44 @@ SpotifyUpdaterFactory::create( const Tomahawk::playlist_ptr& pl )
}
}
return new SpotifyPlaylistUpdater( m_account, pl );
// Register the updater with the account
const QString spotifyId = QString( "playlistupdaters/%1" ).arg( pl->guid() );
Q_ASSERT( !spotifyId.isEmpty() );
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( m_account, pl );
m_account->registerUpdaterForPlaylist( spotifyId, updater );
return updater;
}
SpotifyPlaylistUpdater::SpotifyPlaylistUpdater( SpotifyAccount* acct, const playlist_ptr& pl )
: PlaylistUpdaterInterface( pl )
, m_spotify( acct )
, m_sync( false )
{
// values will be loaded from settings
init();
}
SpotifyPlaylistUpdater::SpotifyPlaylistUpdater( SpotifyAccount* acct, const QString& revid, const QString& spotifyId, const playlist_ptr& pl )
: PlaylistUpdaterInterface( pl )
, m_spotify( acct )
, m_latestRev( revid )
, m_spotifyId( spotifyId )
, m_sync( false )
{
init();
}
void
SpotifyPlaylistUpdater::init()
{
connect( playlist().data(), SIGNAL( tracksInserted( QList<Tomahawk::plentry_ptr>, int ) ), this, SLOT( tomahawkTracksInserted( QList<Tomahawk::plentry_ptr>, int ) ) );
connect( playlist().data(), SIGNAL( tracksRemoved( QList<Tomahawk::query_ptr> ) ), this, SLOT( tomahawkTracksRemoved( QList<Tomahawk::query_ptr> ) ) );
// TODO reorders in a playlist
}
@@ -60,30 +89,217 @@ SpotifyPlaylistUpdater::~SpotifyPlaylistUpdater()
void
SpotifyPlaylistUpdater::loadFromSettings( const QString& group )
{
m_latestRev = TomahawkSettings::instance()->value( QString( "%1/latestrev" ).arg( group ) ).toString();
m_sync = TomahawkSettings::instance()->value( QString( "%1/sync" ).arg( group ) ).toBool();
m_spotifyId = TomahawkSettings::instance()->value( QString( "%1/spotifyId" ).arg( group ) ).toString();
}
void
SpotifyPlaylistUpdater::removeFromSettings( const QString& group ) const
{
TomahawkSettings::instance()->remove( QString( "%1/latestrev" ).arg( group ) );
TomahawkSettings::instance()->remove( QString( "%1/sync" ).arg( group ) );
TomahawkSettings::instance()->remove( QString( "%1/spotifyId" ).arg( group ) );
}
void
SpotifyPlaylistUpdater::saveToSettings( const QString& group ) const
{
TomahawkSettings::instance()->setValue( QString( "%1/latestrev" ).arg( group ), m_latestRev );
TomahawkSettings::instance()->setValue( QString( "%1/sync" ).arg( group ), m_sync );
TomahawkSettings::instance()->setValue( QString( "%1/spotifyId" ).arg( group ), m_spotifyId );
}
QString
SpotifyPlaylistUpdater::type() const
{
return QString();
return "spotify";
}
void
SpotifyPlaylistUpdater::updateNow()
SpotifyPlaylistUpdater::setSync( bool sync )
{
m_sync = sync;
}
bool
SpotifyPlaylistUpdater::sync() const
{
return m_sync;
}
void
SpotifyPlaylistUpdater::spotifyTracksAdded( const QVariantList& tracks, int startPos, const QString& newRev, const QString& oldRev )
{
const QList< query_ptr > queries = variantToQueries( tracks );
qDebug() << Q_FUNC_INFO << "inserting tracks in middle of tomahawk playlist, from spotify command!" << tracks << startPos << newRev << oldRev;
// Uh oh, dont' want to get out of sync!!
Q_ASSERT( m_latestRev == oldRev );
m_latestRev = newRev;
playlist()->insertEntries( queries, startPos, playlist()->currentrevision() );
}
void
SpotifyPlaylistUpdater::spotifyTracksRemoved( const QVariantList& tracks, const QString& newRev, const QString& oldRev )
{
qDebug() << Q_FUNC_INFO << "remove tracks in middle of tomahawk playlist, from spotify command!" << tracks << newRev << oldRev;
// Uh oh, dont' want to get out of sync!!
Q_ASSERT( m_latestRev == oldRev );
m_latestRev = newRev;
QList< plentry_ptr > entries = playlist()->entries();
// FIXME UGH have to do a manual lookup for each track we want to remove... any ideas?
foreach( const QVariant& blob, tracks )
{
const QVariantMap trackMap = blob.toMap();
for ( QList<plentry_ptr>::iterator iter = entries.begin(); iter != entries.end(); ++iter )
{
const QString trackId = iter->data()->query()->property( "spotifytrackid" ).toString();
// easy case, we have a track id on both sides, so we're sure
if ( trackId.isEmpty() && trackId == trackMap.value( "id" ).toString() )
{
iter = entries.erase( iter );
continue;
}
// fuzzy case, check metadata
if ( iter->data()->query()->track() == trackMap[ "track" ].toString() &&
iter->data()->query()->artist() == trackMap[ "artist" ].toString() &&
iter->data()->query()->album() == trackMap[ "album" ].toString() )
{
iter = entries.erase( iter );
continue;
}
}
}
qDebug() << "We were asked to delete:" << tracks.size() << "tracks from the playlist, and we deleted:" << ( playlist()->entries().size() - entries.size() );
playlist()->createNewRevision( uuid(), playlist()->currentrevision(), entries );
}
void
SpotifyPlaylistUpdater::spotifyTracksMoved( const QVariantList& tracks, const QString& newRev, const QString& oldRev )
{
// TODO
}
void
SpotifyPlaylistUpdater::tomahawkTracksInserted( const QList< plentry_ptr >& tracks, int pos )
{
// Notify the resolver that we've updated
qDebug() << Q_FUNC_INFO << "updating spotify resolver with inserted tracks at:" << pos << tracks;
QVariantMap msg;
msg[ "_msgtype" ] = "addTracksToPlaylist";
msg[ "oldrev" ] = m_latestRev;
msg[ "startPosition" ] = pos;
QVariantList tracksJson;
foreach ( const plentry_ptr& ple, tracks )
{
const query_ptr q = ple->query();
if ( q.isNull() )
{
qDebug() << "Got null query_ptr in plentry_ptr!!!" << ple;
continue;
}
tracksJson << queryToVariant( q );
}
msg[ "tracks" ] = tracksJson;
m_spotify->sendMessage( msg, this, "onTracksInsertedReturn" );
}
void
SpotifyPlaylistUpdater::onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg )
{
const bool success = msg.value( "success" ).toBool();
qDebug() << Q_FUNC_INFO << "GOT RETURN FOR tracksInserted call from spotify!" << msgType << msg << "Succeeded?" << success;
m_latestRev = msg.value( "revid" ).toString();
}
void
SpotifyPlaylistUpdater::tomahawkTracksRemoved( const QList< query_ptr >& tracks )
{
qDebug() << Q_FUNC_INFO << "updating spotify resolver with removed tracks:" << tracks;
QVariantMap msg;
msg[ "_msgtype" ] = "removeTracksFromPlaylist";
msg[ "oldrev" ] = m_latestRev;
msg[ "tracks" ] = queriesToVariant( tracks );
m_spotify->sendMessage( msg, this, "onTracksRemovedReturn" );
}
void
SpotifyPlaylistUpdater::onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg )
{
const bool success = msg.value( "success" ).toBool();
qDebug() << Q_FUNC_INFO << "GOT RETURN FOR tracksRemoved call from spotify!" << msgType << msg << "Succeeded?" << success;
m_latestRev = msg.value( "revid" ).toString();
}
QVariantList
SpotifyPlaylistUpdater::queriesToVariant( const QList< query_ptr >& queries )
{
QVariantList tracksJson;
foreach ( const query_ptr& q, queries )
{
QVariantMap m;
if ( q.isNull() )
continue;
tracksJson << queryToVariant( q );
}
return tracksJson;
}
QVariant
SpotifyPlaylistUpdater::queryToVariant( const query_ptr& query )
{
QVariantMap m;
m[ "track" ] = query->track();
m[ "artist" ] = query->artist();
m[ "album" ] = query->album();
if ( !query->property( "spotifytrackid" ).isNull() )
m[ "id" ] = query->property( "spotifytrackid" );
return m;
}
QList< query_ptr >
SpotifyPlaylistUpdater::variantToQueries( const QVariantList& list )
{
QList< query_ptr > queries;
foreach ( const QVariant& blob, list )
{
QVariantMap trackMap = blob.toMap();
const query_ptr q = Query::get( trackMap.value( "artist" ).toString(), trackMap.value( "track" ).toString(), trackMap.value( "album" ).toString(), uuid(), false );
if ( trackMap.contains( "id" ) )
q->setProperty( "spotifytrackid", trackMap.value( "id" ) );
queries << q;
}
return queries;
}

View File

@@ -20,6 +20,7 @@
#define SPOTIFYPLAYLISTUPDATER_H
#include "playlist/PlaylistUpdaterInterface.h"
#include <QVariant>
namespace Tomahawk {
namespace Accounts {
@@ -27,25 +28,53 @@ namespace Accounts {
}
}
class SpotifyPlaylistUpdater : public Tomahawk::PlaylistUpdaterInterface
{
Q_OBJECT
friend class Tomahawk::Accounts::SpotifyAccount;
public:
// used when creating anew
SpotifyPlaylistUpdater( Tomahawk::Accounts::SpotifyAccount* acct, const QString& revid, const QString& spotifyId, const Tomahawk::playlist_ptr& pl );
// used when inflating from config file
SpotifyPlaylistUpdater( Tomahawk::Accounts::SpotifyAccount* acct, const Tomahawk::playlist_ptr& pl );
virtual ~SpotifyPlaylistUpdater();
virtual QString type() const;
virtual void updateNow();
virtual void updateNow() {}
bool sync() const;
void setSync( bool sync );
/// Spotify callbacks when we are directly instructed from the resolver
void spotifyTracksAdded( const QVariantList& tracks, int startPos, const QString& newRev, const QString& oldRev );
void spotifyTracksRemoved( const QVariantList& tracks, const QString& newRev, const QString& oldRev );
void spotifyTracksMoved( const QVariantList& tracks, const QString& newRev, const QString& oldRev );
protected:
virtual void removeFromSettings(const QString& group) const;
virtual void saveToSettings(const QString& group) const;
virtual void loadFromSettings(const QString& group);
private slots:
void tomahawkTracksInserted( const QList<Tomahawk::plentry_ptr>& ,int );
void tomahawkTracksRemoved( const QList<Tomahawk::query_ptr>& );
// SpotifyResolver message handlers, all take msgtype, msg as argument
void onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg );
void onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg );
private:
void init();
static QVariantList queriesToVariant( const QList< Tomahawk::query_ptr >& queries );
static QVariant queryToVariant( const Tomahawk::query_ptr& query );
static QList< Tomahawk::query_ptr > variantToQueries( const QVariantList& list );
Tomahawk::Accounts::SpotifyAccount* m_spotify;
QString m_latestRev, m_spotifyId;
bool m_sync;
};

View File

@@ -1,6 +1,7 @@
/* === 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
@@ -517,6 +518,27 @@ Playlist::addEntries( const QList<query_ptr>& queries, const QString& oldrev )
createNewRevision( newrev, oldrev, el );
}
void
Playlist::insertEntries( const QList< query_ptr >& queries, const int position, const QString& oldrev )
{
QList<plentry_ptr> toInsert = entriesFromQueries( queries, true );
QList<plentry_ptr> entries = m_entries;
Q_ASSERT( position < m_entries.size() );
if ( position >= m_entries.size() )
{
qWarning() << "ERROR trying to insert tracks past end of playlist! Appending!!";
addEntries( queries, oldrev );
return;
}
for ( QList< plentry_ptr >::iterator iter = toInsert.end(); iter != toInsert.begin(); iter-- )
entries.insert( position, *iter );
qDebug() << "Done inserting playlist entries in the middle of the playlist! Committing...";
createNewRevision( uuid(), oldrev, entries );
}
QList<plentry_ptr>
Playlist::entriesFromQueries( const QList<Tomahawk::query_ptr>& queries, bool clearFirst )

View File

@@ -1,6 +1,7 @@
/* === 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
@@ -37,6 +38,8 @@ class DatabaseCommand_LoadAllPlaylists;
class DatabaseCommand_LoadAllSortedPlaylists;
class DatabaseCommand_SetPlaylistRevision;
class DatabaseCommand_CreatePlaylist;
class PlaylistModel;
namespace Tomahawk
{
@@ -116,20 +119,21 @@ public:
class DLLEXPORT Playlist : public QObject
{
Q_OBJECT
Q_PROPERTY( QString guid READ guid WRITE setGuid )
Q_PROPERTY( QString currentrevision READ currentrevision WRITE setCurrentrevision )
Q_PROPERTY( QString title READ title WRITE setTitle )
Q_PROPERTY( QString info READ info WRITE setInfo )
Q_PROPERTY( QString creator READ creator WRITE setCreator )
Q_PROPERTY( unsigned int createdon READ createdOn WRITE setCreatedOn )
Q_PROPERTY( bool shared READ shared WRITE setShared )
Q_OBJECT
Q_PROPERTY( QString guid READ guid WRITE setGuid )
Q_PROPERTY( QString currentrevision READ currentrevision WRITE setCurrentrevision )
Q_PROPERTY( QString title READ title WRITE setTitle )
Q_PROPERTY( QString info READ info WRITE setInfo )
Q_PROPERTY( QString creator READ creator WRITE setCreator )
Q_PROPERTY( unsigned int createdon READ createdOn WRITE setCreatedOn )
Q_PROPERTY( bool shared READ shared WRITE setShared )
friend class ::DatabaseCommand_LoadAllPlaylists;
friend class ::DatabaseCommand_LoadAllSortedPlaylists;
friend class ::DatabaseCommand_SetPlaylistRevision;
friend class ::DatabaseCommand_CreatePlaylist;
friend class DynamicPlaylist;
friend class ::PlaylistModel;
public:
virtual ~Playlist();
@@ -165,6 +169,7 @@ public:
const QList< plentry_ptr >& entries() { return m_entries; }
virtual void addEntry( const Tomahawk::query_ptr& query, const QString& oldrev );
virtual void addEntries( const QList<Tomahawk::query_ptr>& queries, const QString& oldrev );
virtual void insertEntries( const QList<Tomahawk::query_ptr>& queries, const int position, const QString& oldrev );
// <IGNORE hack="true">
// these need to exist and be public for the json serialization stuff
@@ -182,6 +187,7 @@ public:
QList<plentry_ptr> entriesFromQueries( const QList<Tomahawk::query_ptr>& queries, bool clearFirst = false );
void setUpdater( PlaylistUpdaterInterface* interface ) { m_updater = interface; }
PlaylistUpdaterInterface* updater() const { return m_updater; }
@@ -206,6 +212,13 @@ signals:
/// was deleted, eh?
void deleted( const Tomahawk::playlist_ptr& pl );
/// Notification for tracks being inserted at a specific point
/// Contiguous range from startPosition
void tracksInserted( const QList< Tomahawk::plentry_ptr >& tracks, int startPosition );
/// Notification for tracks being removed from playlist
void tracksRemoved( const QList< Tomahawk::query_ptr >& tracks );
public slots:
// want to update the playlist from the model?
// generate a newrev using uuid() and call this:

View File

@@ -40,6 +40,7 @@ PlaylistModel::PlaylistModel( QObject* parent )
: TrackModel( parent )
, m_isTemporary( false )
, m_changesOngoing( false )
, m_savedInsertPos( -1 )
{
m_dropStorage.parent = QPersistentModelIndex();
m_dropStorage.row = -10;
@@ -202,6 +203,9 @@ PlaylistModel::insert( const QList< Tomahawk::plentry_ptr >& entries, int row )
crows.first = c;
crows.second = c + entries.count() - 1;
m_savedInsertPos = row;
m_savedInsertTracks = entries;
emit beginInsertRows( QModelIndex(), crows.first, crows.second );
QList< Tomahawk::query_ptr > queries;
@@ -398,6 +402,18 @@ PlaylistModel::endPlaylistChanges()
{
m_playlist->createNewRevision( newrev, m_playlist->currentrevision(), l );
}
if ( m_savedInsertPos >= 0 )
{
emit m_playlist->tracksInserted( m_savedInsertTracks, m_savedInsertPos );
m_savedInsertPos = -1;
m_savedInsertTracks.clear();
}
else if ( !m_savedRemoveTracks.isEmpty() )
{
emit m_playlist->tracksRemoved( m_savedRemoveTracks );
m_savedRemoveTracks.clear();
}
}
@@ -442,6 +458,9 @@ PlaylistModel::remove( const QModelIndex& index, bool moreToCome )
if ( !m_changesOngoing )
beginPlaylistChanges();
if ( item )
m_savedRemoveTracks << item->query();
TrackModel::remove( index, moreToCome );
if ( !moreToCome )

View File

@@ -100,6 +100,10 @@ private:
QList< Tomahawk::Query* > m_waitingForResolved;
QStringList m_waitForRevision;
int m_savedInsertPos;
QList< Tomahawk::plentry_ptr > m_savedInsertTracks;
QList< Tomahawk::query_ptr > m_savedRemoveTracks;
DropStorageData m_dropStorage;
};