diff --git a/include/tomahawk/collection.h b/include/tomahawk/collection.h index af1bc7dc4..c573a1e22 100644 --- a/include/tomahawk/collection.h +++ b/include/tomahawk/collection.h @@ -14,9 +14,10 @@ #include #include "tomahawk/functimeout.h" -#include "tomahawk/playlist.h" #include "tomahawk/source.h" #include "tomahawk/typedefs.h" +#include "typedefs.h" +#include "dynamic/dynamicplaylist.h" namespace Tomahawk { @@ -33,12 +34,19 @@ public: virtual void loadPlaylists() { qDebug() << Q_FUNC_INFO; } virtual void loadTracks() { qDebug() << Q_FUNC_INFO; } + virtual void loadDynamicPlaylists() { qDebug() << Q_FUNC_INFO ; } virtual Tomahawk::playlist_ptr playlist( const QString& guid ); + virtual Tomahawk::dynplaylist_ptr dynamicPlaylist( const QString& guid ); + virtual void addPlaylist( const Tomahawk::playlist_ptr& p ); virtual void deletePlaylist( const Tomahawk::playlist_ptr& p ); - + + virtual void addDynamicPlaylist( const Tomahawk::dynplaylist_ptr& p ); + virtual void deleteDynamicPlaylist( const Tomahawk::dynplaylist_ptr& p ); + virtual QList< Tomahawk::playlist_ptr > playlists() { return m_playlists; } + virtual QList< Tomahawk::dynplaylist_ptr > dynamicPlaylists() { return m_dynplaylists; } virtual QList< Tomahawk::query_ptr > tracks() { return m_tracks; } const source_ptr& source() const { return m_source; } @@ -51,6 +59,9 @@ signals: void playlistsAdded( const QList& ); void playlistsDeleted( const QList& ); + + void dynamicPlaylistsAdded( const QList& ); + void dynamicPlaylistsDeleted( const QList& ); public slots: virtual void addTracks( const QList &newitems ) = 0; @@ -59,6 +70,7 @@ public slots: void setPlaylists( const QList& plists ); void setTracks( const QList& tracks, Tomahawk::collection_ptr collection ); + void setDynamicPlaylistS( const QList< Tomahawk::dynplaylist_ptr >& dynplists ); protected: QString m_name; unsigned int m_lastmodified; // unix time of last change to collection @@ -67,6 +79,7 @@ private: source_ptr m_source; QList< Tomahawk::playlist_ptr > m_playlists; QList< Tomahawk::query_ptr > m_tracks; + QList< Tomahawk::dynplaylist_ptr > m_dynplaylists; }; }; // ns diff --git a/include/tomahawk/playlist.h b/include/tomahawk/playlist.h index 8245c5367..2255a0295 100644 --- a/include/tomahawk/playlist.h +++ b/include/tomahawk/playlist.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "tomahawk/query.h" @@ -119,12 +120,7 @@ public: // these need to exist and be public for the json serialization stuff // you SHOULD NOT call them. They are used for an alternate CTOR method from json. // maybe friend QObjectHelper and make them private? - explicit Playlist( const source_ptr& author ) - : m_source( author ) - , m_lastmodified( 0 ) - { - qDebug() << Q_FUNC_INFO << "JSON"; - } + explicit Playlist( const source_ptr& author ); void setCurrentrevision( const QString& s ) { m_currentrevision = s; } void setTitle( const QString& s ) { m_title = s; } void setInfo( const QString& s ) { m_info = s; } @@ -182,6 +178,8 @@ protected: bool is_newest_rev, const QMap< QString, Tomahawk::plentry_ptr >& addedmap ); private: + Playlist(); + source_ptr m_source; QString m_currentrevision; QString m_guid, m_title, m_info, m_creator; diff --git a/include/tomahawk/query.h b/include/tomahawk/query.h index 3ce6064eb..536063337 100644 --- a/include/tomahawk/query.h +++ b/include/tomahawk/query.h @@ -6,7 +6,7 @@ #include #include -#include "tomahawk/collection.h" +// #include "tomahawk/collection.h" #include "tomahawk/result.h" #include "tomahawk/typedefs.h" diff --git a/include/tomahawk/result.h b/include/tomahawk/result.h index 193c799e4..fc7a34f75 100644 --- a/include/tomahawk/result.h +++ b/include/tomahawk/result.h @@ -1,12 +1,11 @@ + #ifndef RESULT_H #define RESULT_H +#include #include - +#include #include "tomahawk/typedefs.h" -#include "collection.h" -#include "artist.h" -#include "album.h" namespace Tomahawk { @@ -17,14 +16,16 @@ Q_OBJECT public: explicit Result( const QVariant& v, const collection_ptr& collection ); + virtual ~Result(); + QVariant toVariant() const { return m_v; } float score() const; RID id() const; - collection_ptr collection() const { return m_collection; } + collection_ptr collection() const; - Tomahawk::artist_ptr artist() const { return m_artist; } - Tomahawk::album_ptr album() const { return m_album; } + Tomahawk::artist_ptr artist() const; + Tomahawk::album_ptr album() const; QString track() const { return m_track; } QString url() const { return m_url; } QString mimetype() const { return m_mimetype; } diff --git a/include/tomahawk/source.h b/include/tomahawk/source.h index baf1af09e..9978a1002 100644 --- a/include/tomahawk/source.h +++ b/include/tomahawk/source.h @@ -21,7 +21,7 @@ Q_OBJECT public: explicit Source( const QString& username, ControlConnection* cc ); - explicit Source( const QString& username ); + explicit Source( const QString& username = QString() ); virtual ~Source(); bool isLocal() const { return m_isLocal; } diff --git a/include/tomahawk/typedefs.h b/include/tomahawk/typedefs.h index 9e47a9d55..1283c7e11 100644 --- a/include/tomahawk/typedefs.h +++ b/include/tomahawk/typedefs.h @@ -15,6 +15,8 @@ namespace Tomahawk class Query; class Result; class Source; + class DynamicControl; + class GeneratorInterface; typedef QSharedPointer collection_ptr; typedef QSharedPointer playlist_ptr; @@ -25,10 +27,19 @@ namespace Tomahawk typedef QSharedPointer source_ptr; typedef QSharedPointer artist_ptr; typedef QSharedPointer album_ptr; - + + typedef QSharedPointer dyncontrol_ptr; + typedef QSharedPointer geninterface_ptr; + // let's keep these typesafe, they are different kinds of GUID: typedef QString QID; //query id typedef QString RID; //result id + + + enum GeneratorMode { + OnDemand = 0, + Static + }; }; // ns diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 51e21e75e..90f6e31a9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -89,10 +89,16 @@ SET( tomahawkSources ${tomahawkSources} database/databasecommand_renameplaylist.cpp database/databasecommand_loadops.cpp database/databasecommand_updatesearchindex.cpp + database/databasecommand_loadallplaylists.cpp + database/databasecommand_setdynamicplaylistrevision.cpp + database/databasecommand_createdynamicplaylist.cpp + database/databasecommand_loaddynamicplaylist.cpp database/databasecollection.cpp dynamic/dynamicplaylist.cpp + dynamic/dynamiccontrol.cpp dynamic/generatorfactory.cpp + dynamic/generatorinterface.cpp dynamic/echonest/echonestgenerator.cpp dynamic/echonest/echonestcontrol.cpp @@ -207,6 +213,9 @@ SET( tomahawkHeaders ${tomahawkHeaders} database/databasecommand_loadallplaylists.h database/databasecommand_createplaylist.h database/databasecommand_deleteplaylist.h + database/databasecommand_setdynamicplaylistrevision.h + database/databasecommand_createdynamicplaylist.h + database/databasecommand_loaddynamicplaylist.h database/databasecommand_renameplaylist.h database/databasecommand_loadops.h database/databasecommand_updatesearchindex.h diff --git a/src/collection.cpp b/src/collection.cpp index 18b7c7a5b..d6c01d48d 100644 --- a/src/collection.cpp +++ b/src/collection.cpp @@ -4,6 +4,7 @@ #include #include "tomahawk/playlist.h" +#include "dynamic/dynamicplaylist.h" using namespace Tomahawk; @@ -45,6 +46,20 @@ Collection::addPlaylist( const Tomahawk::playlist_ptr& p ) emit playlistsAdded( toadd ); } +void +Collection::addDynamicPlaylist( const Tomahawk::dynplaylist_ptr& p ) +{ + qDebug() << Q_FUNC_INFO; + QList toadd; + toadd << p; + m_dynplaylists.append( toadd ); + + qDebug() << Q_FUNC_INFO << "Collection name" << name() + << "from source id" << source()->id() + << "numplaylists:" << m_playlists.length(); + emit dynamicPlaylistsAdded( toadd ); +} + void Collection::deletePlaylist( const Tomahawk::playlist_ptr& p ) @@ -60,6 +75,20 @@ Collection::deletePlaylist( const Tomahawk::playlist_ptr& p ) emit playlistsDeleted( todelete ); } +void +Collection::deleteDynamicPlaylist( const Tomahawk::dynplaylist_ptr& p ) +{ + qDebug() << Q_FUNC_INFO; + QList todelete; + todelete << p; + m_dynplaylists.removeAll( p ); + + qDebug() << Q_FUNC_INFO << "Collection name" << name() + << "from source id" << source()->id() + << "numplaylists:" << m_playlists.length(); + emit dynamicPlaylistsDeleted( todelete ); +} + playlist_ptr Collection::playlist( const QString& guid ) @@ -74,6 +103,19 @@ Collection::playlist( const QString& guid ) } +dynplaylist_ptr +Collection::dynamicPlaylist( const QString& guid ) +{ + foreach( const dynplaylist_ptr& pp, m_dynplaylists ) + { + if( pp->guid() == guid ) + return pp; + } + + return dynplaylist_ptr(); +} + + void Collection::setPlaylists( const QList& plists ) { @@ -83,6 +125,14 @@ Collection::setPlaylists( const QList& plists ) emit playlistsAdded( plists ); } +void +Collection::setDynamicPlaylistS( const QList< Tomahawk::dynplaylist_ptr >& plists ) +{ + qDebug() << Q_FUNC_INFO << plists.count(); + + m_dynplaylists.append( plists ); + emit dynamicPlaylistsAdded( plists ); +} void Collection::setTracks( const QList& tracks, Tomahawk::collection_ptr collection ) diff --git a/src/database/databasecollection.cpp b/src/database/databasecollection.cpp index 771291096..4a27b9004 100644 --- a/src/database/databasecollection.cpp +++ b/src/database/databasecollection.cpp @@ -27,6 +27,19 @@ DatabaseCollection::loadPlaylists() TomahawkApp::instance()->database()->enqueue( QSharedPointer( cmd ) ); } +void +DatabaseCollection::loadDynamicPlaylists() +{ + qDebug() << Q_FUNC_INFO; +// DatabaseCommand_LoadAllDynamicPlaylists* cmd = new DatabaseCommand_LoadAllDynamicPlaylists( source() ); +// +// connect( cmd, SIGNAL( done( const QList& ) ), +// SLOT( setDynamicPlaylists( const QList& ) ) ); +// +// TomahawkApp::instance()->database()->enqueue( QSharedPointer( cmd ) ); +} + + void DatabaseCollection::loadTracks() @@ -77,6 +90,19 @@ DatabaseCollection::playlists() return Collection::playlists(); } +QList< dynplaylist_ptr > DatabaseCollection::dynamicPlaylists() +{ + qDebug() << Q_FUNC_INFO; + + if ( Collection::dynamicPlaylists().isEmpty() ) + { + loadDynamicPlaylists(); + } + + return Collection::dynamicPlaylists(); +} + + QList< Tomahawk::query_ptr > DatabaseCollection::tracks() diff --git a/src/database/databasecollection.h b/src/database/databasecollection.h index 37b658bed..0a305b03f 100644 --- a/src/database/databasecollection.h +++ b/src/database/databasecollection.h @@ -17,9 +17,11 @@ public: virtual void loadTracks(); virtual void loadPlaylists(); + virtual void loadDynamicPlaylists(); virtual QList< Tomahawk::playlist_ptr > playlists(); virtual QList< Tomahawk::query_ptr > tracks(); + virtual QList< Tomahawk::dynplaylist_ptr > dynamicPlaylists(); public slots: virtual void addTracks( const QList &newitems ); diff --git a/src/database/databasecommand_createdynamicplaylist.cpp b/src/database/databasecommand_createdynamicplaylist.cpp new file mode 100644 index 000000000..eeb8fbc1c --- /dev/null +++ b/src/database/databasecommand_createdynamicplaylist.cpp @@ -0,0 +1,79 @@ +#include "databasecommand_createdynamicplaylist.h" + +#include + +#include "tomahawk/tomahawkapp.h" +#include "dynamic/dynamicplaylist.h" +#include "dynamic/dynamiccontrol.h" +#include "dynamic/generatorinterface.h" + +using namespace Tomahawk; + + +DatabaseCommand_CreateDynamicPlaylist::DatabaseCommand_CreateDynamicPlaylist( QObject* parent ) +: DatabaseCommand_CreatePlaylist( parent ) +{ + qDebug() << Q_FUNC_INFO << "creating dynamiccreatecommand 1"; +} + + +DatabaseCommand_CreateDynamicPlaylist::DatabaseCommand_CreateDynamicPlaylist( const source_ptr& author, + const dynplaylist_ptr& playlist ) +: DatabaseCommand_CreatePlaylist( author, playlist.staticCast() ) +, m_playlist( playlist ) +{ + qDebug() << Q_FUNC_INFO << "creating dynamiccreatecommand 2"; +} + + +void +DatabaseCommand_CreateDynamicPlaylist::exec( DatabaseImpl* lib ) +{ + qDebug() << Q_FUNC_INFO; + Q_ASSERT( !m_playlist.isNull() ); + Q_ASSERT( !source().isNull() ); + + DatabaseCommand_CreatePlaylist::exec( lib ); + + TomahawkSqlQuery cre = lib->newquery(); + cre.prepare( "INSERT INTO dynamic_playlist( guid, pltype, plmode) " + "VALUES( :guid, :pltype, :plmode )" ); + cre.bindValue( ":guid", m_playlist->guid() ); + cre.bindValue( ":pltype", m_playlist->type() ); + cre.bindValue( ":plmode", m_playlist->mode() ); + + qDebug() << "CREATE DYNPLAYLIST:" << cre.boundValues(); + + cre.exec(); + + // save the controls + cre = lib->newquery(); + cre.prepare( "INSERT INTO dynamic_playlist_controls( id, selectedType, match, input) " + "VALUES( :id, :selectedType, :match, :input )" ); + foreach( const dyncontrol_ptr& control, m_playlist->generator()->controls() ) { + + cre.bindValue( ":id", control->id() ); + cre.bindValue( ":selectedType", control->selectedType() ); + cre.bindValue( ":match", control->match() ); + cre.bindValue( ":input", control->input() ); + + qDebug() << "CREATE DYNPLAYLIST CONTROL:" << cre.boundValues(); + + cre.exec(); + } +} + + +void +DatabaseCommand_CreateDynamicPlaylist::postCommitHook() +{ + qDebug() << Q_FUNC_INFO; + if( report() == false ) + return; + + qDebug() << Q_FUNC_INFO << "..reporting.."; + m_playlist->reportCreated( m_playlist ); + + if( source()->isLocal() ) + APP->servent().triggerDBSync(); +} diff --git a/src/database/databasecommand_createdynamicplaylist.h b/src/database/databasecommand_createdynamicplaylist.h new file mode 100644 index 000000000..a1c5668dd --- /dev/null +++ b/src/database/databasecommand_createdynamicplaylist.h @@ -0,0 +1,43 @@ +#ifndef DATABASECOMMAND_CREATEDYNAMICPLAYLIST_H +#define DATABASECOMMAND_CREATEDYNAMICPLAYLIST_H + +#include "databaseimpl.h" +#include "databasecommand_createplaylist.h" +#include "dynamic/dynamicplaylist.h" +#include "tomahawk/typedefs.h" + +class DatabaseCommand_CreateDynamicPlaylist : public DatabaseCommand_CreatePlaylist +{ + Q_OBJECT + Q_PROPERTY( QVariant playlist READ playlistV WRITE setPlaylistV ) + +public: + explicit DatabaseCommand_CreateDynamicPlaylist( QObject* parent = 0 ); + explicit DatabaseCommand_CreateDynamicPlaylist( const Tomahawk::source_ptr& author, const Tomahawk::dynplaylist_ptr& playlist ); + + QString commandname() const { return "createdynamicplaylist"; } + + virtual void exec( DatabaseImpl* lib ); + virtual void postCommitHook(); + virtual bool doesMutates() const { return true; } + + QVariant playlistV() const + { + return QJson::QObjectHelper::qobject2qvariant( (QObject*)m_playlist.data() ); + } + + void setPlaylistV( const QVariant& v ) + { + qDebug() << "***********" << Q_FUNC_INFO << v; + using namespace Tomahawk; + + DynamicPlaylist* p = new DynamicPlaylist( source() ); + QJson::QObjectHelper::qvariant2qobject( v.toMap(), p ); + m_playlist = dynplaylist_ptr( p ); + } + +private: + Tomahawk::dynplaylist_ptr m_playlist; +}; + +#endif // DATABASECOMMAND_CREATEDYNAMICPLAYLIST_H diff --git a/src/database/databasecommand_createplaylist.h b/src/database/databasecommand_createplaylist.h index bd259eece..69118dd79 100644 --- a/src/database/databasecommand_createplaylist.h +++ b/src/database/databasecommand_createplaylist.h @@ -35,6 +35,9 @@ public: QJson::QObjectHelper::qvariant2qobject( v.toMap(), p ); m_playlist = playlist_ptr( p ); } + +protected: + bool report() { return m_report; } private: Tomahawk::playlist_ptr m_playlist; diff --git a/src/database/databasecommand_loaddynamicplaylist.cpp b/src/database/databasecommand_loaddynamicplaylist.cpp new file mode 100644 index 000000000..2b7273e5e --- /dev/null +++ b/src/database/databasecommand_loaddynamicplaylist.cpp @@ -0,0 +1,64 @@ +#include "databasecommand_loaddynamicplaylist.h" + +#include +#include + +#include "databaseimpl.h" +#include "tomahawksqlquery.h" +#include "dynamic/dynamiccontrol.h" +#include "dynamic/generatorinterface.h" + +using namespace Tomahawk; + + +void +DatabaseCommand_LoadDynamicPlaylist::exec( DatabaseImpl* dbi ) +{ + qDebug() << "Loading dynamic playlist revision" << guid(); + // load the entries first + generateEntries( dbi ); + + // now load the controls etc + + TomahawkSqlQuery controlsQuery = dbi->newquery(); + controlsQuery.prepare("SELECT controls, plmode, pltype" + "FROM dynamic_playlist_revision " + "WHERE guid = :guid"); + controlsQuery.bindValue( ":guid", guid() ); + controlsQuery.exec(); + + QList< dyncontrol_ptr > controls; + if( controlsQuery.next() ) + { + QStringList controlIds = controlsQuery.value( 0 ).toStringList(); + foreach( const QString& controlId, controlIds ) + { + TomahawkSqlQuery controlQuery = dbi->newquery(); + controlQuery.prepare( "SELECT selectedType, match, input" + "FROM dynamic_playlist_controls" + "WHERE id = :id" ); + controlQuery.bindValue( ":id", controlId ); + controlQuery.exec(); + if( controlQuery.next() ) + { + dyncontrol_ptr c = dyncontrol_ptr( new DynamicControl ); + c->setId( controlId ); + c->setSelectedType( controlQuery.value( 0 ).toString() ); + c->setMatch( controlQuery.value( 1 ).toString() ); + c->setInput( controlQuery.value( 2 ).toString() ); + controls << c; + } + } + } + + + QString type = controlsQuery.value( 2 ).toString(); + GeneratorMode mode = static_cast( controlsQuery.value( 1 ).toInt() ); + if( mode == OnDemand ) { + Q_ASSERT( m_entrymap.isEmpty() ); // ondemand should have no entry + + emit done( guid(), m_islatest, type, controls, true ); + } else { + emit done( guid(), m_guids, m_oldentries, type, controls, m_islatest, m_entrymap, true ); + } +} diff --git a/src/database/databasecommand_loaddynamicplaylist.h b/src/database/databasecommand_loaddynamicplaylist.h new file mode 100644 index 000000000..2dbbb44c3 --- /dev/null +++ b/src/database/databasecommand_loaddynamicplaylist.h @@ -0,0 +1,47 @@ +#ifndef DATABASECOMMAND_LOADDYNAMICPLAYLIST_H +#define DATABASECOMMAND_LOADDYNAMICPLAYLIST_H + +#include +#include + +#include "tomahawk/typedefs.h" +#include "databasecommand.h" +#include "databasecommand_loadplaylistentries.h" +#include "tomahawk/playlist.h" +#include "dynamic/dynamiccontrol.h" + +class DatabaseCommand_LoadDynamicPlaylist : public DatabaseCommand_LoadPlaylistEntries +{ + Q_OBJECT + +public: + explicit DatabaseCommand_LoadDynamicPlaylist( QString revision_guid, QObject* parent = 0 ) + : DatabaseCommand_LoadPlaylistEntries( revision_guid, parent ) + {} + + + virtual void exec( DatabaseImpl* ); + virtual bool doesMutates() const { return false; } + virtual QString commandname() const { return "loaddynamicplaylist"; } + +signals: + // used if loading an ondemand playlist + void done( QString, + bool, + const QString, + QList< Tomahawk::dyncontrol_ptr>, + bool ); + // used when loading a static playlist + void done( QString, + QList< QString >, + QList< QString >, + QString, + QList< Tomahawk::dyncontrol_ptr>, + bool, + const QMap< QString, Tomahawk::plentry_ptr >, + bool ); + +private: +}; + +#endif // DATABASECOMMAND_LOADDYNAMICPLAYLIST_H diff --git a/src/database/databasecommand_loadplaylistentries.cpp b/src/database/databasecommand_loadplaylistentries.cpp index c71fe9b8f..9eaea480c 100644 --- a/src/database/databasecommand_loadplaylistentries.cpp +++ b/src/database/databasecommand_loadplaylistentries.cpp @@ -11,67 +11,69 @@ void DatabaseCommand_LoadPlaylistEntries::exec( DatabaseImpl* dbi ) { qDebug() << "Loading playlist entries for revision" << m_guid; + generateEntries( dbi ); + + emit done( m_guid, m_guids, m_oldentries, m_islatest, m_entrymap, true ); +} +void DatabaseCommand_LoadPlaylistEntries::generateEntries( DatabaseImpl* dbi ) +{ TomahawkSqlQuery query_entries = dbi->newquery(); query_entries.prepare("SELECT entries, playlist, author, timestamp, previous_revision " "FROM playlist_revision " "WHERE guid = :guid"); query_entries.bindValue( ":guid", m_guid ); query_entries.exec(); - - QStringList guids; - QMap< QString, plentry_ptr > entrymap; - bool islatest = true; - QStringList oldentries; + QString prevrev; QJson::Parser parser; bool ok; - + if( query_entries.next() ) { // entries should be a list of strings: QVariant v = parser.parse( query_entries.value(0).toByteArray(), &ok ); Q_ASSERT( ok && v.type() == QVariant::List ); //TODO - guids = v.toStringList(); -// qDebug() << "Entries:" << guids; - - QString inclause = QString("('%1')").arg(guids.join("', '")); - + m_guids = v.toStringList(); + // qDebug() << "Entries:" << guids; + + QString inclause = QString("('%1')").arg(m_guids.join("', '")); + TomahawkSqlQuery query = dbi->newquery(); QString sql = QString("SELECT guid, trackname, artistname, albumname, annotation, " "duration, addedon, addedby, result_hint " "FROM playlist_item " "WHERE guid IN %1").arg( inclause ); - //qDebug() << sql; - - query.exec( sql ); - while( query.next() ) - { - plentry_ptr e( new PlaylistEntry ); - e->setGuid( query.value( 0 ).toString() ); - e->setAnnotation( query.value( 4 ).toString() ); - e->setDuration( query.value( 5 ).toUInt() ); - e->setLastmodified( 0 ); // TODO e->lastmodified = query.value(6).toInt(); - e->setResulthint( query.value( 8 ).toString() ); - - QVariantMap m; - m.insert( "artist", query.value( 2 ).toString() ); - m.insert( "album", query.value( 3 ).toString() ); - m.insert( "track", query.value( 1 ).toString() ); - m.insert( "qid", uuid() ); - - Tomahawk::query_ptr q( new Tomahawk::Query( m ) ); - e->setQuery( q ); - - entrymap.insert( e->guid(), e ); - } - - prevrev = query_entries.value( 4 ).toString(); + //qDebug() << sql; + + query.exec( sql ); + while( query.next() ) + { + plentry_ptr e( new PlaylistEntry ); + e->setGuid( query.value( 0 ).toString() ); + e->setAnnotation( query.value( 4 ).toString() ); + e->setDuration( query.value( 5 ).toUInt() ); + e->setLastmodified( 0 ); // TODO e->lastmodified = query.value(6).toInt(); + e->setResulthint( query.value( 8 ).toString() ); + + QVariantMap m; + m.insert( "artist", query.value( 2 ).toString() ); + m.insert( "album", query.value( 3 ).toString() ); + m.insert( "track", query.value( 1 ).toString() ); + m.insert( "qid", uuid() ); + + Tomahawk::query_ptr q( new Tomahawk::Query( m ) ); + e->setQuery( q ); + + m_entrymap.insert( e->guid(), e ); + } + + prevrev = query_entries.value( 4 ).toString(); } else { qDebug() << "Playlist has no current revision data"; } - + if( prevrev.length() ) { TomahawkSqlQuery query_entries_old = dbi->newquery(); @@ -82,21 +84,19 @@ DatabaseCommand_LoadPlaylistEntries::exec( DatabaseImpl* dbi ) query_entries_old.addBindValue( m_guid ); query_entries_old.addBindValue( query_entries.value( 1 ).toString() ); query_entries_old.addBindValue( prevrev ); - + query_entries_old.exec(); if( !query_entries_old.next() ) { return; Q_ASSERT( false ); } - + QVariant v = parser.parse( query_entries_old.value( 0 ).toByteArray(), &ok ); Q_ASSERT( ok && v.type() == QVariant::List ); //TODO - oldentries = v.toStringList(); - islatest = query_entries_old.value( 1 ).toBool(); + m_oldentries = v.toStringList(); + m_islatest = query_entries_old.value( 1 ).toBool(); } - - qDebug() << Q_FUNC_INFO << "entrymap:" << entrymap; - - emit done( m_guid, guids, oldentries, islatest, entrymap, true ); + + qDebug() << Q_FUNC_INFO << "entrymap:" << m_entrymap; } diff --git a/src/database/databasecommand_loadplaylistentries.h b/src/database/databasecommand_loadplaylistentries.h index d9333e9eb..8b563ecc3 100644 --- a/src/database/databasecommand_loadplaylistentries.h +++ b/src/database/databasecommand_loadplaylistentries.h @@ -28,6 +28,14 @@ signals: const QMap< QString, Tomahawk::plentry_ptr >& added, bool applied ); +protected: + void generateEntries( DatabaseImpl* dbi ); + + QStringList m_guids; + QMap< QString, Tomahawk::plentry_ptr > m_entrymap; + bool m_islatest; + QStringList m_oldentries; + private: QString m_guid; }; diff --git a/src/database/databasecommand_setdynamicplaylistrevision.cpp b/src/database/databasecommand_setdynamicplaylistrevision.cpp new file mode 100644 index 000000000..b1889fba8 --- /dev/null +++ b/src/database/databasecommand_setdynamicplaylistrevision.cpp @@ -0,0 +1,212 @@ +#include "databasecommand_setdynamicplaylistrevision.h" + +#include + +#include "tomahawksqlquery.h" +#include "dynamic/dynamicplaylist.h" +#include "dynamic/dynamiccontrol.h" +#include "tomahawk/tomahawkapp.h" + +DatabaseCommand_SetDynamicPlaylistRevision::DatabaseCommand_SetDynamicPlaylistRevision(const Tomahawk::source_ptr& s, + const QString& playlistguid, + const QString& newrev, + const QString& oldrev, + const QStringList& orderedguids, + const QList< plentry_ptr >& addedentries, + const QString& type, + GeneratorMode mode, + const QList< dyncontrol_ptr >& controls ) + : DatabaseCommand_SetPlaylistRevision( s, playlistguid, newrev, oldrev, orderedguids, addedentries ) + , m_type( type ) + , m_mode( mode ) + , m_controls( controls ) +{ + +} + +DatabaseCommand_SetDynamicPlaylistRevision::DatabaseCommand_SetDynamicPlaylistRevision(const Tomahawk::source_ptr& s, + const QString& playlistguid, + const QString& newrev, + const QString& oldrev, + const QString& type, + GeneratorMode mode, + const QList< dyncontrol_ptr >& controls ) + : DatabaseCommand_SetPlaylistRevision( s, playlistguid, newrev, oldrev, QStringList(), QList< plentry_ptr >() ) + , m_type( type ) + , m_mode( mode ) + , m_controls( controls ) +{ + +} + +QVariantList DatabaseCommand_SetDynamicPlaylistRevision::controlsV() +{ + if( m_controls.isEmpty() ) + return m_controlsV; + + if( !m_controls.isEmpty() && m_controlsV.isEmpty() ) + { + foreach( const dyncontrol_ptr& control, m_controls ) + { + m_controlsV << QJson::QObjectHelper::qobject2qvariant( control.data() ); + } + } + return m_controlsV; + +} + + +void +DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook() +{ + qDebug() << Q_FUNC_INFO; + + QStringList orderedentriesguids; + foreach( const QVariant& v, orderedguids() ) + orderedentriesguids << v.toString(); + + // private, but we are a friend. will recall itself in its own thread: + dynplaylist_ptr playlist = source()->collection()->dynamicPlaylist( playlistguid() ); + + if ( playlist.isNull() ) + { + qDebug() << playlistguid(); + Q_ASSERT( !playlist.isNull() ); + return; + } + + if( m_controls.isEmpty() && !m_controlsV.isEmpty() ) // we were creatd from JSON, not programmatically. construct the controls fromthe playlist now + { + foreach( const QVariant& contrl, m_controlsV ) { + dyncontrol_ptr control = playlist->generator()->createControl( m_type ); + QJson::QObjectHelper::qvariant2qobject( contrl.toMap(), control.data( )); + m_controls << control; + } + } + + if( m_mode == OnDemand ) + playlist->setRevision( newrev(), + true, // this *is* the newest revision so far + m_type, + m_controls, + m_applied ); + else + playlist->setRevision( newrev(), + orderedentriesguids, + m_previous_rev_orderedguids, + m_type, + m_controls, + true, // this *is* the newest revision so far + m_addedmap, + m_applied ); + + if( source()->isLocal() ) + APP->servent().triggerDBSync(); +} + + +void +DatabaseCommand_SetDynamicPlaylistRevision::exec( DatabaseImpl* lib ) +{ + /*using namespace Tomahawk; + + QString currentrevision; + + // get the current revision for this playlist + // this also serves to check the playlist exists. + TomahawkSqlQuery chkq = lib->newquery(); + chkq.prepare("SELECT currentrevision FROM playlist WHERE guid = ?"); + chkq.addBindValue( m_playlistguid ); + if( chkq.exec() && chkq.next() ) + { + currentrevision = chkq.value( 0 ).toString(); + //qDebug() << Q_FUNC_INFO << "pl guid" << m_playlistguid << " curr rev" << currentrevision; + } + else + { + throw "No such playlist, WTF?"; + return; + } + + QVariantList vlist = m_orderedguids; + QJson::Serializer ser; + const QByteArray entries = ser.serialize( vlist ); + + // add any new items: + TomahawkSqlQuery adde = lib->newquery(); + + QString sql = "INSERT INTO playlist_item( guid, playlist, trackname, artistname, albumname, " + "annotation, duration, addedon, addedby, result_hint ) " + "VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )"; + adde.prepare( sql ); + + qDebug() << "Num new playlist_items to add:" << m_addedentries.length(); + foreach( const plentry_ptr& e, m_addedentries ) + { + m_addedmap.insert( e->guid(), e ); // needed in postcommithook + + adde.bindValue( 0, e->guid() ); + adde.bindValue( 1, m_playlistguid ); + adde.bindValue( 2, e->query()->track() ); + adde.bindValue( 3, e->query()->artist() ); + adde.bindValue( 4, e->query()->album() ); + adde.bindValue( 5, e->annotation() ); + adde.bindValue( 6, (int) e->duration() ); + adde.bindValue( 7, e->lastmodified() ); + adde.bindValue( 8, source()->isLocal() ? QVariant(QVariant::Int) : source()->id() ); + adde.bindValue( 9, "" ); + adde.exec(); + } + + // add the new revision: + //qDebug() << "Adding new playlist revision, guid:" << m_newrev + // << entries; + TomahawkSqlQuery query = lib->newquery(); + sql = "INSERT INTO playlist_revision(guid, playlist, entries, author, timestamp, previous_revision) " + "VALUES(?, ?, ?, ?, ?, ?)"; + + query.prepare( sql ); + query.addBindValue( m_newrev ); + query.addBindValue( m_playlistguid ); + query.addBindValue( entries ); + query.addBindValue( source()->isLocal() ? QVariant(QVariant::Int) : source()->id() ); + query.addBindValue( 0 ); //ts + query.addBindValue( m_oldrev.isEmpty() ? QVariant(QVariant::String) : m_oldrev ); + query.exec(); + + qDebug() << "Currentrevision:" << currentrevision << "oldrev:" << m_oldrev; + // if optimistic locking is ok, update current revision to this new one + if( currentrevision == m_oldrev ) + { + TomahawkSqlQuery query2 = lib->newquery(); + qDebug() << "updating current revision, optimistic locking ok"; + query2.prepare("UPDATE playlist SET currentrevision = ? WHERE guid = ?"); + query2.bindValue( 0, m_newrev ); + query2.bindValue( 1, m_playlistguid ); + query2.exec(); + + m_applied = true; + + // load previous revision entries, which we need to pass on + // so the change can be diffed + TomahawkSqlQuery query_entries = lib->newquery(); + query_entries.prepare( "SELECT entries, playlist, author, timestamp, previous_revision " + "FROM playlist_revision " + "WHERE guid = :guid" ); + query_entries.bindValue( ":guid", m_oldrev ); + query_entries.exec(); + if( query_entries.next() ) + { + // entries should be a list of strings: + bool ok; + QJson::Parser parser; + QVariant v = parser.parse( query_entries.value(0).toByteArray(), &ok ); + Q_ASSERT( ok && v.type() == QVariant::List ); //TODO + m_previous_rev_orderedguids = v.toStringList(); + } + } + else + { + qDebug() << "Not updating current revision, optimistic locking fail"; + } */ +} diff --git a/src/database/databasecommand_setdynamicplaylistrevision.h b/src/database/databasecommand_setdynamicplaylistrevision.h new file mode 100644 index 000000000..52799d4a4 --- /dev/null +++ b/src/database/databasecommand_setdynamicplaylistrevision.h @@ -0,0 +1,68 @@ +#ifndef DATABASECOMMAND_SETDYNAMICPLAYLISTREVISION_H +#define DATABASECOMMAND_SETDYNAMICPLAYLISTREVISION_H + +#include "databasecommand_setplaylistrevision.h" +#include "databaseimpl.h" +#include "tomahawk/collection.h" +#include "tomahawk/playlist.h" +#include + +using namespace Tomahawk; + +class DatabaseCommand_SetDynamicPlaylistRevision : public DatabaseCommand_SetPlaylistRevision +{ + Q_OBJECT + Q_PROPERTY( QString type READ type WRITE setType ) + Q_PROPERTY( GeneratorMode mode READ mode WRITE setMode ) + Q_PROPERTY( QVariantList controls READ controlsV WRITE setControlsV ) + +public: + explicit DatabaseCommand_SetDynamicPlaylistRevision( QObject* parent = 0 ) + : DatabaseCommand_SetPlaylistRevision( parent ) + {} + + explicit DatabaseCommand_SetDynamicPlaylistRevision( const source_ptr& s, + const QString& playlistguid, + const QString& newrev, + const QString& oldrev, + const QStringList& orderedguids, + const QList& addedentries, + const QString& type, + GeneratorMode mode, + const QList< dyncontrol_ptr >& controls ); + + explicit DatabaseCommand_SetDynamicPlaylistRevision( const source_ptr& s, + const QString& playlistguid, + const QString& newrev, + const QString& oldrev, + const QString& type, + GeneratorMode mode, + const QList< dyncontrol_ptr >& controls ); + + QString commandname() const { return "setdynamicplaylistrevision"; } + + virtual void exec( DatabaseImpl* lib ); + virtual void postCommitHook(); + virtual bool doesMutates() const { return true; } + + void setControlsV( const QVariantList& vlist ) + { + m_controlsV = vlist; + } + + QVariantList controlsV(); + + QString type() const { return m_type; } + GeneratorMode mode() const { return m_mode; } + + void setType( const QString& type ) { m_type = type; } + void setMode( GeneratorMode mode ) { m_mode = mode; } + +private: + QString m_type; + GeneratorMode m_mode; + QList< dyncontrol_ptr > m_controls; + QList< QVariant > m_controlsV; +}; + +#endif // DATABASECOMMAND_SETDYNAMICPLAYLISTREVISION_H diff --git a/src/database/databasecommand_setplaylistrevision.cpp b/src/database/databasecommand_setplaylistrevision.cpp index be2dbdfda..b4e21349b 100644 --- a/src/database/databasecommand_setplaylistrevision.cpp +++ b/src/database/databasecommand_setplaylistrevision.cpp @@ -13,11 +13,11 @@ DatabaseCommand_SetPlaylistRevision::DatabaseCommand_SetPlaylistRevision( const QString& oldrev, const QStringList& orderedguids, const QList& addedentries ) - : DatabaseCommandLoggable( s ) +: DatabaseCommandLoggable( s ) + , m_applied( false ) , m_newrev( newrev ) , m_oldrev( oldrev ) , m_addedentries( addedentries ) - , m_applied( false ) { setPlaylistguid( playlistguid ); diff --git a/src/database/databasecommand_setplaylistrevision.h b/src/database/databasecommand_setplaylistrevision.h index f9d420df0..5c0fb04f2 100644 --- a/src/database/databasecommand_setplaylistrevision.h +++ b/src/database/databasecommand_setplaylistrevision.h @@ -69,14 +69,16 @@ public: void setOrderedguids( const QVariantList& l ) { m_orderedguids = l; } QVariantList orderedguids() const { return m_orderedguids; } +protected: + bool m_applied; + QStringList m_previous_rev_orderedguids; + QMap m_addedmap; + private: QString m_playlistguid; QString m_newrev, m_oldrev; QVariantList m_orderedguids; - QStringList m_previous_rev_orderedguids; QList m_addedentries; - bool m_applied; - QMap m_addedmap; }; #endif // DATABASECOMMAND_SETPLAYLISTREVISION_H diff --git a/src/database/schema.sql b/src/database/schema.sql index efaaf45bc..f651835fe 100644 --- a/src/database/schema.sql +++ b/src/database/schema.sql @@ -97,6 +97,28 @@ CREATE TABLE IF NOT EXISTS playlist_revision ( previous_revision TEXT REFERENCES playlist_revision(guid) DEFERRABLE INITIALLY DEFERRED ); +CREATE TABLE IF NOT EXISTS dynamic_playlist { + guid TEXT PRIMARY KEY, + pltype TEXT, -- the generator type + plmode INTEGER -- the mode of this playlist +}; + +-- list of controls in each playlist. each control saves a selectedType, a match, and an input +CREATE TABLE IF NOT EXISTS dynamic_playlist_controls { + id TEXT PRIMARY KEY, + playlist TEXT NOT NULL REFERENCES playlist(guid) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, + selectedType TEXT, + match TEXT, + input TEXT +}; + +CREATE TABLE IF NOT EXISTS dynamic_playlist_revision { + guid TEXT PRIMARY KEY, + controls TEXT, -- qlist( id, id, id ) + plmode INTEGER REFERENCES dynamic_playlist( plmode ) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, + pltype TEXT REFERENCES dynamic_playlist( pltype ) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED +}; + --INSERT INTO playlist_revision(guid, playlist, entries) -- VALUES('revisionguid-1', 'playlistguid-1', '["itemguid-2","itemguid-1","itemguid-3"]'); diff --git a/src/database/tomahawksqlquery.h b/src/database/tomahawksqlquery.h index 543072786..448369f4f 100644 --- a/src/database/tomahawksqlquery.h +++ b/src/database/tomahawksqlquery.h @@ -3,6 +3,7 @@ // subclass QSqlQuery so that it prints the error msg if a query fails #include +#include #include #define TOMAHAWK_QUERY_THRESHOLD 20 diff --git a/src/dynamic/dynamiccontrol.cpp b/src/dynamic/dynamiccontrol.cpp new file mode 100644 index 000000000..5e5dd6bac --- /dev/null +++ b/src/dynamic/dynamiccontrol.cpp @@ -0,0 +1,34 @@ +/**************************************************************************************** + * Copyright (c) 2010 Leo Franchi * + * * + * This program is free software; you can redistribute it and/or modify it under * + * the terms of the GNU General Public License as published by the Free Software * + * Foundation; either version 2 of the License, or (at your option) any later * + * version. * + * * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY * + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along with * + * this program. If not, see . * + ****************************************************************************************/ + +#include "dynamiccontrol.h" + +Tomahawk::DynamicControl::DynamicControl() +{ + +} + +Tomahawk::DynamicControl::~DynamicControl() +{ + +} + +Tomahawk::DynamicControl::DynamicControl(const QString& selectedType, QObject* parent) + : QObject(parent) + , m_selectedType( selectedType ) +{ + +} diff --git a/src/dynamic/dynamiccontrol.h b/src/dynamic/dynamiccontrol.h index b13b9a7b8..1b127cb18 100644 --- a/src/dynamic/dynamiccontrol.h +++ b/src/dynamic/dynamiccontrol.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace Tomahawk { @@ -38,40 +39,63 @@ namespace Tomahawk class DynamicControl : public QObject { Q_OBJECT + Q_PROPERTY( QString id READ id WRITE setId ) Q_PROPERTY( QString selectedType READ selectedType WRITE setSelectedType ) - Q_PROPERTY( QStringList typeSelectors READ typeSelectors ) + Q_PROPERTY( QString match READ match WRITE setMatch ) + Q_PROPERTY( QString input READ input WRITE setInput ) public: + // eff this :P + DynamicControl(); virtual ~DynamicControl(); + /// The current type of this control QString selectedType() const { return m_selectedType; } /// The match selector widget based on this control's type - virtual QWidget* matchSelector() { return 0; } + virtual QWidget* matchSelector() { Q_ASSERT( false ); return 0; } /// The input field widget that is associated with this type - virtual QWidget* inputField() { return 0; } + virtual QWidget* inputField() { Q_ASSERT( false ); return 0; } + + /// the serializable value of the match + QString match() const { Q_ASSERT( false ); return QString(); } + /// the serializable value of the input + QString input() const { Q_ASSERT( false ); return QString(); } + + // used by JSON serialization + void setMatch( const QString& match ) { m_match = match; } + void setInput( const QString& input ) { m_input = input; } /// All the potential type selectors for this control QStringList typeSelectors() const { return m_typeSelectors; } + QString id() { + if( m_id.isEmpty() ) + m_id = uuid(); + return m_id; + }; + void setId( const QString& id ) { m_id = id; } + public slots: /** * Sets the type to the newly specified one. Note that this will update the matchSelector * and inputField widgets, so you should fetch the new widgets for use immediately. */ - virtual void setSelectedType( const QString& type ) { m_selectedType = type; } + virtual void setSelectedType( const QString& selectedType ) { m_selectedType = selectedType; } protected: // Private constructor, you can't make one. Get it from your Generator. - explicit DynamicControl( const QString& type, const QStringList& typeSelectors, QObject* parent = 0 ) : QObject( parent ), m_selectedType( type ), m_typeSelectors( typeSelectors ) {} + explicit DynamicControl( const QString& selectedType, QObject* parent = 0 ); + + QString m_match; + QString m_input; private: QString m_selectedType; QStringList m_typeSelectors; + QString m_id; }; -typedef QSharedPointer dyncontrol_ptr; - }; #endif diff --git a/src/dynamic/dynamicplaylist.cpp b/src/dynamic/dynamicplaylist.cpp index 8348d595c..0341414ab 100644 --- a/src/dynamic/dynamicplaylist.cpp +++ b/src/dynamic/dynamicplaylist.cpp @@ -20,9 +20,24 @@ #include "generatorfactory.h" #include "database.h" #include "databasecommand.h" +#include "databasecommand_createdynamicplaylist.h" +#include "databasecommand_setdynamicplaylistrevision.h" +#include "databasecommand_loaddynamicplaylist.h" using namespace Tomahawk; +DynamicPlaylist::DynamicPlaylist(const Tomahawk::source_ptr& author) + : Playlist(author) +{ + qDebug() << Q_FUNC_INFO << "JSON"; +} + + +DynamicPlaylist::~DynamicPlaylist() +{ + +} + // Called by loadAllPlaylists command DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& src, const QString& currentrevision, @@ -54,6 +69,33 @@ DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& author, // TODO instantiate generator } +geninterface_ptr DynamicPlaylist::generator() const +{ + return m_generator; +} + +GeneratorMode DynamicPlaylist::mode() const +{ + return m_generator->mode(); +} + +void DynamicPlaylist::setGenerator(const Tomahawk::geninterface_ptr& gen_ptr) +{ + m_generator = gen_ptr; +} + +QString DynamicPlaylist::type() const +{ + return m_generator->type(); +} + +void DynamicPlaylist::setMode(GeneratorMode mode) +{ + m_generator->setMode( mode ); +} + + + dynplaylist_ptr DynamicPlaylist::create( const Tomahawk::source_ptr& author, const QString& guid, const QString& title, @@ -129,8 +171,7 @@ void DynamicPlaylist::loadRevision( const QString& rev ) { qDebug() << Q_FUNC_INFO; - DatabaseCommand_LoadDynamicPlaylist* cmd = - new DatabaseCommand_LoadDynamicPlaylist( rev.isEmpty() ? currentrevision() : rev, m_generator->mode() ); + DatabaseCommand_LoadDynamicPlaylist* cmd = new DatabaseCommand_LoadDynamicPlaylist( rev.isEmpty() ? currentrevision() : rev ); if( m_generator->mode() == OnDemand ) { connect( cmd, SIGNAL( done( QString, @@ -238,6 +279,18 @@ void DynamicPlaylist::setRevision( const QString& rev, const QList< dyncontrol_ptr>& controls, bool applied ) { + if( QThread::currentThread() != thread() ) + { + QMetaObject::invokeMethod( this, + "setRevision", + Qt::BlockingQueuedConnection, + Q_ARG( QString, rev ), + Q_ARG( bool, is_newest_rev ), + Q_ARG( QString, type ), + QGenericArgument( "QList< dyncontrol_ptr >" , (const void*)&controls ), + Q_ARG( bool, applied ) ); + return; + } if( m_generator->type() != type ) { // new generator needed m_generator = geninterface_ptr( GeneratorFactory::create( type ) ); } diff --git a/src/dynamic/dynamicplaylist.h b/src/dynamic/dynamicplaylist.h index 407103211..4d62bd016 100644 --- a/src/dynamic/dynamicplaylist.h +++ b/src/dynamic/dynamicplaylist.h @@ -22,7 +22,8 @@ #include #include "tomahawk/playlist.h" -#include "dynamic/generatorinterface.h" +#include "tomahawk/typedefs.h" +#include "dynamic/dynamiccontrol.h" namespace Tomahawk { @@ -42,6 +43,8 @@ struct DynamicPlaylistRevision : PlaylistRevision revisionguid = other.revisionguid; oldrevisionguid = other.oldrevisionguid; newlist = other.newlist; + added = other.added; + removed = other.removed; applied = other.applied; } @@ -56,6 +59,8 @@ class DynamicPlaylist : public Playlist Q_PROPERTY( QString type WRITE setType READ type ) public: + virtual ~DynamicPlaylist(); + /// Generate an empty dynamic playlist with default generator static Tomahawk::dynplaylist_ptr create( const source_ptr& author, const QString& guid, @@ -68,22 +73,18 @@ public: virtual void loadRevision( const QString& rev = "" ); - GeneratorMode mode() const { return m_generator->mode(); } - QString type() const { return m_generator->type(); } - geninterface_ptr generator() const { return m_generator; } + GeneratorMode mode() const; + QString type() const; + geninterface_ptr generator() const; // // these need to exist and be public for the json serialization stuff // you SHOULD NOT call them. They are used for an alternate CTOR method from json. // maybe friend QObjectHelper and make them private? - explicit DynamicPlaylist( const source_ptr& author ) - : Playlist( author ) - { - qDebug() << Q_FUNC_INFO << "JSON"; - } - void setMode( GeneratorMode mode ) { m_generator->setMode( mode ); } + explicit DynamicPlaylist( const source_ptr& author ); + void setMode( GeneratorMode mode ); void setType( const QString& type ) { /** TODO */; } - void setGenerator( const geninterface_ptr& gen_ptr ) { m_generator = gen_ptr; } + void setGenerator( const geninterface_ptr& gen_ptr ); // signals: @@ -140,6 +141,7 @@ private: bool shared ); private: + Q_DISABLE_COPY(DynamicPlaylist) geninterface_ptr m_generator; }; diff --git a/src/dynamic/echonest/echonestcontrol.cpp b/src/dynamic/echonest/echonestcontrol.cpp index 0fb56b058..073b78733 100644 --- a/src/dynamic/echonest/echonestcontrol.cpp +++ b/src/dynamic/echonest/echonestcontrol.cpp @@ -22,8 +22,8 @@ #include -Tomahawk::EchonestControl::EchonestControl( const QString& type, const QStringList& typeSelectors, QObject* parent ) - : DynamicControl ( type, typeSelectors, parent ) +Tomahawk::EchonestControl::EchonestControl( const QString& type, QObject* parent ) + : DynamicControl ( type, parent ) { updateWidgets(); } @@ -76,11 +76,11 @@ Tomahawk::EchonestControl::updateWidgets() void Tomahawk::EchonestControl::updateData() { if( selectedType() == "Artist" ) { - QWeakPointer combo = qWeakPointerCast( m_match ); + QWeakPointer combo = qWeakPointerCast( m_match ); if( !combo.isNull() ) - m_data.first = static_cast( combo.data()->itemData( combo->currentIndex() ) ); - QWeakPointer edit = qWeakPointerCast( m_input ); + m_data.first = static_cast( combo.data()->itemData( combo.data()->currentIndex() ).toInt() ); + QWeakPointer edit = qWeakPointerCast( m_input ); if( !edit.isNull() ) - m_data.second = qWeakPointerCast->text(); + m_data.second = edit.data()->text(); } } diff --git a/src/dynamic/echonest/echonestcontrol.h b/src/dynamic/echonest/echonestcontrol.h index f68e51b87..8e400c4ac 100644 --- a/src/dynamic/echonest/echonestcontrol.h +++ b/src/dynamic/echonest/echonestcontrol.h @@ -36,13 +36,13 @@ public: public slots: virtual void setSelectedType ( const QString& type ); - -protected: - explicit EchonestControl( const QString& type, const QStringList& typeSelectors, QObject* parent = 0 ); - + private slots: void updateData(); +protected: + explicit EchonestControl( const QString& type, QObject* parent = 0 ); + private: void updateWidgets(); @@ -50,6 +50,8 @@ private: QWeakPointer< QWidget > m_match; Echonest::DynamicPlaylist::PlaylistParamData m_data; + + friend class EchonestGenerator; }; typedef QSharedPointer encontrol_ptr; diff --git a/src/dynamic/echonest/echonestgenerator.cpp b/src/dynamic/echonest/echonestgenerator.cpp index bc2ce455a..73dc4914f 100644 --- a/src/dynamic/echonest/echonestgenerator.cpp +++ b/src/dynamic/echonest/echonestgenerator.cpp @@ -16,12 +16,12 @@ #include "echonest/echonestgenerator.h" #include "echonest/echonestcontrol.h" -#include "query.h" +#include "tomahawk/query.h" using namespace Tomahawk; -EchonestFactory::GeneratorFactoryInterface() +EchonestFactory::EchonestFactory() {} GeneratorInterface* @@ -32,12 +32,12 @@ EchonestFactory::create() EchonestGenerator::EchonestGenerator ( QObject* parent ) : GeneratorInterface ( parent ) - , m_type( "echonest" ) - , m_mode( OnDemand ) { m_typeSelectors << "Variety" << "Artist" << "Description" << "Tempo" << "Duration" << "Loudness" << "Danceability" << "Energy" << "Artist Familiarity" << "Artist Hotttnesss" << "Song Familiarity" << "Longitude" << "Latitude" << "Mode" << "Key" << "Sorting"; + m_type = "echonest"; + m_mode = OnDemand; } @@ -49,7 +49,7 @@ EchonestGenerator::~EchonestGenerator() dyncontrol_ptr EchonestGenerator::createControl( const QString& type ) const { - return dyncontrol_ptr( new EchonestControl( type, m_typeSelectors ) ); + return dyncontrol_ptr( new EchonestControl( type ) ); } void diff --git a/src/dynamic/echonest/echonestgenerator.h b/src/dynamic/echonest/echonestgenerator.h index aef705558..5d010755b 100644 --- a/src/dynamic/echonest/echonestgenerator.h +++ b/src/dynamic/echonest/echonestgenerator.h @@ -39,7 +39,7 @@ class EchonestGenerator : public GeneratorInterface { Q_OBJECT public: - explicit EchonestGenerator( QObject* parent ); + explicit EchonestGenerator( QObject* parent = 0 ); virtual ~EchonestGenerator(); virtual dyncontrol_ptr createControl( const QString& type = QString() ) const; diff --git a/src/dynamic/generatorfactory.cpp b/src/dynamic/generatorfactory.cpp index b93dbbe2f..c0f594c2e 100644 --- a/src/dynamic/generatorfactory.cpp +++ b/src/dynamic/generatorfactory.cpp @@ -1,24 +1,19 @@ #include "dynamic/generatorfactory.h" #include "dynamic/generatorinterface.h" -Tomahawk::GeneratorFactory::GeneratorFactory() -{ -} +using namespace Tomahawk; -Tomahawk::GeneratorFactory::~GeneratorFactory() -{ - qDeleteAll( m_factories.values() ); -} +QHash< QString, GeneratorFactoryInterface* > GeneratorFactory::s_factories = QHash< QString, GeneratorFactoryInterface* >(); -generatorinterface_ptr Tomahawk::GeneratorFactory::create ( const QString& type ) +geninterface_ptr GeneratorFactory::create ( const QString& type ) { - if( !m_factories.contains( type ) ) + if( !s_factories.contains( type ) ) return geninterface_ptr(); - return geninterface_ptr( m_factories.value( type )->create() ); + return geninterface_ptr( s_factories.value( type )->create() ); } -void Tomahawk::GeneratorFactory::registerFactory ( const QString& type, Tomahawk::GeneratorFactoryInterface* interface ) +void GeneratorFactory::registerFactory ( const QString& type, GeneratorFactoryInterface* interface ) { - m_factories.insert( type, interface ); + s_factories.insert( type, interface ); } diff --git a/src/dynamic/generatorfactory.h b/src/dynamic/generatorfactory.h index 673895305..c38fe912b 100644 --- a/src/dynamic/generatorfactory.h +++ b/src/dynamic/generatorfactory.h @@ -29,7 +29,7 @@ public: static void registerFactory( const QString& type, GeneratorFactoryInterface* interface ); private: - static QHash m_factories; + static QHash s_factories; }; diff --git a/src/dynamic/generatorinterface.cpp b/src/dynamic/generatorinterface.cpp new file mode 100644 index 000000000..01f7f2c1b --- /dev/null +++ b/src/dynamic/generatorinterface.cpp @@ -0,0 +1,33 @@ +/**************************************************************************************** + * Copyright (c) 2010 Leo Franchi * + * * + * This program is free software; you can redistribute it and/or modify it under * + * the terms of the GNU General Public License as published by the Free Software * + * Foundation; either version 2 of the License, or (at your option) any later * + * version. * + * * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY * + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along with * + * this program. If not, see . * + ****************************************************************************************/ + +#include "dynamic/generatorinterface.h" + +// lame +Tomahawk::GeneratorInterface::GeneratorInterface() +{ + +} + +Tomahawk::GeneratorInterface::GeneratorInterface( QObject* parent ): QObject( parent ) +{ + +} + +Tomahawk::GeneratorInterface::~GeneratorInterface() +{ + +} diff --git a/src/dynamic/generatorinterface.h b/src/dynamic/generatorinterface.h index c89ae07e5..c564adc6d 100644 --- a/src/dynamic/generatorinterface.h +++ b/src/dynamic/generatorinterface.h @@ -24,12 +24,7 @@ #include namespace Tomahawk { - -enum GeneratorMode { - OnDemand = 0, - Static -}; - + /** * The abstract interface for Dynamic Playlist Generators. Generators have the following features: * - They create new DynamicControls that are appropriate for the generator @@ -43,11 +38,12 @@ class GeneratorInterface : public QObject Q_OBJECT Q_PROPERTY( QString type READ type ) Q_PROPERTY( GeneratorMode mode READ mode WRITE setMode ); - Q_ENUMS( GeneratorMode ) public: - explicit GeneratorInterface( QObject* parent = 0 ) : QObject( parent ) {} - virtual ~GeneratorInterface() {} + // can't inline constructors/destructors for forward declared shared pointer types + GeneratorInterface(); + explicit GeneratorInterface( QObject* parent = 0 ); + virtual ~GeneratorInterface(); // Can't make it pure otherwise we can't shove it in QVariants :-/ // empty QString means use default @@ -85,6 +81,9 @@ protected: GeneratorMode m_mode; QList< dyncontrol_ptr > m_controls; QStringList m_typeSelectors; + +private: + Q_DISABLE_COPY(GeneratorInterface) }; typedef QSharedPointer geninterface_ptr; diff --git a/src/network/filetransferconnection.h b/src/network/filetransferconnection.h index 1badf186d..b9258b60c 100644 --- a/src/network/filetransferconnection.h +++ b/src/network/filetransferconnection.h @@ -1,3 +1,4 @@ + #ifndef FILETRANSFERCONNECTION_H #define FILETRANSFERCONNECTION_H @@ -7,6 +8,7 @@ #include "connection.h" #include "tomahawk/result.h" +#include "tomahawk/source.h" class ControlConnection; class BufferIODevice; diff --git a/src/playlist.cpp b/src/playlist.cpp index 916ea4fcc..bf3dbd04b 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -28,6 +28,13 @@ PlaylistEntry::queryvariant() const } +Playlist::Playlist( const source_ptr& author ) + : m_source( author ) + , m_lastmodified( 0 ) +{ + qDebug() << Q_FUNC_INFO << "JSON"; +} + // used when loading from DB: Playlist::Playlist( const source_ptr& src, const QString& currentrevision, diff --git a/src/playlist/plitem.cpp b/src/playlist/plitem.cpp index 18170cb7c..89ac6a80a 100644 --- a/src/playlist/plitem.cpp +++ b/src/playlist/plitem.cpp @@ -1,6 +1,7 @@ #include "plitem.h" #include "utils/tomahawkutils.h" +#include "tomahawk/playlist.h" #include @@ -66,6 +67,18 @@ PlItem::PlItem( const Tomahawk::plentry_ptr& entry, PlItem* parent, int row ) setupItem( entry->query(), parent, row ); } +const Tomahawk::plentry_ptr& +PlItem::entry() const +{ + return m_entry; +} + +const Tomahawk::query_ptr& +PlItem::query() const +{ + if ( !m_entry.isNull() ) return m_entry->query(); else return m_query; +} + void PlItem::setupItem( const Tomahawk::query_ptr& query, PlItem* parent, int row ) diff --git a/src/playlist/plitem.h b/src/playlist/plitem.h index ca2372f26..3de1dd941 100644 --- a/src/playlist/plitem.h +++ b/src/playlist/plitem.h @@ -2,11 +2,11 @@ #define PLITEM_H #include +#include #include #include -#include "tomahawk/query.h" - +#include "tomahawk/result.h" #include "tomahawk/typedefs.h" class PlItem : public QObject @@ -14,15 +14,15 @@ class PlItem : public QObject Q_OBJECT public: - ~PlItem(); + virtual ~PlItem(); explicit PlItem( PlItem* parent = 0, QAbstractItemModel* model = 0 ); explicit PlItem( const QString& caption, PlItem* parent = 0 ); explicit PlItem( const Tomahawk::query_ptr& query, PlItem* parent = 0, int row = -1 ); explicit PlItem( const Tomahawk::plentry_ptr& entry, PlItem* parent = 0, int row = -1 ); - const Tomahawk::plentry_ptr& entry() const { return m_entry; }; - const Tomahawk::query_ptr& query() const { if ( !m_entry.isNull() ) return m_entry->query(); else return m_query; }; + const Tomahawk::plentry_ptr& entry() const; + const Tomahawk::query_ptr& query() const; bool isPlaying() { return m_isPlaying; } void setIsPlaying( bool b ) { m_isPlaying = b; emit dataChanged(); } diff --git a/src/result.cpp b/src/result.cpp index 1f483f63d..19eefe616 100644 --- a/src/result.cpp +++ b/src/result.cpp @@ -30,6 +30,25 @@ Result::Result( const QVariant& v, const collection_ptr& collection ) connect( m_collection->source().data(), SIGNAL( offline() ), SIGNAL( becomingUnavailable() ), Qt::QueuedConnection ); } +Result::~Result() {} + +artist_ptr +Result::artist() const +{ + return m_artist; +} + +album_ptr +Result::album() const +{ + return m_album; +} + +collection_ptr +Result::collection() const +{ + return m_collection; +} float Result::score() const diff --git a/src/source.cpp b/src/source.cpp index 5900858f7..cf8341a34 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -10,7 +10,6 @@ using namespace Tomahawk; - Source::Source( const QString &username, ControlConnection* cc ) : QObject() , m_isLocal( false ) diff --git a/src/tomahawktrayicon.cpp b/src/tomahawktrayicon.cpp index 7dfeec69d..92996b57f 100644 --- a/src/tomahawktrayicon.cpp +++ b/src/tomahawktrayicon.cpp @@ -3,6 +3,8 @@ #include #include "tomahawk/tomahawkapp.h" +#include "tomahawk/artist.h" + #include "audio/audioengine.h" #include "tomahawkwindow.h" diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index 56bd9166e..f49c0bfe7 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -16,6 +16,7 @@ #include "tomahawk/functimeout.h" #include "tomahawk/playlist.h" #include "tomahawk/query.h" +#include "tomahawk/artist.h" #include "database/databasecommand_collectionstats.h" #include "topbar/topbar.h" diff --git a/src/transferview.cpp b/src/transferview.cpp index 74a6da876..628e32f03 100644 --- a/src/transferview.cpp +++ b/src/transferview.cpp @@ -4,6 +4,7 @@ #include #include "tomahawk/tomahawkapp.h" +#include "tomahawk/artist.h" #include "network/filetransferconnection.h" #include "network/servent.h"