1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-04-13 04:21:51 +02:00

Fix merge and compile, fix schema issue

This commit is contained in:
Leo Franchi 2011-01-03 23:50:09 -06:00
parent c28a7b8aa4
commit 2172f68a66
25 changed files with 1781 additions and 17 deletions

View File

@ -0,0 +1,56 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "databasecommand_deletedynamicplaylist.h"
#include <QSqlQuery>
#include "network/servent.h"
using namespace Tomahawk;
DatabaseCommand_DeleteDynamicPlaylist::DatabaseCommand_DeleteDynamicPlaylist( const source_ptr& source, const QString& playlistguid )
: DatabaseCommand_DeletePlaylist( source, playlistguid )
{
}
void
DatabaseCommand_DeleteDynamicPlaylist::exec( DatabaseImpl* lib )
{
qDebug() << Q_FUNC_INFO;
DatabaseCommand_DeletePlaylist::exec( lib );
TomahawkSqlQuery cre = lib->newquery();
cre.prepare( "DELETE FROM dynamic_playlist WHERE guid = :id" );
cre.bindValue( ":id", m_playlistguid );
cre.exec();
}
void
DatabaseCommand_DeleteDynamicPlaylist::postCommitHook()
{
qDebug() << Q_FUNC_INFO << "..reporting..";
dynplaylist_ptr playlist = source()->collection()->dynamicPlaylist( m_playlistguid );
Q_ASSERT( !playlist.isNull() );
playlist->reportDeleted( playlist );
if( source()->isLocal() )
Servent::instance()->triggerDBSync();
}

View File

@ -0,0 +1,45 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef DATABASECOMMAND_DELETEDYNAMICPLAYLIST_H
#define DATABASECOMMAND_DELETEDYNAMICPLAYLIST_H
#include "databaseimpl.h"
#include "databasecommand_deleteplaylist.h"
#include "source.h"
#include "typedefs.h"
class DatabaseCommand_DeleteDynamicPlaylist : public DatabaseCommand_DeletePlaylist
{
Q_OBJECT
public:
explicit DatabaseCommand_DeleteDynamicPlaylist( QObject* parent = 0 )
: DatabaseCommand_DeletePlaylist( parent )
{}
explicit DatabaseCommand_DeleteDynamicPlaylist( const Tomahawk::source_ptr& source, const QString& playlistguid );
QString commandname() const { return "deletedynamicplaylist"; }
virtual void exec( DatabaseImpl* lib );
virtual void postCommitHook();
virtual bool doesMutates() const { return true; }
private:
QString m_playlistguid;
};
#endif // DATABASECOMMAND_DELETEDYNAMICPLAYLIST_H

View File

@ -0,0 +1,56 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "databasecommand_loadalldynamicplaylists.h"
#include <QSqlQuery>
#include "dynamic/DynamicPlaylist.h"
#include "databaseimpl.h"
using namespace Tomahawk;
void DatabaseCommand_LoadAllDynamicPlaylists::exec( DatabaseImpl* dbi )
{
TomahawkSqlQuery query = dbi->newquery();
query.exec( QString( "SELECT playlist.guid as guid, title, info, creator, lastmodified, shared, currentrevision, dynamic_playlist.pltype, dynamic_playlist.plmode "
"FROM playlist, dynamic_playlist WHERE source %1 AND dynplaylist AND playlist.guid = dynamic_playlist.guid" )
.arg( source()->isLocal() ? "IS NULL" :
QString( "=%1" ).arg( source()->id() )
) );
QList<dynplaylist_ptr> plists;
while ( query.next() )
{
dynplaylist_ptr p( new DynamicPlaylist( source(), //src
query.value(6).toString(), //current rev
query.value(1).toString(), //title
query.value(2).toString(), //info
query.value(3).toString(), //creator
query.value(7).toString(), // dynamic type
static_cast<GeneratorMode>(query.value(8).toInt()), // dynamic mode
query.value(5).toBool(), //shared
query.value(4).toInt(), //lastmod
query.value(0).toString() //GUID
) );
plists.append( p );
}
emit done( plists );
}

View File

@ -0,0 +1,42 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef DATABASECOMMAND_LOADALLDYNAMICPLAYLISTS_H
#define DATABASECOMMAND_LOADALLDYNAMICPLAYLISTS_H
#include <QObject>
#include <QVariantMap>
#include "databasecommand.h"
#include "typedefs.h"
class DatabaseCommand_LoadAllDynamicPlaylists : public DatabaseCommand
{
Q_OBJECT
public:
explicit DatabaseCommand_LoadAllDynamicPlaylists( const Tomahawk::source_ptr& s, QObject* parent = 0 )
: DatabaseCommand( s, parent )
{}
virtual void exec( DatabaseImpl* );
virtual bool doesMutates() const { return false; }
virtual QString commandname() const { return "loadalldynamicplaylists"; }
signals:
void done( const QList<Tomahawk::dynplaylist_ptr>& playlists );
};
#endif // DATABASECOMMAND_ADDFILES_H

View File

@ -0,0 +1,74 @@
#include "databasecommand_loaddynamicplaylist.h"
#include <QSqlQuery>
#include <QString>
#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 playlist_revision.playlist, controls, plmode, pltype "
"FROM dynamic_playlist_revision, playlist_revision "
"WHERE dynamic_playlist_revision.guid = ? AND playlist_revision.guid = dynamic_playlist_revision.guid");
controlsQuery.addBindValue( revisionGuid() );
controlsQuery.exec();
QList< dyncontrol_ptr > controls;
QString playlist_guid;
if( controlsQuery.next() )
{
playlist_guid = controlsQuery.value( 0 ).toString();
QStringList controlIds = controlsQuery.value( 1 ).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;
}
}
}
TomahawkSqlQuery info = dbi->newquery();
info.prepare( QString( "SELECT dynamic_playlist.pltype, dynamic_playlist.plmode FROM playlist, dynamic_playlist WHERE playlist.guid = \"%1\" AND playlist.guid = dynamic_playlist.guid" ).arg( playlist_guid ) );
if( !info.exec() ) {
qWarning() << "Failed to load dynplaylist info..";
return;
} else if( !info.first() ) {
qWarning() << "Noo results for queryL:" << info.lastQuery();
return;
}
QString type = info.value( 0 ).toString();
GeneratorMode mode = static_cast<GeneratorMode>( info.value( 1 ).toInt() );
if( mode == OnDemand ) {
Q_ASSERT( m_entrymap.isEmpty() ); // ondemand should have no entry
emit done( revisionGuid(), m_islatest, type, controls, true );
} else {
emit done( revisionGuid(), m_guids, m_oldentries, type, controls, m_islatest, m_entrymap, true );
}
}

View File

@ -0,0 +1,47 @@
#ifndef DATABASECOMMAND_LOADDYNAMICPLAYLIST_H
#define DATABASECOMMAND_LOADDYNAMICPLAYLIST_H
#include <QObject>
#include <QVariantMap>
#include "typedefs.h"
#include "databasecommand.h"
#include "databasecommand_loadplaylistentries.h"
#include "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 )
{ qDebug() << "loaded with:" << revision_guid << guid(); }
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,
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,
QMap< QString, Tomahawk::plentry_ptr >,
bool );
private:
};
#endif // DATABASECOMMAND_LOADDYNAMICPLAYLIST_H

View File

@ -0,0 +1,152 @@
#include "databasecommand_setdynamicplaylistrevision.h"
#include <QSqlQuery>
#include "tomahawksqlquery.h"
#include "dynamic/DynamicPlaylist.h"
#include "dynamic/DynamicControl.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() )
Servent::instance()->triggerDBSync();
}
void
DatabaseCommand_SetDynamicPlaylistRevision::exec( DatabaseImpl* lib )
{
DatabaseCommand_SetPlaylistRevision::exec( lib );
QVariantList newcontrols;
foreach( const dyncontrol_ptr& control, m_controls ) {
newcontrols << control->id();
}
QJson::Serializer ser;
const QByteArray newcontrols_data = ser.serialize( newcontrols );
TomahawkSqlQuery query = lib->newquery();
QString sql = "INSERT INTO dynamic_playlist_revision (guid, controls, plmode, pltype) "
"VALUES(?, ?, ?, ?)";
query.prepare( sql );
query.addBindValue( m_newrev );
query.addBindValue( newcontrols_data );
query.addBindValue( QString::number( (int) m_mode ) );
query.addBindValue( m_type );
query.exec();
// delete all the old controls, replace with new onws
qDebug() << "Deleting controls with playlist id" << m_currentRevision;
TomahawkSqlQuery delQuery = lib->newquery();
delQuery.prepare( "DELETE FROM dynamic_playlist_controls WHERE playlist = ?" );
delQuery.addBindValue( m_currentRevision );
if( !delQuery.exec() )
qWarning() << "Failed to delete controls from dynamic playlist controls table";
TomahawkSqlQuery controlsQuery = lib->newquery();
controlsQuery.prepare( "INSERT INTO dynamic_playlist_controls( id, playlist, selectedType, match, input ) "
"VALUES( ?, ?, ?, ?, ? )" );
foreach( const dyncontrol_ptr& control, m_controls )
{
controlsQuery.addBindValue( control->id() );
controlsQuery.addBindValue( m_playlistguid );
controlsQuery.addBindValue( control->selectedType() );
controlsQuery.addBindValue( control->match() );
controlsQuery.addBindValue( control->input() );
controlsQuery.exec();
}
}

View File

@ -0,0 +1,71 @@
#ifndef DATABASECOMMAND_SETDYNAMICPLAYLISTREVISION_H
#define DATABASECOMMAND_SETDYNAMICPLAYLISTREVISION_H
#include "databasecommand_setplaylistrevision.h"
#include "databaseimpl.h"
#include "collection.h"
#include "playlist.h"
#include "dynamic/GeneratorInterface.h"
#include "network/servent.h"
using namespace Tomahawk;
class DatabaseCommand_SetDynamicPlaylistRevision : public DatabaseCommand_SetPlaylistRevision
{
Q_OBJECT
Q_PROPERTY( QString type READ type WRITE setType )
Q_PROPERTY( int 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<Tomahawk::plentry_ptr>& 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; }
int mode() const { return (int)m_mode; }
void setType( const QString& type ) { m_type = type; }
// void setMode( GeneratorMode mode ) { m_mode = mode; }
void setMode( int mode ) { m_mode = (GeneratorMode)mode; }
private:
QString m_type;
GeneratorMode m_mode;
QList< dyncontrol_ptr > m_controls;
QList< QVariant > m_controlsV;
};
#endif // DATABASECOMMAND_SETDYNAMICPLAYLISTREVISION_H

View File

@ -15,7 +15,7 @@
*/
#include "schema.sql.h"
#define CURRENT_SCHEMA_VERSION 14
#define CURRENT_SCHEMA_VERSION 15
DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )

View File

@ -160,10 +160,6 @@ DatabaseWorker::logOp( DatabaseCommandLoggable* command )
"VALUES(?, ?, ?, ?, ?) ");
QVariantMap variant = QJson::QObjectHelper::qobject2qvariant( command );
qDebug() << "trying to serialize:" << variant.keys();
foreach( const QString& key, variant.keys() ) {
qDebug() << key << ":" << variant.value( key );
}
QByteArray ba = m_serializer.serialize( variant );
// qDebug() << "OP JSON:" << ba.isNull() << ba << "from:" << variant; // debug

View File

@ -133,8 +133,8 @@ INSERT INTO dynamic_playlist_controls(id, playlist, selectedType, match, input)
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
plmode INTEGER,
pltype TEXT
);
INSERT INTO dynamic_playlist_revision(guid, controls, plmode, pltype)
@ -257,4 +257,4 @@ CREATE TABLE IF NOT EXISTS settings (
k TEXT NOT NULL PRIMARY KEY,
v TEXT NOT NULL DEFAULT ''
);
INSERT INTO settings(k,v) VALUES('schema_version', '14');
INSERT INTO settings(k,v) VALUES('schema_version', '15');

View File

@ -1,5 +1,5 @@
/*
This file was automatically generated from schema.sql on Sun Dec 12 21:41:41 EST 2010.
This file was automatically generated from schema.sql on Mon Jan 3 23:24:18 CST 2011.
*/
static const char * tomahawk_schema_sql =
@ -103,8 +103,8 @@ static const char * tomahawk_schema_sql =
"CREATE TABLE IF NOT EXISTS dynamic_playlist_revision ("
" guid TEXT PRIMARY KEY,"
" controls TEXT, "
" 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"
" plmode INTEGER,"
" pltype TEXT"
");"
"INSERT INTO dynamic_playlist_revision(guid, controls, plmode, pltype)"
" VALUES('revisionguid-1', '[\"controlid-1\"]', 0, \"echonest\");"
@ -190,7 +190,7 @@ static const char * tomahawk_schema_sql =
" k TEXT NOT NULL PRIMARY KEY,"
" v TEXT NOT NULL DEFAULT ''"
");"
"INSERT INTO settings(k,v) VALUES('schema_version', '14');"
"INSERT INTO settings(k,v) VALUES('schema_version', '15');"
;
const char * get_tomahawk_sql()

View File

@ -0,0 +1,36 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "DynamicControl.h"
Tomahawk::DynamicControl::DynamicControl( const QStringList& typeSelectors )
: m_typeSelectors( typeSelectors )
{
}
Tomahawk::DynamicControl::~DynamicControl()
{
}
Tomahawk::DynamicControl::DynamicControl(const QString& selectedType, const QStringList& typeSelectors, QObject* parent)
: QObject(parent)
, m_selectedType( selectedType )
, m_typeSelectors( typeSelectors )
{
}

View File

@ -0,0 +1,108 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef DYNAMIC_PLAYLIST_CONTROL
#define DYNAMIC_PLAYLIST_CONTROL
#include <QtCore/QObject>
#include <QtCore/QSharedPointer>
#include <QStringList>
#include <QtGui/QWidget>
#include "typedefs.h"
namespace Tomahawk
{
/**
* A Dynamic Control is a single constraint that limits a dynamic playlist. Each generator creates controls specific to that generator.
* Each control has 3 pieces:
* - Type (string selector for what this control is matching)
* - Match selector (how to match the type to the input)
* - Input field (the user input field).
*
* Each control also has a list of TypeSelectors that comes from the generator, and only one is selected at once.
*
*/
class DynamicControl : public QObject
{
Q_OBJECT
Q_PROPERTY( QString id READ id WRITE setId )
Q_PROPERTY( QString selectedType READ selectedType WRITE setSelectedType )
Q_PROPERTY( QString match READ match WRITE setMatch )
Q_PROPERTY( QString input READ input WRITE setInput )
public:
DynamicControl( const QStringList& typeSelectors = QStringList() );
virtual ~DynamicControl();
/// The current type of this control
QString selectedType() const { return m_selectedType; }
/**
* The match selector widget based on this control's type
*
* The control manages the lifetime of the widget.
*/
virtual QWidget* matchSelector() { Q_ASSERT( false ); return 0; }
/**
* The input field widget that is associated with this type
*
* The control manages the lifetime of the widget.
*/
virtual QWidget* inputField() { Q_ASSERT( false ); return 0; }
/// the serializable value of the match
QString match() const { return m_match; }
/// the serializable value of the input
QString input() const { return m_input; }
// 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& selectedType ) { m_selectedType = selectedType; }
protected:
// Private constructor, you can't make one. Get it from your Generator.
explicit DynamicControl( const QString& selectedType, const QStringList& typeSelectors, QObject* parent = 0 );
QString m_match;
QString m_input;
private:
QString m_selectedType;
QStringList m_typeSelectors;
QString m_id;
};
};
#endif

View File

@ -0,0 +1,349 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "DynamicPlaylist.h"
#include "sourcelist.h"
#include "GeneratorFactory.h"
#include "database/database.h"
#include "database/databasecommand.h"
#include "database/databasecommand_createdynamicplaylist.h"
#include "database/databasecommand_setdynamicplaylistrevision.h"
#include "database/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,
const QString& title,
const QString& info,
const QString& creator,
const QString& type,
GeneratorMode mode,
bool shared,
int lastmod,
const QString& guid )
: Playlist( src, currentrevision, title, info, creator, shared, lastmod, guid )
{
qDebug() << "Creating Dynamic Playlist 1";
// TODO instantiate generator
m_generator = geninterface_ptr( GeneratorFactory::create( type ) );
m_generator->setMode( mode );
}
// called when a new playlist is created (no currentrevision, new guid)
DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& author,
const QString& guid,
const QString& title,
const QString& info,
const QString& creator,
const QString& type,
bool shared )
: Playlist ( author, guid, title, info, creator, shared )
{
qDebug() << "Creating Dynamic Playlist 2";
m_generator = geninterface_ptr( GeneratorFactory::create( type ) );
}
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,
const QString& info,
const QString& creator,
bool shared )
{
// default generator
QString type = "";
dynplaylist_ptr dynplaylist = dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, shared ) );
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist );
connect( cmd, SIGNAL(finished()), dynplaylist.data(), SIGNAL(created()) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
dynplaylist->reportCreated( dynplaylist );
return dynplaylist;
}
// create a new revision that will be a static playlist, as it has entries
void
DynamicPlaylist::createNewRevision( const QString& newrev,
const QString& oldrev,
const QString& type,
const QList< dyncontrol_ptr>& controls,
const QList< plentry_ptr >& entries )
{
// get the newly added tracks
QList< plentry_ptr > added = newEntries( entries );
QStringList orderedguids;
for( int i = 0; i < entries.size(); ++i )
orderedguids << entries.at(i)->guid();
// no conflict resolution or partial updating for controls. all or nothing baby
// source making the change (local user in this case)
source_ptr author = SourceList::instance()->getLocal();
// command writes new rev to DB and calls setRevision, which emits our signal
DatabaseCommand_SetDynamicPlaylistRevision* cmd =
new DatabaseCommand_SetDynamicPlaylistRevision( author,
guid(),
newrev,
oldrev,
orderedguids,
added,
type,
Static,
controls );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
// create a new revision that will be an ondemand playlist, as it has no entries
void
DynamicPlaylist::createNewRevision( const QString& newrev,
const QString& oldrev,
const QString& type,
const QList< dyncontrol_ptr>& controls )
{
// can skip the entry stuff. just overwrite with new info
source_ptr author = SourceList::instance()->getLocal();
// command writes new rev to DB and calls setRevision, which emits our signal
DatabaseCommand_SetDynamicPlaylistRevision* cmd =
new DatabaseCommand_SetDynamicPlaylistRevision( author,
guid(),
newrev,
oldrev,
type,
OnDemand,
controls );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
void
DynamicPlaylist::loadRevision( const QString& rev )
{
qDebug() << Q_FUNC_INFO << "Loading with:" << ( rev.isEmpty() ? currentrevision() : rev );
DatabaseCommand_LoadDynamicPlaylist* cmd = new DatabaseCommand_LoadDynamicPlaylist( rev.isEmpty() ? currentrevision() : rev );
if( m_generator->mode() == OnDemand ) {
connect( cmd, SIGNAL( done( QString,
bool,
QString,
QList< Tomahawk::dyncontrol_ptr>,
bool ) ),
SLOT( setRevision( QString,
bool,
QString,
QList< Tomahawk::dyncontrol_ptr>,
bool) ) );
} else if( m_generator->mode() == Static ) {
connect( cmd, SIGNAL( done( QString,
QList< QString >,
QList< QString >,
QString,
QList< Tomahawk::dyncontrol_ptr>,
bool,
QMap< QString, Tomahawk::plentry_ptr >,
bool ) ),
SLOT( setRevision( QString,
QList< QString >,
QList< QString >,
QString,
QList< Tomahawk::dyncontrol_ptr>,
bool,
QMap< QString, Tomahawk::plentry_ptr >,
bool ) ) );
}
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
bool
DynamicPlaylist::remove( const Tomahawk::dynplaylist_ptr& playlist )
{
// TODO
// DatabaseCommand_DeletePlaylist* cmd = new DatabaseCommand_DeletePlaylist( playlist->author(), playlist->guid() );
// APP->database()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
return false;
}
void
DynamicPlaylist::reportCreated( const Tomahawk::dynplaylist_ptr& self )
{
qDebug() << Q_FUNC_INFO;
Q_ASSERT( self.data() == this );
// will emit Collection::playlistCreated(...)
author()->collection()->addDynamicPlaylist( self );
}
void
DynamicPlaylist::reportDeleted( const Tomahawk::dynplaylist_ptr& self )
{
qDebug() << Q_FUNC_INFO;
Q_ASSERT( self.data() == this );
// will emit Collection::playlistCreated(...)
author()->collection()->deleteDynamicPlaylist( self );
}
void DynamicPlaylist::addEntries(const QList< query_ptr >& queries, const QString& oldrev)
{
Q_ASSERT( m_generator->mode() == Static );
QList<plentry_ptr> el = addEntriesInternal( queries );
QString newrev = uuid();
createNewRevision( newrev, oldrev, m_generator->type(), m_generator->controls(), el );
}
void DynamicPlaylist::addEntry(const Tomahawk::query_ptr& query, const QString& oldrev)
{
QList<query_ptr> queries;
queries << query;
addEntries( queries, oldrev );
}
// static version
void
DynamicPlaylist::setRevision( const QString& rev,
const QList< QString >& neworderedguids,
const QList< QString >& oldorderedguids,
const QString& type,
const QList< Tomahawk::dyncontrol_ptr>& controls,
bool is_newest_rev,
const QMap< QString, Tomahawk::plentry_ptr >& addedmap,
bool applied )
{
// we're probably being called by a database worker thread
if( QThread::currentThread() != thread() )
{
QMetaObject::invokeMethod( this,
"setRevision",
Qt::BlockingQueuedConnection,
Q_ARG( QString, rev ),
Q_ARG( QList<QString> , neworderedguids ),
Q_ARG( QList<QString> , oldorderedguids ),
Q_ARG( QString , type ),
QGenericArgument( "QList< Tomahawk::dyncontrol_ptr > " , (const void*)&controls ),
Q_ARG( bool, is_newest_rev ),
QGenericArgument( "QMap< QString,Tomahawk::plentry_ptr > " , (const void*)&addedmap ),
Q_ARG( bool, applied ) );
return;
}
if( m_generator->type() != type ) { // new generator needed
m_generator = GeneratorFactory::create( type );
}
m_generator->setControls( controls );
m_generator->setMode( Static );
DynamicPlaylistRevision pr = setNewRevision( rev, neworderedguids, oldorderedguids, is_newest_rev, addedmap );
pr.controls = controls;
pr.type = type;
pr.mode = Static;
if( applied )
setCurrentrevision( rev );
pr.applied = applied;
emit revisionLoaded( pr );
}
// ondemand version
void
DynamicPlaylist::setRevision( const QString& rev,
bool is_newest_rev,
const QString& type,
const QList< Tomahawk::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< Tomahawk::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 ) );
}
m_generator->setControls( controls );
m_generator->setMode( OnDemand );
DynamicPlaylistRevision pr;
pr.oldrevisionguid = currentrevision();
pr.revisionguid = rev;
pr.controls = controls;
pr.type = type;
pr.mode = OnDemand;
emit revisionLoaded( pr );
}

View File

@ -0,0 +1,161 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef DYNAMIC_PLAYLIST_H
#define DYNAMIC_PLAYLIST_H
#include <QObject>
#include <QList>
#include <QSharedPointer>
#include "playlist.h"
#include "typedefs.h"
#include "dynamic/DynamicControl.h"
class DatabaseCommand_LoadAllDynamicPlaylists;
class DatabaseCommand_SetDynamicPlaylistRevision;
class DatabaseCommand_CreateDynamicPlaylist;
namespace Tomahawk {
/**
* Subclass of playlist that adds the information needed to store a dynamic playlist.
* It uses normal PlaylistEntries but also has a mode, a generator, and a list of controls
*/
struct DynamicPlaylistRevision : PlaylistRevision
{
QList< dyncontrol_ptr > controls;
Tomahawk::GeneratorMode mode;
QString type;
DynamicPlaylistRevision( const PlaylistRevision& other )
{
revisionguid = other.revisionguid;
oldrevisionguid = other.oldrevisionguid;
newlist = other.newlist;
added = other.added;
removed = other.removed;
applied = other.applied;
}
DynamicPlaylistRevision() {}
};
class DynamicPlaylist : public Playlist
{
Q_OBJECT
Q_PROPERTY( GeneratorMode mode WRITE setMode READ mode )
Q_PROPERTY( QString type WRITE setType READ type )
friend class ::DatabaseCommand_LoadAllDynamicPlaylists;
friend class ::DatabaseCommand_SetDynamicPlaylistRevision;
friend class ::DatabaseCommand_CreateDynamicPlaylist;
public:
virtual ~DynamicPlaylist();
/// Generate an empty dynamic playlist with default generator
static Tomahawk::dynplaylist_ptr create( const source_ptr& author,
const QString& guid,
const QString& title,
const QString& info,
const QString& creator,
bool shared
);
static bool remove( const dynplaylist_ptr& playlist );
virtual void loadRevision( const QString& rev = "" );
GeneratorMode mode() const;
QString type() const;
geninterface_ptr generator() const;
virtual void addEntries( const QList< query_ptr >& queries, const QString& oldrev );
virtual void addEntry( const Tomahawk::query_ptr& query, const QString& oldrev );
// <IGNORE hack="true">
// 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 );
void setMode( GeneratorMode mode );
void setType( const QString& type ) { /** TODO */; }
void setGenerator( const geninterface_ptr& gen_ptr );
// </IGNORE>
signals:
/// emitted when the playlist revision changes (whenever the playlist changes)
void revisionLoaded( Tomahawk::DynamicPlaylistRevision );
public slots:
// want to update the playlist from the model?
// generate a newrev using uuid() and call this:
// if this is a static playlist, pass it a new list of entries. implicitly sets mode to static
void createNewRevision( const QString& newrev, const QString& oldrev, const QString& type, const QList< dyncontrol_ptr>& controls, const QList< plentry_ptr >& entries );
// if it is ondemand, no entries are needed implicitly sets mode to ondemand
void createNewRevision( const QString& newrev, const QString& oldrev, const QString& type, const QList< dyncontrol_ptr>& controls );
void reportCreated( const Tomahawk::dynplaylist_ptr& self );
void reportDeleted( const Tomahawk::dynplaylist_ptr& self );
// called from setdynamicplaylistrevision db cmd
// static version
void setRevision( const QString& rev,
const QList<QString>& neworderedguids,
const QList<QString>& oldorderedguids,
const QString& type,
const QList< Tomahawk::dyncontrol_ptr>& controls,
bool is_newest_rev,
const QMap< QString, Tomahawk::plentry_ptr >& addedmap,
bool applied );
// ondemand version
void setRevision( const QString& rev,
bool is_newest_rev,
const QString& type,
const QList< Tomahawk::dyncontrol_ptr>& controls,
bool applied );
private:
// called from loadAllPlaylists DB cmd:
explicit DynamicPlaylist( const source_ptr& src,
const QString& currentrevision,
const QString& title,
const QString& info,
const QString& creator,
const QString& type,
GeneratorMode mode,
bool shared,
int lastmod,
const QString& guid = "" ); // populate db
// called when creating new playlist
explicit DynamicPlaylist( const source_ptr& author,
const QString& guid,
const QString& title,
const QString& info,
const QString& creator,
const QString& type,
bool shared );
private:
geninterface_ptr m_generator;
};
}; // namespace
#endif

View File

@ -0,0 +1,27 @@
#include "dynamic/GeneratorFactory.h"
#include "dynamic/GeneratorInterface.h"
using namespace Tomahawk;
QHash< QString, GeneratorFactoryInterface* > GeneratorFactory::s_factories = QHash< QString, GeneratorFactoryInterface* >();
geninterface_ptr GeneratorFactory::create ( const QString& type )
{
if( type.isEmpty() && !s_factories.isEmpty() ) // default, return first
return geninterface_ptr( s_factories.begin().value()->create() );
if( !s_factories.contains( type ) )
return geninterface_ptr();
return geninterface_ptr( s_factories.value( type )->create() );
}
void GeneratorFactory::registerFactory ( const QString& type, GeneratorFactoryInterface* interface )
{
s_factories.insert( type, interface );
}
QStringList GeneratorFactory::types()
{
return s_factories.keys();
}

View File

@ -0,0 +1,40 @@
#ifndef GENERATOR_FACTORY_H
#define GENERATOR_FACTORY_H
#include <QHash>
#include <QString>
#include "dynamic/GeneratorInterface.h"
namespace Tomahawk {
/**
* Generators should subclass this and have it create the custom Generator
*/
class GeneratorFactoryInterface
{
public:
GeneratorFactoryInterface() {}
virtual GeneratorInterface* create() = 0;
};
/**
* Simple factory that generates Generators from string type descriptors
*/
class GeneratorFactory
{
public:
static geninterface_ptr create( const QString& type );
static void registerFactory( const QString& type, GeneratorFactoryInterface* interface );
static QStringList types();
private:
static QHash<QString, GeneratorFactoryInterface*> s_factories;
};
};
#endif

View File

@ -0,0 +1,67 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "dynamic/GeneratorInterface.h"
// lame
Tomahawk::GeneratorInterface::GeneratorInterface()
{
}
Tomahawk::GeneratorInterface::GeneratorInterface( QObject* parent ): QObject( parent )
{
}
Tomahawk::GeneratorInterface::~GeneratorInterface()
{
}
QList< Tomahawk::dyncontrol_ptr >
Tomahawk::GeneratorInterface::controls()
{
if( m_controls.isEmpty() ) { // return a default control (so the user can add more)
return QList< Tomahawk::dyncontrol_ptr >() << createControl();
}
return m_controls;
}
void
Tomahawk::GeneratorInterface::addControl( const Tomahawk::dyncontrol_ptr& control )
{
m_controls << control;
}
void
Tomahawk::GeneratorInterface::clearControls()
{
m_controls.clear();
}
void
Tomahawk::GeneratorInterface::setControls( const QList< Tomahawk::dyncontrol_ptr >& controls )
{
m_controls = controls;
}
Tomahawk::dyncontrol_ptr Tomahawk::GeneratorInterface::createControl(const QString& type)
{
return dyncontrol_ptr();
}

View File

@ -0,0 +1,95 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef GENERATOR_INTERFACE_H
#define GENERATOR_INTERFACE_H
#include <QtCore/QObject>
#include <QtCore/QSharedPointer>
#include <QStringList>
#include "typedefs.h"
#include "query.h"
#include "dynamic/DynamicControl.h"
namespace Tomahawk {
/**
* The abstract interface for Dynamic Playlist Generators. Generators have the following features:
* - They create new DynamicControls that are appropriate for the generator
* - They expose a list of controls that this generator currently is operating on
* - They have a mode of OnDemand or Static
*
* And they generate tracks
*/
class GeneratorInterface : public QObject
{
Q_OBJECT
Q_PROPERTY( QString type READ type )
Q_PROPERTY( GeneratorMode mode READ mode WRITE setMode )
Q_ENUMS( GeneratorMode )
public:
// 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
/// The generator will keep track of all the controls it creates. No need to tell it about controls
/// you ask it to create
virtual dyncontrol_ptr createControl( const QString& type = QString() );
/**
* Generate tracks from the controls in this playlist. If the current mode is
* OnDemand, then \p number is not taken into account. If this generator is in static
* mode, then it will return the desired number of tracks
*
* Connect to the generated() signal for the results.
*
*/
virtual void generate( int number = -1 ) {}
/// The type of this generator
QString type() const { return m_type; }
GeneratorMode mode() const { return m_mode; }
void setMode( GeneratorMode mode ) { m_mode = mode; }
// control functions
QList< dyncontrol_ptr > controls();
void addControl( const dyncontrol_ptr& control );
void clearControls();
void setControls( const QList< dyncontrol_ptr>& controls );
QStringList typeSelectors() const { return m_typeSelectors; }
signals:
void generated( const QList< Tomahawk::query_ptr>& queries );
protected:
QString m_type;
GeneratorMode m_mode;
QList< dyncontrol_ptr > m_controls;
QStringList m_typeSelectors;
};
typedef QSharedPointer<GeneratorInterface> geninterface_ptr;
};
#endif

View File

@ -0,0 +1,109 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "dynamic/echonest/EchonestControl.h"
#include <echonest/Playlist.h>
#include <QComboBox>
#include <QLineEdit>
Tomahawk::EchonestControl::EchonestControl( const QString& type, const QStringList& typeSelectors, QObject* parent )
: DynamicControl ( type.isEmpty() ? "Artist" : type, typeSelectors, parent )
{
updateWidgets();
}
QWidget*
Tomahawk::EchonestControl::inputField()
{
return m_input.data();
}
QWidget*
Tomahawk::EchonestControl::matchSelector()
{
return m_match.data();
}
void
Tomahawk::EchonestControl::setSelectedType ( const QString& type )
{
if( !m_input.isNull() )
delete m_input.data();
if( !m_match.isNull() )
delete m_match.data();
Tomahawk::DynamicControl::setSelectedType ( type );
updateWidgets();
}
Echonest::DynamicPlaylist::PlaylistParamData
Tomahawk::EchonestControl::toENParam() const
{
return m_data;
}
void
Tomahawk::EchonestControl::updateWidgets()
{
if( !m_input.isNull() )
delete m_input.data();
if( !m_match.isNull() )
delete m_match.data();
// make sure the widgets are the proper kind for the selected type, and hook up to their slots
if( selectedType() == "Artist" ) {
m_currentType = Echonest::DynamicPlaylist::Artist;
QComboBox* match = new QComboBox();
QLineEdit* input = new QLineEdit();
match->addItem( "Limit To", Echonest::DynamicPlaylist::ArtistType );
match->addItem( "Similar To", Echonest::DynamicPlaylist::ArtistRadioType );
input->setPlaceholderText( "Artist name" );
input->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Fixed );
connect( match, SIGNAL( currentIndexChanged(int) ), this, SLOT( updateData() ) );
connect( input, SIGNAL( textChanged(QString) ), this, SLOT( updateData() ) );
match->hide();
input->hide();
m_match = QWeakPointer< QWidget >( match );
m_input = QWeakPointer< QWidget >( input );
} else {
m_match = QWeakPointer<QWidget>( new QWidget );
m_input = QWeakPointer<QWidget>( new QWidget );
}
}
void
Tomahawk::EchonestControl::updateData()
{
qDebug() << "Sender:" << sender() << qobject_cast<QLineEdit*>(sender()) << m_input << qobject_cast<QLineEdit*>(m_input.data());
if( selectedType() == "Artist" ) {
QComboBox* combo = qobject_cast<QComboBox*>( m_match.data() );
if( combo ) {
}
QLineEdit* edit = qobject_cast<QLineEdit*>( m_input.data() );
if( edit && !edit->text().isEmpty() ) {
m_data.first = m_currentType;
m_data.second = edit->text();
}
}
}

View File

@ -0,0 +1,63 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_CONTROL_H
#define ECHONEST_CONTROL_H
#include <echonest/Playlist.h>
#include "dynamic/DynamicControl.h"
namespace Tomahawk
{
class EchonestControl : public DynamicControl
{
Q_OBJECT
public:
virtual QWidget* inputField();
virtual QWidget* matchSelector();
/// Converts this to an echonest suitable parameter
Echonest::DynamicPlaylist::PlaylistParamData toENParam() const;
public slots:
virtual void setSelectedType ( const QString& type );
private slots:
void updateData();
protected:
explicit EchonestControl( const QString& type, const QStringList& typeSelectors, QObject* parent = 0 );
private:
void updateWidgets();
Echonest::DynamicPlaylist::PlaylistParam m_currentType;
QWeakPointer< QWidget > m_input;
QWeakPointer< QWidget > m_match;
Echonest::DynamicPlaylist::PlaylistParamData m_data;
friend class EchonestGenerator;
};
typedef QSharedPointer<EchonestControl> encontrol_ptr;
};
#endif

View File

@ -0,0 +1,112 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "dynamic/echonest/EchonestGenerator.h"
#include "dynamic/echonest/EchonestControl.h"
#include "query.h"
using namespace Tomahawk;
EchonestFactory::EchonestFactory()
{}
GeneratorInterface*
EchonestFactory::create()
{
return new EchonestGenerator();
}
EchonestGenerator::EchonestGenerator ( QObject* parent )
: GeneratorInterface ( parent )
{
m_typeSelectors << "Artist" << "Variety" << "Description" << "Tempo" << "Duration" << "Loudness"
<< "Danceability" << "Energy" << "Artist Familiarity" << "Artist Hotttnesss" << "Song Familiarity"
<< "Longitude" << "Latitude" << "Mode" << "Key" << "Sorting";
m_type = "echonest";
m_mode = OnDemand;
}
EchonestGenerator::~EchonestGenerator()
{
}
dyncontrol_ptr
EchonestGenerator::createControl( const QString& type )
{
m_controls << dyncontrol_ptr( new EchonestControl( type, m_typeSelectors ) );
return m_controls.last();
}
void
EchonestGenerator::generate ( int number )
{
// convert to an echonest query, and fire it off
if( number < 0 ) { // dynamic
} else { // static
Echonest::DynamicPlaylist::PlaylistParams params;
foreach( const dyncontrol_ptr& control, m_controls ) {
params.append( control.dynamicCast<EchonestControl>()->toENParam() );
}
params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, determineRadioType() ) );
params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Results, number ) );
QNetworkReply* reply = Echonest::DynamicPlaylist::staticPlaylist( params );
qDebug() << "Generating a static playlist from echonest!" << reply->url().toString();
connect( reply, SIGNAL( finished() ), this, SLOT( staticFinished() ) );
}
}
void
EchonestGenerator::staticFinished()
{
Q_ASSERT( sender() );
Q_ASSERT( qobject_cast< QNetworkReply* >( sender() ) );
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
Echonest::SongList songs;
try {
songs = Echonest::DynamicPlaylist::parseStaticPlaylist( reply );
} catch( const Echonest::ParseError& e ) {
qWarning() << "libechonest threw an error trying to parse the static playlist!" << e.errorType() << e.what();
return;
}
QList< query_ptr > queries;
foreach( const Echonest::Song& song, songs ) {
qDebug() << "EchonestGenerator got song:" << song;
QVariantMap track;
track[ "artist" ] = song.artistName();
// track[ "album" ] = song.release(); // TODO should we include it? can be quite specific
track[ "track" ] = song.title();
queries << query_ptr( new Query( track ) );
}
emit generated( queries );
}
// tries to heuristically determine what sort of radio this is based on the controls
Echonest::DynamicPlaylist::ArtistTypeEnum EchonestGenerator::determineRadioType() const
{
// TODO
return Echonest::DynamicPlaylist::ArtistRadioType;
}

View File

@ -0,0 +1,58 @@
/****************************************************************************************
* Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#ifndef ECHONEST_GENERATOR_H
#define ECHONEST_GENERATOR_H
#include <echonest/Playlist.h>
#include "dynamic/GeneratorInterface.h"
#include "dynamic/GeneratorFactory.h"
#include "dynamic/DynamicControl.h"
namespace Tomahawk
{
class EchonestFactory : public GeneratorFactoryInterface
{
public:
EchonestFactory();
virtual GeneratorInterface* create();
};
class EchonestGenerator : public GeneratorInterface
{
Q_OBJECT
public:
explicit EchonestGenerator( QObject* parent = 0 );
virtual ~EchonestGenerator();
virtual dyncontrol_ptr createControl( const QString& type = QString() );
virtual void generate ( int number = -1 );
private slots:
void staticFinished();
private:
Echonest::DynamicPlaylist::ArtistTypeEnum determineRadioType() const;
};
};
#endif

View File

@ -286,11 +286,11 @@ Playlist::setNewRevision( const QString& rev,
//qDebug() << "counters:" << neworderedguids.count() << entriesmap.count() << addedmap.count();
foreach( const QString& id, neworderedguids )
{
qDebug() << "id:" << id;
qDebug() << "newordered:" << neworderedguids.count() << neworderedguids;
qDebug() << "entriesmap:" << entriesmap.count() << entriesmap;
qDebug() << "addedmap:" << addedmap.count() << addedmap;
qDebug() << "m_entries" << m_entries;
//qDebug() << "id:" << id;
//qDebug() << "newordered:" << neworderedguids.count() << neworderedguids;
//qDebug() << "entriesmap:" << entriesmap.count() << entriesmap;
//qDebug() << "addedmap:" << addedmap.count() << addedmap;
//qDebug() << "m_entries" << m_entries;
if( entriesmap.contains( id ) )
{