diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/accounts/spotify/SpotifyAccount.cpp index 036d8c4c0..a15047d44 100644 --- a/src/accounts/spotify/SpotifyAccount.cpp +++ b/src/accounts/spotify/SpotifyAccount.cpp @@ -123,8 +123,18 @@ SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist ) return; // If it's not being synced, allow the option to sync - SpotifyPlaylistUpdater* updater = qobject_cast< SpotifyPlaylistUpdater* >( playlist->updater() ); - if ( !updater || !updater->sync() ) + bool found = false; + QList updaters = playlist->updaters(); + foreach ( PlaylistUpdaterInterface* updater, updaters ) + { + if ( SpotifyPlaylistUpdater* spotifyUpdater = qobject_cast< SpotifyPlaylistUpdater* >( updater ) ) + { + if ( spotifyUpdater->sync() ) + found = true; + } + } + + if ( !found ) { action->setText( tr( "Sync with Spotify" ) ); } @@ -152,7 +162,15 @@ SpotifyAccount::syncActionTriggered( bool checked ) return; } - SpotifyPlaylistUpdater* updater = qobject_cast< SpotifyPlaylistUpdater* >( playlist->updater() ); + SpotifyPlaylistUpdater* updater = 0; + QList updaters = playlist->updaters(); + foreach ( PlaylistUpdaterInterface* u, updaters ) + { + if ( SpotifyPlaylistUpdater* spotifyUpdater = qobject_cast< SpotifyPlaylistUpdater* >( u ) ) + { + updater = spotifyUpdater; + } + } if ( !updater ) { diff --git a/src/accounts/spotify/SpotifyPlaylistUpdater.cpp b/src/accounts/spotify/SpotifyPlaylistUpdater.cpp index 7d54a0005..64bdda98f 100644 --- a/src/accounts/spotify/SpotifyPlaylistUpdater.cpp +++ b/src/accounts/spotify/SpotifyPlaylistUpdater.cpp @@ -32,7 +32,7 @@ QPixmap* SpotifyPlaylistUpdater::s_typePixmap = 0; #endif Tomahawk::PlaylistUpdaterInterface* -SpotifyUpdaterFactory::create( const Tomahawk::playlist_ptr& pl, const QString &key ) +SpotifyUpdaterFactory::create( const Tomahawk::playlist_ptr& pl, const QVariantHash &settings ) { if ( !m_account ) { @@ -54,9 +54,9 @@ SpotifyUpdaterFactory::create( const Tomahawk::playlist_ptr& pl, const QString & } // Register the updater with the account - const QString spotifyId = TomahawkSettings::instance()->value( QString( "%1/spotifyId" ).arg( key ) ).toString(); - const QString latestRev = TomahawkSettings::instance()->value( QString( "%1/latestrev" ).arg( key ) ).toString(); - const bool sync = TomahawkSettings::instance()->value( QString( "%1/sync" ).arg( key ) ).toBool(); + const QString spotifyId = settings.value( "spotifyId" ).toString(); + const QString latestRev = settings.value( "latestrev" ).toString(); + const bool sync = settings.value( "sync" ).toBool(); Q_ASSERT( !spotifyId.isEmpty() ); SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( m_account.data(), latestRev, spotifyId, pl ); @@ -89,6 +89,8 @@ SpotifyPlaylistUpdater::init() connect( playlist().data(), SIGNAL( renamed( QString, QString ) ), this, SLOT( tomahawkPlaylistRenamed( QString, QString ) ) ); connect( playlist().data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistRevisionLoaded() ), Qt::QueuedConnection ); // Queued so that in Playlist.cpp:443 we let the playlist clear its own queue first // TODO reorders in a playlist + + saveToSettings(); } @@ -122,12 +124,8 @@ SpotifyPlaylistUpdater::remove( bool askToDeletePlaylist ) void -SpotifyPlaylistUpdater::removeFromSettings( const QString& group ) const +SpotifyPlaylistUpdater::aboutToDelete() { - TomahawkSettings::instance()->remove( QString( "%1/latestrev" ).arg( group ) ); - TomahawkSettings::instance()->remove( QString( "%1/sync" ).arg( group ) ); - TomahawkSettings::instance()->remove( QString( "%1/spotifyId" ).arg( group ) ); - if ( m_sync ) { if ( QThread::currentThread() != QApplication::instance()->thread() ) @@ -173,11 +171,15 @@ SpotifyPlaylistUpdater::playlistRevisionLoaded() void -SpotifyPlaylistUpdater::saveToSettings( const QString& group ) const +SpotifyPlaylistUpdater::saveToSettings() { - 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 ); + QVariantHash s = settings(); + + s[ "latestrev" ] = m_latestRev; + s[ "sync" ] = m_sync; + s[ "spotifyId" ] = m_spotifyId; + + saveSettings( s ); } @@ -214,6 +216,7 @@ SpotifyPlaylistUpdater::setSync( bool sync ) m_sync = sync; + saveToSettings(); emit changed(); } @@ -543,6 +546,9 @@ SpotifyPlaylistUpdater::onTracksInsertedReturn( const QString& msgType, const QV if ( changed.size() > 0 ) playlist()->updateEntries( uuid(), playlist()->currentrevision(), changed ); + // Update with latest rev when/if we use it +// saveToSettings(); + } diff --git a/src/accounts/spotify/SpotifyPlaylistUpdater.h b/src/accounts/spotify/SpotifyPlaylistUpdater.h index d0c987191..d07fc172a 100644 --- a/src/accounts/spotify/SpotifyPlaylistUpdater.h +++ b/src/accounts/spotify/SpotifyPlaylistUpdater.h @@ -67,9 +67,9 @@ public slots: void tomahawkTracksRemoved( const QList& ); void tomahawkTracksMoved( const QList& ,int ); void tomahawkPlaylistRenamed( const QString&, const QString& ); + protected: - virtual void removeFromSettings(const QString& group) const; - virtual void saveToSettings(const QString& group) const; + void aboutToDelete(); private slots: // SpotifyResolver message handlers, all take msgtype, msg as argument @@ -82,6 +82,8 @@ private slots: void playlistRevisionLoaded(); private: void init(); + void saveToSettings(); + /// Finds the nearest spotify id from pos to the beginning of the playlist QString nearestSpotifyTrack( const QList< Tomahawk::plentry_ptr >& entries, int pos ); QVariantList plentryToVariant( const QList< Tomahawk::plentry_ptr >& entries ); @@ -109,7 +111,7 @@ class SpotifyUpdaterFactory : public Tomahawk::PlaylistUpdaterFactory public: SpotifyUpdaterFactory() {} - virtual Tomahawk::PlaylistUpdaterInterface* create( const Tomahawk::playlist_ptr& pl, const QString& key ); + virtual Tomahawk::PlaylistUpdaterInterface* create( const Tomahawk::playlist_ptr& pl, const QVariantHash& settings ); virtual QString type() const { return "spotify"; } private: diff --git a/src/libtomahawk/Playlist.cpp b/src/libtomahawk/Playlist.cpp index a93431560..bbda7ed5f 100644 --- a/src/libtomahawk/Playlist.cpp +++ b/src/libtomahawk/Playlist.cpp @@ -270,8 +270,11 @@ void Playlist::reportDeleted( const Tomahawk::playlist_ptr& self ) { Q_ASSERT( self.data() == this ); - if ( !m_updater.isNull() ) - m_updater.data()->remove(); + if ( !m_updaters.isEmpty() ) + { + foreach( PlaylistUpdaterInterface* updater, m_updaters ) + updater->remove(); + } m_deleted = true; m_source->collection()->deletePlaylist( self ); @@ -280,24 +283,25 @@ Playlist::reportDeleted( const Tomahawk::playlist_ptr& self ) } void -Playlist::setUpdater( PlaylistUpdaterInterface* pluinterface ) +Playlist::addUpdater( PlaylistUpdaterInterface* updater ) { - if ( !m_updater.isNull() ) - disconnect( m_updater.data(), SIGNAL( changed() ), this, SIGNAL( changed() ) ); + m_updaters << updater; - m_updater = QWeakPointer< PlaylistUpdaterInterface >( pluinterface ); - - connect( m_updater.data(), SIGNAL( changed() ), this, SIGNAL( changed() ), Qt::UniqueConnection ); - connect( m_updater.data(), SIGNAL( destroyed( QObject* ) ), this, SLOT( updaterDestroyed() ), Qt::QueuedConnection ); + connect( updater, SIGNAL( changed() ), this, SIGNAL( changed() ), Qt::UniqueConnection ); + connect( updater, SIGNAL( destroyed( QObject* ) ), this, SIGNAL( changed() ), Qt::QueuedConnection ); emit changed(); } void -Playlist::updaterDestroyed() +Playlist::removeUpdater( PlaylistUpdaterInterface* updater ) { - m_updater.clear(); + m_updaters.removeAll( updater ); + + disconnect( updater, SIGNAL( changed() ), this, SIGNAL( changed() ) ); + disconnect( updater, SIGNAL( destroyed( QObject* ) ), this, SIGNAL( changed() ) ); + emit changed(); } diff --git a/src/libtomahawk/Playlist.h b/src/libtomahawk/Playlist.h index 87f9fa55f..649468086 100644 --- a/src/libtomahawk/Playlist.h +++ b/src/libtomahawk/Playlist.h @@ -188,8 +188,10 @@ public: QList entriesFromQueries( const QList& queries, bool clearFirst = false ); - void setUpdater( PlaylistUpdaterInterface* pluinterface ); - PlaylistUpdaterInterface* updater() const { return m_updater.data(); } + + void addUpdater( PlaylistUpdaterInterface* updater ); + void removeUpdater( PlaylistUpdaterInterface* updater ); + QList updaters() const { return m_updaters; } Tomahawk::playlistinterface_ptr playlistInterface(); @@ -278,7 +280,6 @@ protected: private slots: void onResultsFound( const QList& results ); void onResolvingFinished(); - void updaterDestroyed(); private: Playlist(); @@ -300,7 +301,7 @@ private: QQueue m_revisionQueue; QQueue m_updateQueue; - QWeakPointer m_updater; + QList m_updaters; bool m_locallyChanged; bool m_deleted; diff --git a/src/libtomahawk/TomahawkSettings.cpp b/src/libtomahawk/TomahawkSettings.cpp index 1c79b0493..48a662765 100644 --- a/src/libtomahawk/TomahawkSettings.cpp +++ b/src/libtomahawk/TomahawkSettings.cpp @@ -30,11 +30,50 @@ #include "database/DatabaseCommand_UpdateSearchIndex.h" #include "database/Database.h" +#include "PlaylistUpdaterInterface.h" using namespace Tomahawk; TomahawkSettings* TomahawkSettings::s_instance = 0; + +inline QDataStream& +operator<<(QDataStream& out, const PlaylistUpdaterInterface::SerializedUpdaters& updaters) +{ + out << TOMAHAWK_SETTINGS_VERSION; + out << (quint32)updaters.count(); + foreach( const QString& key, updaters.keys() ) + { + PlaylistUpdaterInterface::SerializedUpdater updater = updaters[ key ]; + out << key << updater.type << updater.customData; + } + return out; +} + + +inline QDataStream& +operator>>(QDataStream& in, PlaylistUpdaterInterface::SerializedUpdaters& updaters) +{ + quint32 count = 0, version = 0; + in >> version; + in >> count; + + for ( uint i = 0; i < count; i++ ) + { + QString key, type; + bool sync; + QVariantHash customData; + qint32 state, userRating; + in >> key; + in >> type; + in >> customData; + updaters[ key ] = PlaylistUpdaterInterface::SerializedUpdater( type, customData ); + } + + return in; +} + + TomahawkSettings* TomahawkSettings::instance() { @@ -444,6 +483,38 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) setValue( "allaccounts", allAccounts ); endGroup(); } + else if ( oldVersion == 9 ) + { + // Upgrade single-updater-per-playlist to list-per-playlist + beginGroup( "playlistupdaters" ); + const QStringList playlists = childGroups(); + + PlaylistUpdaterInterface::SerializedUpdaters updaters; + foreach ( const QString& playlist, playlists ) + { + beginGroup( playlist ); + const QString type = value( "type" ).toString(); + + QVariantHash extraData; + foreach ( const QString& key, childKeys() ) + { + if ( key == "type" ) + continue; + + extraData[ key ] = value( key ); + } + + updaters[ playlist ] = PlaylistUpdaterInterface::SerializedUpdater( type, extraData ); + + endGroup(); + } + + endGroup(); + + setPlaylistUpdaters( updaters ); + + remove( "playlistupdaters" ); + } } @@ -1174,3 +1245,26 @@ TomahawkSettings::setImportXspfPath( const QString& path ) { setValue( "importXspfPath", path ); } + + +PlaylistUpdaterInterface::SerializedUpdaters +TomahawkSettings::playlistUpdaters() const +{ + return value( "playlist/updaters" ).value< PlaylistUpdaterInterface::SerializedUpdaters >(); +} + + +void +TomahawkSettings::setPlaylistUpdaters( const PlaylistUpdaterInterface::SerializedUpdaters& updaters ) +{ + setValue( "playlist/updaters", QVariant::fromValue< PlaylistUpdaterInterface::SerializedUpdaters >( updaters ) ); +} + + +void +TomahawkSettings::registerCustomSettingsHandlers() +{ + qRegisterMetaType< Tomahawk::PlaylistUpdaterInterface::SerializedUpdater >( "Tomahawk::PlaylistUpdaterInterface::SerializedUpdater" ); + qRegisterMetaType< Tomahawk::PlaylistUpdaterInterface::SerializedUpdaters >( "Tomahawk::PlaylistUpdaterInterface::SerializedUpdaters" ); + qRegisterMetaTypeStreamOperators< Tomahawk::PlaylistUpdaterInterface::SerializedUpdaters >( "Tomahawk::PlaylistUpdaterInterface::SerializedUpdaters" ); +} diff --git a/src/libtomahawk/TomahawkSettings.h b/src/libtomahawk/TomahawkSettings.h index 65e6d84ea..6c3fc9f7c 100644 --- a/src/libtomahawk/TomahawkSettings.h +++ b/src/libtomahawk/TomahawkSettings.h @@ -23,12 +23,14 @@ #include "Playlist.h" +#include "playlist/PlaylistUpdaterInterface.h" + #include #include #include "DllMacro.h" -#define TOMAHAWK_SETTINGS_VERSION 9 +#define TOMAHAWK_SETTINGS_VERSION 10 /** * Convenience wrapper around QSettings for tomahawk-specific config @@ -201,6 +203,11 @@ public: void setImportXspfPath( const QString& path ); QString importXspfPath() const; + Tomahawk::PlaylistUpdaterInterface::SerializedUpdaters playlistUpdaters() const; + void setPlaylistUpdaters( const Tomahawk::PlaylistUpdaterInterface::SerializedUpdaters& updaters ); + + static void registerCustomSettingsHandlers(); + signals: void changed(); void recentlyPlayedPlaylistAdded( const Tomahawk::playlist_ptr& playlist ); diff --git a/src/libtomahawk/TomahawkSettingsGui.cpp b/src/libtomahawk/TomahawkSettingsGui.cpp index 2c76d1fd6..dea0c5236 100644 --- a/src/libtomahawk/TomahawkSettingsGui.cpp +++ b/src/libtomahawk/TomahawkSettingsGui.cpp @@ -23,6 +23,38 @@ using namespace Tomahawk; +inline QDataStream& operator<<(QDataStream& out, const AtticaManager::StateHash& states) +{ + out << TOMAHAWK_SETTINGS_VERSION; + out << (quint32)states.count(); + foreach( const QString& key, states.keys() ) + { + AtticaManager::Resolver resolver = states[ key ]; + out << key << resolver.version << resolver.scriptPath << (qint32)resolver.state << resolver.userRating; + } + return out; +} + + +inline QDataStream& operator>>(QDataStream& in, AtticaManager::StateHash& states) +{ + quint32 count = 0, version = 0; + in >> version; + in >> count; + for ( uint i = 0; i < count; i++ ) + { + QString key, version, scriptPath; + qint32 state, userRating; + in >> key; + in >> version; + in >> scriptPath; + in >> state; + in >> userRating; + states[ key ] = AtticaManager::Resolver( version, scriptPath, userRating, (AtticaManager::ResolverState)state ); + } + return in; +} + TomahawkSettingsGui* TomahawkSettingsGui::instanceGui() { @@ -91,3 +123,11 @@ TomahawkSettingsGui::removeAtticaResolverState ( const QString& resolver ) resolvers.remove( resolver ); setValue( "script/atticaresolverstates", QVariant::fromValue< AtticaManager::StateHash >( resolvers ) ); } + + +void +TomahawkSettingsGui::registerCustomSettingsHandlers() +{ + qRegisterMetaType< AtticaManager::StateHash >( "AtticaManager::StateHash" ); + qRegisterMetaTypeStreamOperators("AtticaManager::StateHash"); +} diff --git a/src/libtomahawk/TomahawkSettingsGui.h b/src/libtomahawk/TomahawkSettingsGui.h index 51eaf30e7..d016dd815 100644 --- a/src/libtomahawk/TomahawkSettingsGui.h +++ b/src/libtomahawk/TomahawkSettingsGui.h @@ -47,6 +47,8 @@ public: void setAtticaResolverState( const QString& resolver, AtticaManager::ResolverState state ); void removeAtticaResolverState( const QString& resolver ); + + static void registerCustomSettingsHandlers(); }; Q_DECLARE_METATYPE(AtticaManager::StateHash); diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index ef2676c3c..56a57df17 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -745,7 +745,7 @@ ViewManager::updateView() m_infobar->setVisible( currentPage()->showInfoBar() ); m_infobar->setCaption( currentPage()->title() ); - m_infobar->setAutoUpdateInterface( currentPage()->autoUpdateInterface() ); + m_infobar->setUpdaters( currentPage()->updaters() ); switch( currentPage()->descriptionType() ) { diff --git a/src/libtomahawk/ViewPage.h b/src/libtomahawk/ViewPage.h index 14307ce95..2398c9e04 100644 --- a/src/libtomahawk/ViewPage.h +++ b/src/libtomahawk/ViewPage.h @@ -25,13 +25,13 @@ #include "Artist.h" #include "Album.h" #include "utils/TomahawkUtils.h" +#include "playlist/PlaylistUpdaterInterface.h" #include namespace Tomahawk { -class PlaylistUpdaterInterface; class DLLEXPORT ViewPage { @@ -69,8 +69,7 @@ public: virtual bool isTemporaryPage() const { return false; } virtual bool isBeingPlayed() const { return false; } - virtual bool canAutoUpdate() const { return false; } - virtual PlaylistUpdaterInterface* autoUpdateInterface() const { return 0; } + virtual QList updaters() const { return QList(); } /** subclasses implementing ViewPage can emit the following signals: * nameChanged( const QString& ) diff --git a/src/libtomahawk/infobar/InfoBar.cpp b/src/libtomahawk/infobar/InfoBar.cpp index cabfd8358..0f999e5f7 100644 --- a/src/libtomahawk/infobar/InfoBar.cpp +++ b/src/libtomahawk/infobar/InfoBar.cpp @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2012, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,8 +41,6 @@ using namespace Tomahawk; InfoBar::InfoBar( QWidget* parent ) : QWidget( parent ) , ui( new Ui::InfoBar ) - , m_updaterInterface( 0 ) - , m_updaterConfiguration( 0 ) , m_queryLabel( 0 ) { ui->setupUi( this ); @@ -202,21 +201,31 @@ InfoBar::setFilterAvailable( bool b ) void -InfoBar::setAutoUpdateInterface( PlaylistUpdaterInterface *interface ) +InfoBar::setUpdaters( const QList& updaters ) { - if ( m_updaterConfiguration ) - m_updaterConfiguration->hide(); + QList< QWidget* > newUpdaterWidgets; + foreach ( PlaylistUpdaterInterface* updater, updaters ) + { + if ( updater->configurationWidget() ) + newUpdaterWidgets << updater->configurationWidget(); + } - if ( m_updaterConfiguration && ( interface ? (m_updaterConfiguration != interface->configurationWidget()) : true ) ) - ui->horizontalLayout->removeWidget( m_updaterConfiguration ); - m_updaterInterface = interface; - m_updaterConfiguration = interface ? interface->configurationWidget() : 0; + foreach ( QWidget* updaterWidget, m_updaterConfigurations ) + { + updaterWidget->hide(); - if ( !m_updaterInterface || !m_updaterConfiguration ) - return; + if ( !newUpdaterWidgets.contains( updaterWidget ) ) + { + // Old config widget no longer present, remove it + ui->horizontalLayout->removeWidget( updaterWidget ); + } + } - m_updaterConfiguration->setPalette( m_whitePal ); + m_updaters = updaters; + m_updaterConfigurations = newUpdaterWidgets; + + // Display each new widget in the proper place int insertIdx = -1; // Ugh, no indexOf for QSpacerItem* for ( int i = 0; i < ui->horizontalLayout->count(); i++ ) { @@ -227,9 +236,40 @@ InfoBar::setAutoUpdateInterface( PlaylistUpdaterInterface *interface ) } } insertIdx++; - ui->horizontalLayout->insertWidget( insertIdx, m_updaterConfiguration ); - m_updaterConfiguration->show(); + foreach ( QWidget* updaterWidget, m_updaterConfigurations ) + { + updaterWidget->setPalette( m_whitePal ); + ui->horizontalLayout->insertWidget( insertIdx, updaterWidget ); + updaterWidget->show(); + } + +// if ( m_updaterConfiguration ) +// m_updaterConfiguration->hide(); +// +// if ( m_updaterConfiguration && ( interface ? (m_updaterConfiguration != interface->configurationWidget()) : true ) ) +// ui->horizontalLayout->removeWidget( m_updaterConfiguration ); +// +// m_updaterInterface = interface; +// m_updaterConfiguration = interface ? interface->configurationWidget() : 0; +// +// if ( !m_updaterInterface || !m_updaterConfiguration ) +// return; +// +// m_updaterConfiguration->setPalette( m_whitePal ); +// int insertIdx = -1; // Ugh, no indexOf for QSpacerItem* +// for ( int i = 0; i < ui->horizontalLayout->count(); i++ ) +// { +// if ( ui->horizontalLayout->itemAt( i )->spacerItem() == ui->horizontalSpacer_4 ) +// { +// insertIdx = i; +// break; +// } +// } +// insertIdx++; +// ui->horizontalLayout->insertWidget( insertIdx, m_updaterConfiguration ); +// +// m_updaterConfiguration->show(); } diff --git a/src/libtomahawk/infobar/InfoBar.h b/src/libtomahawk/infobar/InfoBar.h index cc4b9cc55..b69aed592 100644 --- a/src/libtomahawk/infobar/InfoBar.h +++ b/src/libtomahawk/infobar/InfoBar.h @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2012, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -62,7 +63,7 @@ public slots: void setFilter( const QString& filter ); void setFilterAvailable( bool b ); - void setAutoUpdateInterface( Tomahawk::PlaylistUpdaterInterface* interface ); + void setUpdaters( const QList& updaters ); signals: void filterTextChanged( const QString& filter ); @@ -82,8 +83,8 @@ private: QPixmap m_bgTile; QPalette m_whitePal; - Tomahawk::PlaylistUpdaterInterface* m_updaterInterface; - QWidget* m_updaterConfiguration; + QList m_updaters;; + QList m_updaterConfigurations; QSearchField* m_searchWidget; QueryLabel* m_queryLabel; diff --git a/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp b/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp index f36c895be..e5eb35d6d 100644 --- a/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp +++ b/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp @@ -35,21 +35,22 @@ PlaylistUpdaterInterface* PlaylistUpdaterInterface::loadForPlaylist( const playlist_ptr& pl ) { TomahawkSettings* s = TomahawkSettings::instance(); - const QString key = QString( "playlistupdaters/%1" ).arg( pl->guid() ); - if ( s->contains( QString( "%1/type" ).arg( key ) ) ) + + const SerializedUpdaters updaters = s->playlistUpdaters(); + if ( updaters.contains( pl->guid() ) ) { // Ok, we have one we can try to load - const QString type = s->value( QString( "%1/type" ).arg( key ) ).toString(); PlaylistUpdaterInterface* updater = 0; + const SerializedUpdater info = updaters[ pl->guid() ]; - if ( !s_factories.contains( type ) ) + if ( !s_factories.contains( info.type ) ) { Q_ASSERT( false ); // You forgot to register your new updater type with the factory.... return 0; } - updater = s_factories[ type ]->create( pl, key ); + updater = s_factories[ info.type ]->create( pl, info.customData ); return updater; } @@ -63,22 +64,35 @@ PlaylistUpdaterInterface::PlaylistUpdaterInterface( const playlist_ptr& pl ) { Q_ASSERT( !m_playlist.isNull() ); - m_playlist->setUpdater( this ); + m_playlist->addUpdater( this ); QTimer::singleShot( 0, this, SLOT( save() ) ); } +PlaylistUpdaterInterface::~PlaylistUpdaterInterface() +{ + if ( !m_playlist.isNull() ) + m_playlist->removeUpdater( this ); +} + + void PlaylistUpdaterInterface::save() { + if ( m_playlist.isNull() ) + return; + TomahawkSettings* s = TomahawkSettings::instance(); - const QString key = QString( "playlistupdaters/%1" ).arg( m_playlist->guid() ); - if ( !s->contains( QString( "%1/type" ).arg( key ) ) ) - { - s->setValue( QString( "%1/type" ).arg( key ), type() ); - } - saveToSettings( key ); + + SerializedUpdaters updaters = s->playlistUpdaters(); + + SerializedUpdater updater = updaters.value( m_playlist ->guid() ); + updater.type = type(); + updater.customData = m_extraData; + updaters[ m_playlist->guid() ] = updater; + + s->setPlaylistUpdaters( updaters ); } void @@ -88,9 +102,27 @@ PlaylistUpdaterInterface::remove() return; TomahawkSettings* s = TomahawkSettings::instance(); - const QString key = QString( "playlistupdaters/%1" ).arg( m_playlist->guid() ); - removeFromSettings( key ); - s->remove( QString( "%1/type" ).arg( key ) ); + + SerializedUpdaters updaters = s->playlistUpdaters(); + if ( updaters.remove( m_playlist->guid() ) ) + s->setPlaylistUpdaters( updaters ); + + aboutToDelete(); deleteLater(); } + + +QVariantHash +PlaylistUpdaterInterface::settings() const +{ + return m_extraData; +} + + +void +PlaylistUpdaterInterface::saveSettings( const QVariantHash& settings ) +{ + m_extraData = settings; + save(); +} diff --git a/src/libtomahawk/playlist/PlaylistUpdaterInterface.h b/src/libtomahawk/playlist/PlaylistUpdaterInterface.h index 84c25a0f7..3cdac7397 100644 --- a/src/libtomahawk/playlist/PlaylistUpdaterInterface.h +++ b/src/libtomahawk/playlist/PlaylistUpdaterInterface.h @@ -43,9 +43,20 @@ class DLLEXPORT PlaylistUpdaterInterface : public QObject { Q_OBJECT public: + // used when loading/saving from settings + struct SerializedUpdater { + QString type; + QVariantHash customData; + + SerializedUpdater( const QString& t, const QVariantHash cd ) : type( t ), customData( cd ) {} + SerializedUpdater() {} + }; + + typedef QHash< QString, SerializedUpdater > SerializedUpdaters; + explicit PlaylistUpdaterInterface( const playlist_ptr& pl ); - virtual ~PlaylistUpdaterInterface(){} + virtual ~PlaylistUpdaterInterface(); // What type you are. If you add a new updater, add the creation code as well. virtual QString type() const = 0; @@ -78,11 +89,14 @@ public slots: void save(); protected: - virtual void saveToSettings( const QString& group ) const = 0; - virtual void removeFromSettings( const QString& group ) const = 0; + virtual void aboutToDelete() {} + + QVariantHash settings() const; + void saveSettings( const QVariantHash& settings ); private: playlist_ptr m_playlist; + QVariantHash m_extraData; static QMap< QString, PlaylistUpdaterFactory* > s_factories; }; @@ -95,9 +109,12 @@ public: virtual ~PlaylistUpdaterFactory() {} virtual QString type() const = 0; - virtual PlaylistUpdaterInterface* create( const playlist_ptr&, const QString& settingsKey ) = 0; + virtual PlaylistUpdaterInterface* create( const playlist_ptr&, const QVariantHash& settings ) = 0; }; } +Q_DECLARE_METATYPE( Tomahawk::PlaylistUpdaterInterface::SerializedUpdater ); +Q_DECLARE_METATYPE( Tomahawk::PlaylistUpdaterInterface::SerializedUpdaters ); + #endif // PLAYLISTUPDATERINTERFACE_H diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index e8c66c3ce..92d6ebe41 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -109,23 +109,13 @@ PlaylistView::deleteItems() } -bool -PlaylistView::canAutoUpdate() const +QList +PlaylistView::updaters() const { - if ( !m_model->playlist().isNull() && m_model->playlist()->updater() ) - return true; + if ( !m_model->playlist().isNull() ) + return m_model->playlist()->updaters(); - return false; -} - - -PlaylistUpdaterInterface* -PlaylistView::autoUpdateInterface() const -{ - if ( !m_model->playlist().isNull() && m_model->playlist()->updater() ) - return m_model->playlist()->updater(); - - return 0; + return QList(); } diff --git a/src/libtomahawk/playlist/PlaylistView.h b/src/libtomahawk/playlist/PlaylistView.h index 0a2f3cc06..978e4e15f 100644 --- a/src/libtomahawk/playlist/PlaylistView.h +++ b/src/libtomahawk/playlist/PlaylistView.h @@ -43,8 +43,7 @@ public: virtual bool showFilter() const { return true; } - virtual bool canAutoUpdate() const; - virtual Tomahawk::PlaylistUpdaterInterface* autoUpdateInterface() const; + virtual QList updaters() const; virtual QString title() const { return playlistModel()->title(); } virtual QString description() const { return m_model->description(); } diff --git a/src/libtomahawk/playlist/XspfUpdater.cpp b/src/libtomahawk/playlist/XspfUpdater.cpp index ffd2a3226..3a4ab3e28 100644 --- a/src/libtomahawk/playlist/XspfUpdater.cpp +++ b/src/libtomahawk/playlist/XspfUpdater.cpp @@ -20,7 +20,6 @@ #include "Playlist.h" #include "utils/XspfLoader.h" -#include "TomahawkSettings.h" #include "Pipeline.h" #include "utils/TomahawkUtils.h" @@ -33,11 +32,11 @@ using namespace Tomahawk; PlaylistUpdaterInterface* -XspfUpdaterFactory::create( const playlist_ptr &pl, const QString& settingsKey ) +XspfUpdaterFactory::create( const playlist_ptr &pl, const QVariantHash& settings ) { - const bool autoUpdate = TomahawkSettings::instance()->value( QString( "%1/autoupdate" ).arg( settingsKey ) ).toBool(); - const int interval = TomahawkSettings::instance()->value( QString( "%1/interval" ).arg( settingsKey ) ).toInt(); - const QString url = TomahawkSettings::instance()->value( QString( "%1/xspfurl" ).arg( settingsKey ) ).toString(); + const bool autoUpdate = settings.value( "autoupdate" ).toBool(); + const int interval = settings.value( "interval" ).toInt(); + const QString url = settings.value( "xspfurl" ).toString(); XspfUpdater* updater = new XspfUpdater( pl, interval, autoUpdate, url ); @@ -57,13 +56,19 @@ XspfUpdater::XspfUpdater( const playlist_ptr& pl, int interval, bool autoUpdate, #ifndef ENABLE_HEADLESS m_toggleCheckbox = new QCheckBox( ); - m_toggleCheckbox->setText( tr( "Automatically update" ) ); + m_toggleCheckbox->setText( tr( "Automatically update from XSPF" ) ); m_toggleCheckbox->setLayoutDirection( Qt::RightToLeft ); m_toggleCheckbox->setChecked( m_autoUpdate ); m_toggleCheckbox->hide(); connect( m_toggleCheckbox, SIGNAL( toggled( bool ) ), this, SLOT( setAutoUpdate( bool ) ) ); #endif + + QVariantHash s = settings(); + s[ "autoupdate" ] = m_autoUpdate; + s[ "interval" ] = interval; + s[ "xspfurl" ] = xspfUrl; + saveSettings( s ); } @@ -113,24 +118,6 @@ XspfUpdater::playlistLoaded( const QList& newEntries ) } -void -XspfUpdater::saveToSettings( const QString& group ) const -{ - TomahawkSettings::instance()->setValue( QString( "%1/autoupdate" ).arg( group ), m_autoUpdate ); - TomahawkSettings::instance()->setValue( QString( "%1/interval" ).arg( group ), m_timer->interval() ); - TomahawkSettings::instance()->setValue( QString( "%1/xspfurl" ).arg( group ), m_url ); -} - - -void -XspfUpdater::removeFromSettings( const QString& group ) const -{ - TomahawkSettings::instance()->remove( QString( "%1/autoupdate" ).arg( group ) ); - TomahawkSettings::instance()->remove( QString( "%1/interval" ).arg( group ) ); - TomahawkSettings::instance()->remove( QString( "%1/xspfurl" ).arg( group ) ); -} - - void XspfUpdater::setAutoUpdate( bool autoUpdate ) { @@ -141,8 +128,9 @@ XspfUpdater::setAutoUpdate( bool autoUpdate ) else m_timer->stop(); - const QString key = QString( "playlistupdaters/%1/autoupdate" ).arg( playlist()->guid() ); - TomahawkSettings::instance()->setValue( key, m_autoUpdate ); + QVariantHash s = settings(); + s[ "autoupdate" ] = m_autoUpdate; + saveSettings( s ); // Update immediately as well if ( m_autoUpdate ) @@ -152,8 +140,9 @@ XspfUpdater::setAutoUpdate( bool autoUpdate ) void XspfUpdater::setInterval( int intervalMsecs ) { - const QString key = QString( "playlistupdaters/%1/interval" ).arg( playlist()->guid() ); - TomahawkSettings::instance()->setValue( key, intervalMsecs ); + QVariantHash s = settings(); + s[ "interval" ] = intervalMsecs; + saveSettings( s ); if ( !m_timer ) m_timer = new QTimer( this ); diff --git a/src/libtomahawk/playlist/XspfUpdater.h b/src/libtomahawk/playlist/XspfUpdater.h index e797386bb..cbe875119 100644 --- a/src/libtomahawk/playlist/XspfUpdater.h +++ b/src/libtomahawk/playlist/XspfUpdater.h @@ -52,10 +52,6 @@ public slots: void updateNow(); void setAutoUpdate( bool autoUpdate ); -protected: - void saveToSettings( const QString& group ) const; - void removeFromSettings(const QString& group) const; - private slots: void playlistLoaded( const QList & ); @@ -75,7 +71,7 @@ public: XspfUpdaterFactory() {} virtual QString type() const { return "xspf"; } - virtual PlaylistUpdaterInterface* create( const playlist_ptr& pl, const QString& settingsKey ); + virtual PlaylistUpdaterInterface* create( const playlist_ptr& pl, const QVariantHash& settings ); }; } diff --git a/src/libtomahawk/utils/SmartPointerList.h b/src/libtomahawk/utils/SmartPointerList.h index 23220bb62..16e9ae6b7 100644 --- a/src/libtomahawk/utils/SmartPointerList.h +++ b/src/libtomahawk/utils/SmartPointerList.h @@ -55,6 +55,11 @@ private slots: * Exposed clear. This class doesn't have a QPtrList autodelete functionality * ever, so if people think that, they're really confused! -- Ian Monroe * + * NOTE: + * This class is NOT implicitly shared like QList. Passing it around + * ***will*** cause it to iterate and copy all the elements in the copy + * constructor! + * */ template class SmartPointerList : private QList { @@ -136,6 +141,11 @@ public: return *this; } + bool operator==( const SmartPointerList& that ) + { + return QList::operator==( that ); + } + void push_back( T* o ) { append( o ); @@ -180,7 +190,7 @@ public: using QList::swap; using QList::value; using QList::operator!=; - using QList::operator==; +// using QList::operator==; // can't use using directive here since we only want the const versions typename QList::const_iterator begin() const { return QList::constBegin(); } diff --git a/src/libtomahawk/widgets/RecentPlaylistsModel.cpp b/src/libtomahawk/widgets/RecentPlaylistsModel.cpp index 79fc8d654..573f02e07 100644 --- a/src/libtomahawk/widgets/RecentPlaylistsModel.cpp +++ b/src/libtomahawk/widgets/RecentPlaylistsModel.cpp @@ -191,6 +191,9 @@ RecentPlaylistsModel::updatePlaylist() for ( int i = 0; i < m_playlists.size(); i++ ) { + if ( m_playlists[ i ].isNull() ) + continue; + if ( m_playlists[ i ]->guid() == p->guid() ) { QModelIndex idx = index( i, 0, QModelIndex() ); diff --git a/src/main.cpp b/src/main.cpp index f0db949a9..b8a475b35 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,38 +37,6 @@ #include "breakpad/BreakPad.h" #endif -inline QDataStream& operator<<(QDataStream& out, const AtticaManager::StateHash& states) -{ - out << TOMAHAWK_SETTINGS_VERSION; - out << (quint32)states.count(); - foreach( const QString& key, states.keys() ) - { - AtticaManager::Resolver resolver = states[ key ]; - out << key << resolver.version << resolver.scriptPath << (qint32)resolver.state << resolver.userRating; - } - return out; -} - - -inline QDataStream& operator>>(QDataStream& in, AtticaManager::StateHash& states) -{ - quint32 count = 0, version = 0; - in >> version; - in >> count; - for ( uint i = 0; i < count; i++ ) - { - QString key, version, scriptPath; - qint32 state, userRating; - in >> key; - in >> version; - in >> scriptPath; - in >> state; - in >> userRating; - states[ key ] = AtticaManager::Resolver( version, scriptPath, userRating, (AtticaManager::ResolverState)state ); - } - return in; -} - #ifdef Q_OS_WIN #include #define argc __argc @@ -115,8 +83,8 @@ main( int argc, char *argv[] ) TomahawkApp a( argc, argv ); // MUST register StateHash ****before*** initing TomahawkSettingsGui as constructor of settings does upgrade before Gui subclass registers type - qRegisterMetaType< AtticaManager::StateHash >( "AtticaManager::StateHash" ); - qRegisterMetaTypeStreamOperators("AtticaManager::StateHash"); + TomahawkSettings::registerCustomSettingsHandlers(); + TomahawkSettingsGui::registerCustomSettingsHandlers(); #ifdef ENABLE_HEADLESS new TomahawkSettings( &a ); diff --git a/src/sourcetree/items/PlaylistItems.cpp b/src/sourcetree/items/PlaylistItems.cpp index 0f38d98af..f7b37ac5a 100644 --- a/src/sourcetree/items/PlaylistItems.cpp +++ b/src/sourcetree/items/PlaylistItems.cpp @@ -52,7 +52,7 @@ PlaylistItem::PlaylistItem( SourcesModel* mdl, SourceTreeItem* parent, const pla if( ViewManager::instance()->pageForPlaylist( pl ) ) model()->linkSourceItemToPage( this, ViewManager::instance()->pageForPlaylist( pl ) ); - if ( m_playlist->updater() && !m_playlist->updater()->typeIcon().isNull() ) + if ( !m_playlist->updaters().isEmpty() ) createOverlay(); } @@ -251,40 +251,66 @@ PlaylistItem::parsedDroppedTracks( const QList< query_ptr >& tracks ) void PlaylistItem::onUpdated() { - if ( m_playlist->updater() && !m_playlist->updater()->typeIcon().isNull() && - m_overlaidIcon.isNull() ) // create overlay + // No work todo + if ( !m_overlaidIcon.isNull() && m_overlaidUpdaters.operator==( m_playlist->updaters() ) ) { - createOverlay(); + emit updated(); + return; } - else if ( !m_playlist->updater() || ( m_playlist->updater()->typeIcon().isNull() && !m_overlaidIcon.isNull() ) ) - { - // No longer an updater with an icon + + const bool newOverlay = createOverlay(); + if ( !newOverlay && !m_overlaidIcon.isNull() ) m_overlaidIcon = QIcon(); - } + emit updated(); } -void +bool PlaylistItem::createOverlay() { Q_ASSERT( !m_playlist.isNull() ); - Q_ASSERT( m_playlist->updater() ); - Q_ASSERT( !m_playlist->updater()->typeIcon().isNull() ); + + if ( m_playlist->updaters().isEmpty() ) + return false; + + QList< QPixmap > icons; + foreach ( PlaylistUpdaterInterface* updater, m_playlist->updaters() ) + { + if ( !updater->typeIcon().isNull() ) + icons << updater->typeIcon(); + } + + if ( icons.isEmpty() ) + return false; + + // For now we only support up to 2 overlaid updater icons, + // we need to add smarter scaling etc to manage more at once + if ( icons.size() > 2 ) + icons = icons.mid( 0, 2 ); m_overlaidIcon = QIcon(); + m_overlaidUpdaters = m_playlist->updaters(); QPixmap base = m_icon.pixmap( 48, 48 ); - const QPixmap overlay = m_playlist->updater()->typeIcon(); - QPainter p( &base ); const int w = base.width() / 2; - const QRect overlayRect( base.rect().right() - w, base.rect().height() - w, w, w ); - p.drawPixmap( overlayRect, overlay ); + QRect overlayRect( base.rect().right() - w, base.rect().height() - w, w, w ); + + foreach ( const QPixmap& overlay, icons ) + { + p.drawPixmap( overlayRect, overlay ); + + // NOTE only works if icons.size == 2 as ensured above + overlayRect.moveLeft( 0 ); + } + p.end(); m_overlaidIcon.addPixmap( base ); + + return true; } diff --git a/src/sourcetree/items/PlaylistItems.h b/src/sourcetree/items/PlaylistItems.h index 6887ee743..31198e778 100644 --- a/src/sourcetree/items/PlaylistItems.h +++ b/src/sourcetree/items/PlaylistItems.h @@ -56,11 +56,12 @@ private slots: void onUpdated(); private: - void createOverlay(); + bool createOverlay(); bool m_loaded; Tomahawk::playlist_ptr m_playlist; QIcon m_icon, m_overlaidIcon; + QList m_overlaidUpdaters; }; Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::DropTypes)