1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-13 09:34:53 +02:00

Add dynamic interface, and fix up some more dynamic playlist code

This commit is contained in:
Leo Franchi
2010-12-04 16:51:33 -05:00
parent 5b23b6ad81
commit c30f62e834
11 changed files with 220 additions and 55 deletions

View File

@@ -7,6 +7,7 @@
#include "tomahawk/query.h"
#include "tomahawk/typedefs.h"
#include "typedefs.h"
class DatabaseCommand_LoadAllPlaylists;
class DatabaseCommand_SetPlaylistRevision;
@@ -174,7 +175,7 @@ protected:
const QString& creator,
bool shared );
QList<plentry_ptr> newEntries( const QList< plentry_ptr >& entries );
QList< plentry_ptr > newEntries( const QList< plentry_ptr >& entries );
PlaylistRevision setNewRevision( const QString& rev,
const QList<QString>& neworderedguids,
const QList<QString>& oldorderedguids,

View File

@@ -92,8 +92,9 @@ SET( tomahawkSources ${tomahawkSources}
database/databasecollection.cpp
dynamic/dynamicplaylist.cpp
dynamic/dynamiccontrol.cpp
dynamic/generatorfactory.cpp
dynamic/echonest/echonestgenerator.cpp
dynamic/echonest/echonestcontrol.cpp
scrobbler.cpp
xmppbot/xmppbot.cpp
@@ -230,6 +231,8 @@ SET( tomahawkHeaders ${tomahawkHeaders}
dynamic/dynamiccontrol.h
dynamic/generatorfactory.h
dynamic/generatorinterface.h
dynamic/echonest/echonestgenerator.h
dynamic/echonest/echonestcontrol.h
musicscanner.h
scriptresolver.h

View File

@@ -1,6 +1,77 @@
/****************************************************************************************
* 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>
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 selectedType READ selectedType WRITE setSelectedType )
Q_PROPERTY( QStringList typeSelectors READ typeSelectors )
public:
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; }
/// The input field widget that is associated with this type
virtual QWidget* inputField() { return 0; }
/// All the potential type selectors for this control
QStringList typeSelectors() const { return m_typeSelectors; }
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; }
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 ) {}
private:
QString m_selectedType;
QStringList m_typeSelectors;
};
typedef QSharedPointer<DynamicControl> dyncontrol_ptr;
};
#endif

View File

@@ -1,6 +1,25 @@
/****************************************************************************************
* 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 "tomahawk/tomahawkapp.h"
#include "generatorfactory.h"
#include "database.h"
#include "databasecommand.h"
using namespace Tomahawk;
@@ -44,7 +63,7 @@ dynplaylist_ptr DynamicPlaylist::create( const Tomahawk::source_ptr& author,
{
// TODO default generator?
QString type = "default_generator";
dynplaylist_ptr dynplaylist = new dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, shared ) );
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()) );
@@ -65,12 +84,12 @@ void DynamicPlaylist::createNewRevision( const QString& newrev,
QList< plentry_ptr > added = newEntries( entries );
QStringList orderedguids;
foreach( plentry_ptr p, entries )
orderedguids << p->guid();
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 (localy user in this case)
// source making the change (local user in this case)
source_ptr author = APP->sourcelist().getLocal();
// command writes new rev to DB and calls setRevision, which emits our signal
DatabaseCommand_SetDynamicPlaylistRevision* cmd =
@@ -81,7 +100,7 @@ void DynamicPlaylist::createNewRevision( const QString& newrev,
orderedguids,
added,
type,
STATIC,
OnDemand,
controls );
APP->database()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
@@ -101,7 +120,7 @@ void DynamicPlaylist::createNewRevision( const QString& newrev,
newrev,
oldrev,
type,
STATIC,
Static,
controls );
APP->database()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
@@ -113,7 +132,7 @@ void DynamicPlaylist::loadRevision( const QString& rev )
DatabaseCommand_LoadDynamicPlaylist* cmd =
new DatabaseCommand_LoadDynamicPlaylist( rev.isEmpty() ? currentrevision() : rev, m_generator->mode() );
if( m_generator->mode() == ONDEMAND ) {
if( m_generator->mode() == OnDemand ) {
connect( cmd, SIGNAL( done( QString,
bool,
const QString,
@@ -124,7 +143,7 @@ void DynamicPlaylist::loadRevision( const QString& rev )
const QString,
QList< dyncontrol_ptr>,
bool) ) );
} else if( m_generator->mode() == STATIC ) {
} else if( m_generator->mode() == Static ) {
connect( cmd, SIGNAL( done( QString,
QList< QString >,
QList< QString >,
@@ -148,7 +167,7 @@ void DynamicPlaylist::loadRevision( const QString& rev )
bool DynamicPlaylist::remove( const Tomahawk::dynplaylist_ptr& playlist )
{
return remove( playlist.staticCast<Tomahawk::playlist_ptr>() );
return Playlist::remove( playlist.staticCast<Tomahawk::Playlist>() );
}
void DynamicPlaylist::reportCreated( const Tomahawk::dynplaylist_ptr& self )
@@ -156,7 +175,7 @@ void DynamicPlaylist::reportCreated( const Tomahawk::dynplaylist_ptr& self )
qDebug() << Q_FUNC_INFO;
Q_ASSERT( self.data() == this );
// will emit Collection::playlistCreated(...)
m_source->collection()->addPlaylist( self.staticCast<Tomahawk::playlist_ptr>() );
author()->collection()->addPlaylist( self.staticCast<Tomahawk::Playlist>() );
}
void DynamicPlaylist::reportDeleted( const Tomahawk::dynplaylist_ptr& self )
@@ -164,7 +183,7 @@ void DynamicPlaylist::reportDeleted( const Tomahawk::dynplaylist_ptr& self )
qDebug() << Q_FUNC_INFO;
Q_ASSERT( self.data() == this );
// will emit Collection::playlistCreated(...)
m_source->collection()->deletePlaylist( self.staticCast<Tomahawk::playlist_ptr>() );
author()->collection()->deletePlaylist( self.staticCast<Tomahawk::Playlist>() );
}
// static version
@@ -194,19 +213,19 @@ void DynamicPlaylist::setRevision( const QString& rev,
return;
}
if( m_generator->type() != type ) { // new generator needed
m_generator = generatorinterface_ptr( GeneratorFactory::create( type ) );
m_generator = GeneratorFactory::create( type );
}
m_generator->setControls( controls );
m_generator->setMode( ONDEMAND )
m_generator->setMode( Static );
DynamicPlaylistRevision pr = DynamicPlaylistRevision( setNewRevision( rev, neworderedguids, oldorderedguids, is_newest_rev, addedmap ) );
DynamicPlaylistRevision pr = setNewRevision( rev, neworderedguids, oldorderedguids, is_newest_rev, addedmap );
pr.controls = controls;
pr.type = type;
pr.mode = STATIC;
pr.mode = Static;
if( applied )
setCurrentRevision( rev );
setCurrentrevision( rev );
pr.applied = applied;
emit revisionLoaded( pr );
@@ -220,18 +239,18 @@ void DynamicPlaylist::setRevision( const QString& rev,
bool applied )
{
if( m_generator->type() != type ) { // new generator needed
m_generator = generatorinterface_ptr( GeneratorFactory::create( type ) );
m_generator = geninterface_ptr( GeneratorFactory::create( type ) );
}
m_generator->setControls( controls );
m_generator->setMode( ONDEMAND )
m_generator->setMode( OnDemand );
DynamicPlaylistRevision pr;
pr.oldrevisionguid = m_currentrevision;
pr.oldrevisionguid = currentrevision();
pr.revisionguid = rev;
pr.controls = controls;
pr.type = type;
pr.mode = ONDEMAND;
pr.mode = OnDemand;
emit revisionLoaded( pr );
}

View File

@@ -1,3 +1,19 @@
/****************************************************************************************
* 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
@@ -15,6 +31,23 @@ namespace Tomahawk {
* 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;
applied = other.applied;
}
DynamicPlaylistRevision() {}
};
class DynamicPlaylist : public Playlist
{
Q_OBJECT
@@ -22,12 +55,7 @@ class DynamicPlaylist : public Playlist
Q_PROPERTY( GeneratorMode mode WRITE setMode READ mode )
Q_PROPERTY( QString type WRITE setType READ type )
public:
enum DynamicPlaylistMode {
OnDemand = 0,
StaticPlaylist
};
public:
/// Generate an empty dynamic playlist with default generator
static Tomahawk::dynplaylist_ptr create( const source_ptr& author,
const QString& guid,
@@ -42,7 +70,7 @@ public:
GeneratorMode mode() const { return m_generator->mode(); }
QString type() const { return m_generator->type(); }
generatorinterface_ptr generator() const { return m_generator; }
geninterface_ptr generator() const { return m_generator; }
// <IGNORE hack="true">
// these need to exist and be public for the json serialization stuff
@@ -55,7 +83,7 @@ public:
}
void setMode( GeneratorMode mode ) { m_generator->setMode( mode ); }
void setType( const QString& type ) { /** TODO */; }
void setGenerator( const generatorinterface_ptr& gen_ptr ) { m_generator = gen_ptr; }
void setGenerator( const geninterface_ptr& gen_ptr ) { m_generator = gen_ptr; }
// </IGNORE>
signals:
@@ -112,7 +140,7 @@ private:
bool shared );
private:
generatorinterface_ptr m_generator;
geninterface_ptr m_generator;
};
}; // namespace

View File

@@ -1,4 +1,5 @@
#include "generatorfactory.h"
#include "dynamic/generatorfactory.h"
#include "dynamic/generatorinterface.h"
Tomahawk::GeneratorFactory::GeneratorFactory()
{
@@ -12,9 +13,9 @@ Tomahawk::GeneratorFactory::~GeneratorFactory()
generatorinterface_ptr Tomahawk::GeneratorFactory::create ( const QString& type )
{
if( !m_factories.contains( type ) )
return generatorinterface_ptr();
return geninterface_ptr();
return generatorinterface_ptr( m_factories.value( type )->create() );
return geninterface_ptr( m_factories.value( type )->create() );
}
void Tomahawk::GeneratorFactory::registerFactory ( const QString& type, Tomahawk::GeneratorFactoryInterface* interface )

View File

@@ -4,6 +4,8 @@
#include <QHash>
#include <QString>
#include "dynamic/generatorinterface.h"
namespace Tomahawk {
/**
@@ -12,7 +14,9 @@ namespace Tomahawk {
class GeneratorFactoryInterface
{
public:
GeneratorInterface* create() = 0;
GeneratorFactoryInterface() {}
virtual GeneratorInterface* create() = 0;
};
/**
@@ -21,15 +25,11 @@ public:
class GeneratorFactory
{
public:
GeneratorFactory();
~GeneratorFactory();
generatorinterface_ptr create( const QString& type );
void registerFactory( const QString& type, GeneratorFactoryInterface* interface );
static geninterface_ptr create( const QString& type );
static void registerFactory( const QString& type, GeneratorFactoryInterface* interface );
private:
QHash<QString, GeneratorFactoryInterface*> m_factories;
static QHash<QString, GeneratorFactoryInterface*> m_factories;
};

View File

@@ -1,7 +1,27 @@
/****************************************************************************************
* 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 "dynamic/dynamiccontrol.h"
#include <tomahawk/typedefs.h>
namespace Tomahawk {
@@ -14,7 +34,9 @@ enum GeneratorMode {
* 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 state of OnDemand or Static
* - They have a mode of OnDemand or Static
*
* And they generate tracks
*/
class GeneratorInterface : public QObject
{
@@ -24,29 +46,49 @@ class GeneratorInterface : public QObject
Q_ENUMS( GeneratorMode )
public:
explicit GeneratorInterface() {}
explicit GeneratorInterface( QObject* parent = 0 ) : QObject( parent ) {}
virtual ~GeneratorInterface() {}
// Can't make it pure otherwise we can't shove it in QVariants :-/
virtual dyncontrol_ptr createControl() const {}
// empty QString means use default
virtual dyncontrol_ptr createControl( const QString& type = QString() ) const { return dyncontrol_ptr(); }
/**
* 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
virtual QString type() const { return m_type; }
QString type() const { return m_type; }
virtual GeneratorMode mode() const { return m_mode; }
virtual void setMode( GeneratorMode mode ) { m_mode = mode; }
GeneratorMode mode() const { return m_mode; }
void setMode( GeneratorMode mode ) { m_mode = mode; }
// control functions
virtual QList< dyncontrol_ptr > controls() const { return m_controls; }
virtual void addControl( const dyncontrol_ptr& control ) { m_controls << control; }
virtual void clearControls() { m_controls.clear(); }
virtual void setControls( const QList< dyncontrol_ptr>& controls ) { m_controls = controls; }
private:
QList< dyncontrol_ptr > controls() const { return m_controls; }
void addControl( const dyncontrol_ptr& control ) { m_controls << control; }
void clearControls() { m_controls.clear(); }
void setControls( const QList< dyncontrol_ptr>& controls ) { m_controls = controls; }
QStringList typeSelectors() const { return m_typeSelectors; }
signals:
void generated( const QList< 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

@@ -312,6 +312,7 @@ Playlist::setNewRevision( const QString& rev,
// << "total entries" << m_entries.size();
pr.newlist = entries;
return pr;
}
void Playlist::resolve()
@@ -363,7 +364,7 @@ Playlist::addEntries( const QList<query_ptr>& queries, const QString& oldrev )
}
QList< plentry_ptr >
Playlist::newEntries( const QList< plentry_ptr > entries )
Playlist::newEntries( const QList< plentry_ptr >& entries )
{
QSet<QString> currentguids;
foreach( plentry_ptr p, m_entries )

View File

@@ -8,7 +8,6 @@ Query::Query( const QVariant& v )
: m_v( v )
, m_solved( false )
{
// ensure a QID is present:
QVariantMap m = m_v.toMap();
m_artist = m.value( "artist" ).toString();