From 4a8b851ba58d6199811226e029af87ab13a65356 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Mon, 25 Jul 2011 18:00:14 -0400 Subject: [PATCH 01/17] Initial database generators --- .../databasecommand_genericselect.cpp | 101 +++++++++++ .../database/databasecommand_genericselect.h | 56 ++++++ .../dynamic/database/DatabaseControl.cpp | 147 ++++++++++++++++ .../dynamic/database/DatabaseControl.h | 81 +++++++++ .../dynamic/database/DatabaseGenerator.cpp | 160 ++++++++++++++++++ .../dynamic/database/DatabaseGenerator.h | 80 +++++++++ 6 files changed, 625 insertions(+) create mode 100644 src/libtomahawk/database/databasecommand_genericselect.cpp create mode 100644 src/libtomahawk/database/databasecommand_genericselect.h create mode 100644 src/libtomahawk/playlist/dynamic/database/DatabaseControl.cpp create mode 100644 src/libtomahawk/playlist/dynamic/database/DatabaseControl.h create mode 100644 src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp create mode 100644 src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h diff --git a/src/libtomahawk/database/databasecommand_genericselect.cpp b/src/libtomahawk/database/databasecommand_genericselect.cpp new file mode 100644 index 000000000..905b5e039 --- /dev/null +++ b/src/libtomahawk/database/databasecommand_genericselect.cpp @@ -0,0 +1,101 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#include "databasecommand_genericselect.h" + +#include "databaseimpl.h" +#include "utils/logger.h" +#include +#include +#include + +using namespace Tomahawk; + + +DatabaseCommand_GenericSelect::DatabaseCommand_GenericSelect( const QString& sqlSelect, QObject* parent ) + : DatabaseCommand( parent ) + , m_sqlSelect( sqlSelect ) +{ +} + + +void +DatabaseCommand_GenericSelect::exec( DatabaseImpl* dbi ) +{ + Q_ASSERT( source()->isLocal() || source()->id() >= 1 ); + TomahawkSqlQuery query = dbi->newquery(); + + query.exec( m_sqlSelect ); + + QList< query_ptr > queries; + + + // Expecting + while ( query.next() ) + { + Tomahawk::result_ptr result = Tomahawk::result_ptr( new Tomahawk::Result() ); + Tomahawk::source_ptr s; + + QString artist, track, album; + artist = query.value( 0 ).toString(); + album = query.value( 1 ).toString(); + track = query.value( 2 ).toString(); + + Tomahawk::query_ptr qry = Tomahawk::Query::get( artist, track, album, uuid(), (query.value( 7 ).toUInt() != 0) ); // Only auto-resolve non-local results + Tomahawk::artist_ptr artistptr = Tomahawk::Artist::get( query.value( 12 ).toUInt(), artist ); + Tomahawk::album_ptr albumptr = Tomahawk::Album::get( query.value( 13 ).toUInt(), album, artistptr ); + + // If it's a local track, set to the local source and url in the result and we're done. otherwise, we get resolved + if( query.value( 7 ).toUInt() == 0 ) + { + s = SourceList::instance()->getLocal(); + result->setUrl( query.value( 7 ).toString() ); + + result->setId( query.value( 9 ).toUInt() ); + result->setArtist( artistptr ); + result->setAlbum( albumptr ); + result->setTrack( query.value( 2 ).toString() ); + result->setSize( query.value( 3 ).toUInt() ); + result->setDuration( query.value( 4 ).toUInt() ); + result->setBitrate( query.value( 5 ).toUInt() ); + result->setMimetype( query.value( 8 ).toString() ); + result->setScore( 1.0 ); + result->setCollection( s->collection() ); + + TomahawkSqlQuery attrQuery = dbi->newquery(); + QVariantMap attr; + + attrQuery.prepare( "SELECT k, v FROM track_attributes WHERE id = ?" ); + attrQuery.bindValue( 0, result->dbid() ); + attrQuery.exec(); + while ( attrQuery.next() ) + { + attr[ attrQuery.value( 0 ).toString() ] = attrQuery.value( 1 ).toString(); + } + + result->setAttributes( attr ); + + qry->addResults( QList() << result ); + qry->setResolveFinished( true ); + } + + queries << qry; + } + + emit tracks( queries ); +} diff --git a/src/libtomahawk/database/databasecommand_genericselect.h b/src/libtomahawk/database/databasecommand_genericselect.h new file mode 100644 index 000000000..e054f9faa --- /dev/null +++ b/src/libtomahawk/database/databasecommand_genericselect.h @@ -0,0 +1,56 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#ifndef DATABASECOMMAND_GENERICSELECT_H +#define DATABASECOMMAND_GENERICSELECT_H + +#include + +#include "databasecommand.h" +#include "source.h" +#include "typedefs.h" + +#include "dllmacro.h" + +/** + * This dbcmd takes a generic SELECT command that operates on the database and returns a list of query_ptrs + * that match. + * + * In order for the conversion to query_ptr to work, the SELECT command should select the following items: + * artist.name, album.name, track.name, file.size, file.duration, file.bitrate, file.url, file.source, file.mimetype, track.id + * + */ +class DLLEXPORT DatabaseCommand_GenericSelect : public DatabaseCommand +{ + Q_OBJECT + +public: + explicit DatabaseCommand_GenericSelect( const QString& sqlSelect, QObject* parent = 0 ); + virtual void exec( DatabaseImpl* lib ); + virtual bool doesMutates() const { return false; } + + virtual QString commandname() const { return "genericselect"; } + +signals: + void tracks( const QList< Tomahawk::query_ptr >& tracks ); + +private: + QString m_sqlSelect; +}; + +#endif // DATABASECOMMAND_GENERICSELECT_H diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseControl.cpp b/src/libtomahawk/playlist/dynamic/database/DatabaseControl.cpp new file mode 100644 index 000000000..6cdb650e3 --- /dev/null +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseControl.cpp @@ -0,0 +1,147 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#include "DatabaseControl.h" + +using namespace Tomahawk; + +DatabaseControl::DatabaseControl( const QString& selectedType, const QStringList& typeSelectors, QObject* parent ) +: DynamicControl ( selectedType.isEmpty() ? "Artist" : selectedType, typeSelectors, parent ) +{ + setType( "database" ); + + m_editingTimer.setInterval( 500 ); //timeout to edits + m_editingTimer.setSingleShot( true ); + connect( &m_editingTimer, SIGNAL( timeout() ), this, SLOT( editTimerFired() ) ); + + m_delayedEditTimer.setInterval( 250 ); // additional timer for "just typing" without enter or focus change + m_delayedEditTimer.setSingleShot( true ); + connect( &m_delayedEditTimer, SIGNAL( timeout() ), &m_editingTimer, SLOT( start() ) ); + +} + +DatabaseControl::DatabaseControl( const QString& sql, const QString& summary, const QStringList& typeSelectors, QObject* parent ) + : DynamicControl ( typeSelectors ) + , m_sql( sql ) + , m_sqlSummary( summary ) +{ + setType( "database" ); +} + + +QString DatabaseControl::input() const +{ + // TODO + return QString(); +} + +QWidget* DatabaseControl::inputField() +{ + return 0; +} + +QString DatabaseControl::match() const +{ + return m_matchData; +} + +QWidget* DatabaseControl::matchSelector() +{ + return 0; +} + +QString DatabaseControl::matchString() const +{ + return m_matchString; +} + +void DatabaseControl::setInput ( const QString& input ) +{ + // TODO + updateWidgets(); +} + +void DatabaseControl::setMatch ( const QString& match ) +{ + m_matchData = match; + + updateWidgets(); +} + +void DatabaseControl::setSelectedType ( const QString& type ) +{ + if ( type != selectedType() ) { + if ( !m_input.isNull() ) + delete m_input.data(); + if ( !m_match.isNull() ) + delete m_match.data(); + + Tomahawk::DynamicControl::setSelectedType ( type ); + updateWidgets(); + updateData(); + // qDebug() << "Setting new type, set data to:" << m_data.first << m_data.second; + } +} + +void DatabaseControl::editingFinished() +{ + +} + +void DatabaseControl::editTimerFired() +{ + +} + +void DatabaseControl::updateData() +{ + +} + +void DatabaseControl::updateWidgets() +{ + +} + +void DatabaseControl::updateWidgetsFromData() +{ + +} + +void DatabaseControl::calculateSummary() +{ + if( !m_sqlSummary.isEmpty() ) + return; + +} + +QString +DatabaseControl::sql() const +{ + return m_sql; +} + + +QString +DatabaseControl::summary() const +{ + if( !m_sqlSummary.isEmpty() ) + return m_sqlSummary; + + return m_summary; +} diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseControl.h b/src/libtomahawk/playlist/dynamic/database/DatabaseControl.h new file mode 100644 index 000000000..bf2a39d7e --- /dev/null +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseControl.h @@ -0,0 +1,81 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#ifndef DATABASE_CONTROL_H +#define DATABASE_CONTROL_H + +#include "dynamic/DynamicControl.h" + +#include + +namespace Tomahawk +{ + + class DatabaseControl : public DynamicControl + { + Q_OBJECT + public: + virtual QWidget* inputField(); + virtual QWidget* matchSelector(); + + virtual QString input() const; + virtual QString match() const; + virtual QString matchString() const; + virtual QString summary() const; + + virtual void setInput(const QString& input); + virtual void setMatch(const QString& match); + + /// DO NOT USE IF YOU ARE NOT A DBCMD + DatabaseControl( const QString& type, const QStringList& typeSelectors, QObject* parent = 0 ); + DatabaseControl( const QString& sql, const QString& summary, const QStringList& typeSelectors, QObject* parent = 0 ); + + QString sql() const; + + public slots: + virtual void setSelectedType ( const QString& type ); + + private slots: + void updateData(); + void editingFinished(); + void editTimerFired(); + + private: + void updateWidgets(); + void updateWidgetsFromData(); + + // utility + void calculateSummary(); + + QWeakPointer< QWidget > m_input; + QWeakPointer< QWidget > m_match; + QString m_matchData; + QString m_matchString; + QString m_summary; + + QTimer m_editingTimer; + QTimer m_delayedEditTimer; + + // SQL control + QString m_sql; + QString m_sqlSummary; + }; + +}; + +#endif diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp new file mode 100644 index 000000000..29f4ca92b --- /dev/null +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp @@ -0,0 +1,160 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#include "DatabaseGenerator.h" + +#include "DatabaseControl.h" +#include "utils/logger.h" +#include +#include + +using namespace Tomahawk; + +GeneratorInterface* +DatabaseFactory::create() +{ + return new DatabaseGenerator(); +} + +dyncontrol_ptr +DatabaseFactory::createControl ( const QString& controlType ) +{ + return dyncontrol_ptr( new DatabaseControl( controlType, typeSelectors() ) ); +} + +dyncontrol_ptr +DatabaseFactory::createControl ( const QString& sql, const QString& summary ) +{ + return dyncontrol_ptr( new DatabaseControl( sql, summary, typeSelectors() ) ); +} + + +QStringList +DatabaseFactory::typeSelectors() const +{ + return QStringList() << "SQL" << "Artist" << "Album" << "Title"; +} + + +DatabaseGenerator::DatabaseGenerator ( QObject* parent ) + : GeneratorInterface ( parent ) +{ +// m_logo.load( RESPATH "images ) +} + +DatabaseGenerator::~DatabaseGenerator() +{ + +} + +QPixmap +DatabaseGenerator::logo() +{ + return m_logo; +} + + +void +DatabaseGenerator::dynamicFetched() +{ + +} + +void +DatabaseGenerator::dynamicStarted() +{ + +} + +void +DatabaseGenerator::generate( int number ) +{ + tLog() << "Generating" << number << "tracks for this database dynamic playlist with" << m_controls.size() << "controls:"; + foreach ( const dyncontrol_ptr& ctrl, m_controls ) + qDebug() << ctrl->selectedType() << ctrl->match() << ctrl->input(); + + // TODO for now, we just support the special "SQL" control, not meant to be shown to the user. Just does a raw query. + bool isSql = false; + foreach ( const dyncontrol_ptr& ctrl, m_controls ) + { + if( ctrl->selectedType() == "SQL" ) + isSql = true; + else if( !isSql ) + { + qWarning() << "Cannot mix sql and non-sql controls!"; + emit error( "Failed to generate tracks", "Cannot mix sql and non-sql controls" ); + } + } + + // TODO for now we just support 1 sql query if we're a sql type + if ( isSql ) + { + dyncontrol_ptr control = m_controls.first(); + + DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( control.dynamicCast< DatabaseControl >()->sql(), this ); + connect( cmd, SIGNAL( tracks( QList ) ), this, SIGNAL( tracksGenerated( QList ) ) ); + Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) ); + + return; + } + + +} + +void +DatabaseGenerator::tracksGenerated ( const QList< query_ptr >& tracks ) +{ + emit generated( tracks ); +} + + +dyncontrol_ptr +DatabaseGenerator::createControl( const QString& type ) +{ + m_controls << dyncontrol_ptr( new DatabaseControl( type, GeneratorFactory::typeSelectors( m_type ) ) ); + return m_controls.last(); +} + +dyncontrol_ptr +DatabaseGenerator::createControl ( const QString& sql, const QString& summary ) +{ + m_controls << dyncontrol_ptr( new DatabaseControl( sql, summary, GeneratorFactory::typeSelectors( m_type ) ) ); + return m_controls.last(); +} + + +void +DatabaseGenerator::fetchNext( int rating ) +{ +} + +QString +DatabaseGenerator::sentenceSummary() +{ + if( m_controls.count() && m_controls.first()->type() == "SQL" ) + return m_controls.first()->summary(); + + // TODO + return QString(); +} + +void +DatabaseGenerator::startOnDemand() +{ + +} diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h new file mode 100644 index 000000000..81627de88 --- /dev/null +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h @@ -0,0 +1,80 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#ifndef DATABASE_GENERATOR_H +#define DATABASE_GENERATOR_H + +#include + +#include "playlist/dynamic/GeneratorInterface.h" +#include "playlist/dynamic/GeneratorFactory.h" +#include "playlist/dynamic/DynamicControl.h" + +#include "dllmacro.h" + +namespace Tomahawk +{ + + class DLLEXPORT DatabaseFactory : public GeneratorFactoryInterface + { + public: + DatabaseFactory() {} + + virtual GeneratorInterface* create(); + virtual dyncontrol_ptr createControl( const QString& controlType = QString() ); + + // TO create a special SQL resolver that consists of a pre-baked SQL query and a description of it + virtual dyncontrol_ptr createControl( const QString& sql, const QString& summary ); + + virtual QStringList typeSelectors() const; + }; + + /** + * Generator based on the database. Can filter the database based on some user-controllable options, + * or just be the front-facing part of any given SQL query to fake an interesting read-only playlist. + */ + class DatabaseGenerator : public GeneratorInterface + { + Q_OBJECT + public: + explicit DatabaseGenerator( QObject* parent = 0 ); + virtual ~DatabaseGenerator(); + + virtual dyncontrol_ptr createControl( const QString& type = QString() ); + virtual dyncontrol_ptr createControl( const QString& sql, const QString& summary ); + + virtual QPixmap logo(); + virtual void generate ( int number = -1 ); + virtual void startOnDemand(); + virtual void fetchNext( int rating = -1 ); + virtual QString sentenceSummary(); + virtual bool onDemandSteerable() const { return false; } + virtual QWidget* steeringWidget() { return 0; } + + private slots: + void tracksGenerated( const QList< Tomahawk::query_ptr >& tracks ); + void dynamicStarted(); + void dynamicFetched(); + + private: + QPixmap m_logo; + }; + +}; + +#endif From 72bfeba65ac14e75631c269cb29f30248347e893 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Mon, 25 Jul 2011 18:08:19 -0400 Subject: [PATCH 02/17] add to cmakelists --- src/libtomahawk/CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index aeafd7c39..2cdbf7731 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -83,6 +83,7 @@ set( libSources database/databasecommand_clientauthvalid.cpp database/databasecommand_socialaction.cpp database/databasecommand_loadsocialactions.cpp + database/databasecommand_genericselect.cpp database/database.cpp infosystem/infosystemcache.cpp @@ -144,6 +145,8 @@ set( libSources playlist/dynamic/widgets/CollapsibleControls.cpp playlist/dynamic/widgets/DynamicSetupWidget.cpp playlist/dynamic/widgets/LoadingSpinner.cpp + playlist/dynamic/database/DatabaseControl.cpp + playlist/dynamic/database/DatabaseGenerator.cpp network/bufferiodevice.cpp network/msgprocessor.cpp @@ -256,6 +259,7 @@ set( libHeaders database/databasecommand_clientauthvalid.h database/databasecommand_socialaction.h database/databasecommand_loadsocialactions.h + database/databasecommand_genericselect.h infosystem/infosystem.h infosystem/infosystemworker.h @@ -326,6 +330,8 @@ set( libHeaders playlist/dynamic/widgets/CollapsibleControls.h playlist/dynamic/widgets/DynamicSetupWidget.h playlist/dynamic/widgets/LoadingSpinner.h + playlist/dynamic/database/DatabaseControl.h + playlist/dynamic/database/DatabaseGenerator.h utils/querylabel.h utils/elidedlabel.h @@ -419,12 +425,12 @@ IF( APPLE ) FIND_LIBRARY( SCRIPTINGBRIDGE_LIBRARY ScriptingBridge ) MARK_AS_ADVANCED( COREAUDIO_LIBRARY COREFOUNDATION_LIBRARY FOUNDATION_LIBRARY SCRIPTINGBRIDGE_LIBRARY ) - SET( libSources ${libSources} + SET( libSources ${libSources} infosystem/infoplugins/mac/adium.mm infosystem/infoplugins/mac/adiumplugin.cpp utils/tomahawkutils_mac.mm ) - SET( libHeaders ${libHeaders} + SET( libHeaders ${libHeaders} infosystem/infoplugins/mac/adium.h infosystem/infoplugins/mac/adiumplugin.h ) From ca467fb5bc56bd960af7939558978db3d0aab73c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 29 Jul 2011 14:06:44 -0400 Subject: [PATCH 03/17] Add support for non-autoloaded dynamic playlists that can be used for custom displays Add a SocialPlaylistWidget that will display some cool social stats and lists, but none right now --- data/sql/dbmigrate-24_to_25.sql | 1 - resources.qrc | 1 + src/libtomahawk/CMakeLists.txt | 5 + .../databasecommand_createdynamicplaylist.cpp | 17 ++- .../databasecommand_createdynamicplaylist.h | 30 +++-- .../databasecommand_createplaylist.cpp | 5 +- .../database/databasecommand_createplaylist.h | 11 +- .../databasecommand_genericselect.cpp | 45 +------ .../database/databasecommand_genericselect.h | 2 +- .../databasecommand_loadallautoplaylists.cpp | 4 +- .../databasecommand_loadallautoplaylists.h | 2 +- .../databasecommand_loadallstations.cpp | 4 +- .../databasecommand_loadallstations.h | 2 +- .../databasecommand_loaddynamicplaylist.cpp | 123 ++++++------------ .../databasecommand_loaddynamicplaylist.h | 42 ++---- ...basecommand_loaddynamicplaylistentries.cpp | 120 +++++++++++++++++ ...tabasecommand_loaddynamicplaylistentries.h | 66 ++++++++++ ...basecommand_setdynamicplaylistrevision.cpp | 15 +-- ...tabasecommand_setdynamicplaylistrevision.h | 24 ++-- src/libtomahawk/database/databaseimpl.cpp | 38 +++--- src/libtomahawk/database/schema.sql | 5 +- src/libtomahawk/database/schema.sql.h | 7 +- .../playlist/dynamic/DynamicControl.h | 38 +++--- .../playlist/dynamic/DynamicPlaylist.cpp | 4 +- .../playlist/dynamic/DynamicPlaylist.h | 3 + .../dynamic/widgets/CollapsibleControls.h | 19 +-- src/libtomahawk/playlist/trackview.h | 1 + .../widgets/SocialPlaylistWidget.cpp | 94 +++++++++++++ .../widgets/SocialPlaylistWidget.h | 96 ++++++++++++++ .../widgets/SocialPlaylistWidget.ui | 46 +++++++ src/sourcetree/items/collectionitem.cpp | 29 +++++ src/sourcetree/items/collectionitem.h | 6 + 32 files changed, 648 insertions(+), 257 deletions(-) create mode 100644 src/libtomahawk/database/databasecommand_loaddynamicplaylistentries.cpp create mode 100644 src/libtomahawk/database/databasecommand_loaddynamicplaylistentries.h create mode 100644 src/libtomahawk/widgets/SocialPlaylistWidget.cpp create mode 100644 src/libtomahawk/widgets/SocialPlaylistWidget.h create mode 100644 src/libtomahawk/widgets/SocialPlaylistWidget.ui diff --git a/data/sql/dbmigrate-24_to_25.sql b/data/sql/dbmigrate-24_to_25.sql index 181df2705..2afabdbc0 100644 --- a/data/sql/dbmigrate-24_to_25.sql +++ b/data/sql/dbmigrate-24_to_25.sql @@ -1,7 +1,6 @@ -- Script to migate from db version 24 to 25. -- Added the social_attributes table. -- --- Separate each command with %% ALTER TABLE dynamic_playlist RENAME TO tmp_dynamic_playlist; diff --git a/resources.qrc b/resources.qrc index 763a4d08e..50f1b79d7 100644 --- a/resources.qrc +++ b/resources.qrc @@ -97,6 +97,7 @@ ./data/sql/dbmigrate-22_to_23.sql ./data/sql/dbmigrate-23_to_24.sql ./data/sql/dbmigrate-24_to_25.sql + ./data/sql/dbmigrate-25_to_26.sql ./data/js/tomahawk.js diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 2cdbf7731..0f874d26b 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -76,6 +76,7 @@ set( libSources database/databasecommand_setdynamicplaylistrevision.cpp database/databasecommand_createdynamicplaylist.cpp database/databasecommand_loaddynamicplaylist.cpp + database/databasecommand_loaddynamicplaylistentries.cpp database/databasecommand_loadallautoplaylists.cpp database/databasecommand_loadallstations.cpp database/databasecommand_deletedynamicplaylist.cpp @@ -177,6 +178,7 @@ set( libSources widgets/welcomeplaylistmodel.cpp widgets/overlaywidget.cpp widgets/HeaderLabel.cpp + widgets/SocialPlaylistWidget.cpp widgets/infowidgets/sourceinfowidget.cpp widgets/infowidgets/ArtistInfoWidget.cpp @@ -252,6 +254,7 @@ set( libHeaders database/databasecommand_setdynamicplaylistrevision.h database/databasecommand_createdynamicplaylist.h database/databasecommand_loaddynamicplaylist.h + database/databasecommand_loaddynamicplaylistentries.h database/databasecommand_deletedynamicplaylist.h database/databasecommand_loadallautoplaylists.h database/databasecommand_loadallstations.h @@ -350,6 +353,7 @@ set( libHeaders widgets/welcomeplaylistmodel.h widgets/overlaywidget.h widgets/HeaderLabel.h + widgets/SocialPlaylistWidget.h widgets/infowidgets/sourceinfowidget.h widgets/infowidgets/ArtistInfoWidget.h @@ -372,6 +376,7 @@ set( libUI ${libUI} widgets/newplaylistwidget.ui widgets/searchwidget.ui widgets/welcomewidget.ui + widgets/SocialPlaylistWidget.ui widgets/infowidgets/sourceinfowidget.ui widgets/infowidgets/ArtistInfoWidget.ui playlist/topbar/topbar.ui diff --git a/src/libtomahawk/database/databasecommand_createdynamicplaylist.cpp b/src/libtomahawk/database/databasecommand_createdynamicplaylist.cpp index 12b459c0a..ebf79af55 100644 --- a/src/libtomahawk/database/databasecommand_createdynamicplaylist.cpp +++ b/src/libtomahawk/database/databasecommand_createdynamicplaylist.cpp @@ -33,18 +33,20 @@ using namespace Tomahawk; DatabaseCommand_CreateDynamicPlaylist::DatabaseCommand_CreateDynamicPlaylist( QObject* parent ) -: DatabaseCommand_CreatePlaylist( parent ) + : DatabaseCommand_CreatePlaylist( parent ) + , m_autoLoad( true ) { - qDebug() << Q_FUNC_INFO << "creating dynamiccreatecommand 1"; + tDebug() << Q_FUNC_INFO << "creating dynamiccreatecommand 1"; } DatabaseCommand_CreateDynamicPlaylist::DatabaseCommand_CreateDynamicPlaylist( const source_ptr& author, - const dynplaylist_ptr& playlist ) + const dynplaylist_ptr& playlist, bool autoLoad ) : DatabaseCommand_CreatePlaylist( author, playlist.staticCast() ) , m_playlist( playlist ) + , m_autoLoad( autoLoad ) { - qDebug() << Q_FUNC_INFO << "creating dynamiccreatecommand 2"; + tDebug() << Q_FUNC_INFO << "creating dynamiccreatecommand 2"; } @@ -61,8 +63,8 @@ DatabaseCommand_CreateDynamicPlaylist::exec( DatabaseImpl* lib ) qDebug() << "Create dynamic execing!" << m_playlist << m_v; TomahawkSqlQuery cre = lib->newquery(); - cre.prepare( "INSERT INTO dynamic_playlist( guid, pltype, plmode ) " - "VALUES( ?, ?, ? )" ); + cre.prepare( "INSERT INTO dynamic_playlist( guid, pltype, plmode, autoload ) " + "VALUES( ?, ?, ?, ? )" ); if( m_playlist.isNull() ) { QVariantMap m = m_v.toMap(); @@ -74,6 +76,7 @@ DatabaseCommand_CreateDynamicPlaylist::exec( DatabaseImpl* lib ) cre.addBindValue( m_playlist->type() ); cre.addBindValue( m_playlist->mode() ); } + cre.addBindValue( m_autoLoad ); cre.exec(); } @@ -88,7 +91,7 @@ DatabaseCommand_CreateDynamicPlaylist::postCommitHook() return; } - if( report() == false ) + if( !DatabaseCommand_CreatePlaylist::report() || report() == false ) return; qDebug() << Q_FUNC_INFO << "..reporting.."; diff --git a/src/libtomahawk/database/databasecommand_createdynamicplaylist.h b/src/libtomahawk/database/databasecommand_createdynamicplaylist.h index 2c2183b61..f0ad2369d 100644 --- a/src/libtomahawk/database/databasecommand_createdynamicplaylist.h +++ b/src/libtomahawk/database/databasecommand_createdynamicplaylist.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -24,21 +24,31 @@ #include "dynamic/DynamicPlaylist.h" #include "typedefs.h" +/** + * Create a new dynamic playlist in the database, based on an existing playlist. + * + * If autoLoad is true, this playlist will *not* show up in the sidebar under the playlist tree, and + * it will *not* be replicated to peers. It is useful to show a "specially crafted" playlist in other places + */ + 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 ); - + explicit DatabaseCommand_CreateDynamicPlaylist( const Tomahawk::source_ptr& author, const Tomahawk::dynplaylist_ptr& playlist, bool autoLoad = true ); + QString commandname() const { return "createdynamicplaylist"; } - + virtual void exec( DatabaseImpl* lib ); virtual void postCommitHook(); virtual bool doesMutates() const { return true; } - + + virtual bool loggable() const { return m_autoLoad; } + + QVariant playlistV() const { if( m_v.isNull() ) @@ -46,14 +56,18 @@ public: else return m_v; } - + void setPlaylistV( const QVariant& v ) { m_v = v; } - + +protected: + virtual bool report() { return m_autoLoad; } + private: Tomahawk::dynplaylist_ptr m_playlist; + bool m_autoLoad; }; #endif // DATABASECOMMAND_CREATEDYNAMICPLAYLIST_H diff --git a/src/libtomahawk/database/databasecommand_createplaylist.cpp b/src/libtomahawk/database/databasecommand_createplaylist.cpp index 516197ab7..b451394be 100644 --- a/src/libtomahawk/database/databasecommand_createplaylist.cpp +++ b/src/libtomahawk/database/databasecommand_createplaylist.cpp @@ -59,7 +59,7 @@ DatabaseCommand_CreatePlaylist::postCommitHook() if ( m_report == false ) return; - qDebug() << Q_FUNC_INFO << "reporting..."; + tDebug() << Q_FUNC_INFO << "reporting..."; if ( m_playlist.isNull() ) { source_ptr src = source(); @@ -82,7 +82,6 @@ DatabaseCommand_CreatePlaylist::postCommitHook() void DatabaseCommand_CreatePlaylist::createPlaylist( DatabaseImpl* lib, bool dynamic) { - qDebug() << Q_FUNC_INFO; Q_ASSERT( !( m_playlist.isNull() && m_v.isNull() ) ); Q_ASSERT( !source().isNull() ); @@ -123,7 +122,7 @@ DatabaseCommand_CreatePlaylist::createPlaylist( DatabaseImpl* lib, bool dynamic) cre.bindValue( ":creator", m.value( "creator" ) ); cre.bindValue( ":lastmodified", m.value( "lastmodified", 0 ) ); } - qDebug() << "CREATE PLAYLIST:" << cre.boundValues(); + tDebug() << "CREATE PLAYLIST:" << cre.boundValues(); cre.exec(); } diff --git a/src/libtomahawk/database/databasecommand_createplaylist.h b/src/libtomahawk/database/databasecommand_createplaylist.h index ec3aa14a3..a6fe0c437 100644 --- a/src/libtomahawk/database/databasecommand_createplaylist.h +++ b/src/libtomahawk/database/databasecommand_createplaylist.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -53,13 +53,14 @@ public: { m_v = v; } - + protected: void createPlaylist( DatabaseImpl* lib, bool dynamic = false ); - - bool report() { return m_report; } + + virtual bool report() { return m_report; } + void setPlaylist( const Tomahawk::playlist_ptr& playlist ) { m_playlist = playlist; } - + QVariant m_v; private: Tomahawk::playlist_ptr m_playlist; diff --git a/src/libtomahawk/database/databasecommand_genericselect.cpp b/src/libtomahawk/database/databasecommand_genericselect.cpp index 905b5e039..63c439b9c 100644 --- a/src/libtomahawk/database/databasecommand_genericselect.cpp +++ b/src/libtomahawk/database/databasecommand_genericselect.cpp @@ -52,48 +52,11 @@ DatabaseCommand_GenericSelect::exec( DatabaseImpl* dbi ) Tomahawk::source_ptr s; QString artist, track, album; - artist = query.value( 0 ).toString(); - album = query.value( 1 ).toString(); - track = query.value( 2 ).toString(); - - Tomahawk::query_ptr qry = Tomahawk::Query::get( artist, track, album, uuid(), (query.value( 7 ).toUInt() != 0) ); // Only auto-resolve non-local results - Tomahawk::artist_ptr artistptr = Tomahawk::Artist::get( query.value( 12 ).toUInt(), artist ); - Tomahawk::album_ptr albumptr = Tomahawk::Album::get( query.value( 13 ).toUInt(), album, artistptr ); - - // If it's a local track, set to the local source and url in the result and we're done. otherwise, we get resolved - if( query.value( 7 ).toUInt() == 0 ) - { - s = SourceList::instance()->getLocal(); - result->setUrl( query.value( 7 ).toString() ); - - result->setId( query.value( 9 ).toUInt() ); - result->setArtist( artistptr ); - result->setAlbum( albumptr ); - result->setTrack( query.value( 2 ).toString() ); - result->setSize( query.value( 3 ).toUInt() ); - result->setDuration( query.value( 4 ).toUInt() ); - result->setBitrate( query.value( 5 ).toUInt() ); - result->setMimetype( query.value( 8 ).toString() ); - result->setScore( 1.0 ); - result->setCollection( s->collection() ); - - TomahawkSqlQuery attrQuery = dbi->newquery(); - QVariantMap attr; - - attrQuery.prepare( "SELECT k, v FROM track_attributes WHERE id = ?" ); - attrQuery.bindValue( 0, result->dbid() ); - attrQuery.exec(); - while ( attrQuery.next() ) - { - attr[ attrQuery.value( 0 ).toString() ] = attrQuery.value( 1 ).toString(); - } - - result->setAttributes( attr ); - - qry->addResults( QList() << result ); - qry->setResolveFinished( true ); - } + track = query.value( 0 ).toString(); + artist = query.value( 1 ).toString(); + album = query.value( 2 ).toString(); + Tomahawk::query_ptr qry = Tomahawk::Query::get( artist, track, album, uuid(), true ); // Only auto-resolve non-local results queries << qry; } diff --git a/src/libtomahawk/database/databasecommand_genericselect.h b/src/libtomahawk/database/databasecommand_genericselect.h index e054f9faa..931f452e9 100644 --- a/src/libtomahawk/database/databasecommand_genericselect.h +++ b/src/libtomahawk/database/databasecommand_genericselect.h @@ -32,7 +32,7 @@ * that match. * * In order for the conversion to query_ptr to work, the SELECT command should select the following items: - * artist.name, album.name, track.name, file.size, file.duration, file.bitrate, file.url, file.source, file.mimetype, track.id + * track.name, artist.name, album.name * */ class DLLEXPORT DatabaseCommand_GenericSelect : public DatabaseCommand diff --git a/src/libtomahawk/database/databasecommand_loadallautoplaylists.cpp b/src/libtomahawk/database/databasecommand_loadallautoplaylists.cpp index 378dd0d9d..4abbb4d94 100644 --- a/src/libtomahawk/database/databasecommand_loadallautoplaylists.cpp +++ b/src/libtomahawk/database/databasecommand_loadallautoplaylists.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ DatabaseCommand_LoadAllAutoPlaylists::exec( DatabaseImpl* dbi ) TomahawkSqlQuery query = dbi->newquery(); query.exec( QString( "SELECT playlist.guid as guid, title, info, creator, createdOn, lastmodified, shared, currentrevision, dynamic_playlist.pltype, dynamic_playlist.plmode " - "FROM playlist, dynamic_playlist WHERE source %1 AND dynplaylist = 'true' AND playlist.guid = dynamic_playlist.guid AND dynamic_playlist.plmode = %2" ) + "FROM playlist, dynamic_playlist WHERE source %1 AND dynplaylist = 'true' AND playlist.guid = dynamic_playlist.guid AND dynamic_playlist.plmode = %2 AND dynamic_playlist.autoload = 'true'" ) .arg( source()->isLocal() ? "IS NULL" : QString( "=%1" ).arg( source()->id() ) ) .arg( Static ) ); diff --git a/src/libtomahawk/database/databasecommand_loadallautoplaylists.h b/src/libtomahawk/database/databasecommand_loadallautoplaylists.h index 6352ff360..0bf9cd5be 100644 --- a/src/libtomahawk/database/databasecommand_loadallautoplaylists.h +++ b/src/libtomahawk/database/databasecommand_loadallautoplaylists.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/database/databasecommand_loadallstations.cpp b/src/libtomahawk/database/databasecommand_loadallstations.cpp index bd5b6e488..90edeeb16 100644 --- a/src/libtomahawk/database/databasecommand_loadallstations.cpp +++ b/src/libtomahawk/database/databasecommand_loadallstations.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ DatabaseCommand_LoadAllStations::exec( DatabaseImpl* dbi ) TomahawkSqlQuery query = dbi->newquery(); query.exec( QString( "SELECT playlist.guid as guid, title, info, creator, createdOn, lastmodified, shared, currentrevision, dynamic_playlist.pltype, dynamic_playlist.plmode " - "FROM playlist, dynamic_playlist WHERE source %1 AND dynplaylist = 'true' AND playlist.guid = dynamic_playlist.guid AND dynamic_playlist.plmode = %2" ) + "FROM playlist, dynamic_playlist WHERE source %1 AND dynplaylist = 'true' AND playlist.guid = dynamic_playlist.guid AND dynamic_playlist.plmode = %2 AND dynamic_playlist.autoload = 'true'" ) .arg( source()->isLocal() ? "IS NULL" : QString( "=%1" ).arg( source()->id() ) ) .arg( OnDemand ) ); diff --git a/src/libtomahawk/database/databasecommand_loadallstations.h b/src/libtomahawk/database/databasecommand_loadallstations.h index 4cb29dc2a..1e838d9c7 100644 --- a/src/libtomahawk/database/databasecommand_loadallstations.h +++ b/src/libtomahawk/database/databasecommand_loadallstations.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/database/databasecommand_loaddynamicplaylist.cpp b/src/libtomahawk/database/databasecommand_loaddynamicplaylist.cpp index 9039db1a9..729408cbd 100644 --- a/src/libtomahawk/database/databasecommand_loaddynamicplaylist.cpp +++ b/src/libtomahawk/database/databasecommand_loaddynamicplaylist.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,102 +19,59 @@ #include "databasecommand_loaddynamicplaylist.h" #include -#include +#include "dynamic/DynamicPlaylist.h" #include "databaseimpl.h" -#include "tomahawksqlquery.h" -#include "dynamic/DynamicControl.h" -#include "dynamic/GeneratorInterface.h" -#include #include "utils/logger.h" using namespace Tomahawk; +Tomahawk::DatabaseCommand_LoadDynamicPlaylist::DatabaseCommand_LoadDynamicPlaylist( const source_ptr& s, const QString& guid, QObject* parent ) + : DatabaseCommand( s, parent ) + , m_plid( guid ) +{ + +} + void -DatabaseCommand_LoadDynamicPlaylist::exec( DatabaseImpl* dbi ) +Tomahawk::DatabaseCommand_LoadDynamicPlaylist::exec( DatabaseImpl* dbi ) { -// qDebug() << "Loading dynamic playlist guid" << guid(); - // load the entries first - generateEntries( dbi ); + TomahawkSqlQuery query = dbi->newquery(); - // now load the controls etc + query.exec( QString( "SELECT playlist.guid as guid, title, info, creator, createdOn, lastmodified, shared, currentrevision, dynamic_playlist.pltype, dynamic_playlist.plmode " + "FROM playlist, dynamic_playlist WHERE source %1 AND dynplaylist = 'true' AND playlist.guid = dynamic_playlist.guid AND playlist.guid = '%2'" ) + .arg( source()->isLocal() ? "IS NULL" : QString( "=%1" ).arg( source()->id() ) ).arg( m_plid ) ); - 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(); - - QString type; - GeneratorMode mode; - - QList< QVariantMap > controls; - QString playlist_guid; -// qDebug() << "Loading controls..." << revisionGuid(); -// qDebug() << "SELECT playlist_revision.playlist, controls, plmode, pltype " -// "FROM dynamic_playlist_revision, playlist_revision " -// "WHERE dynamic_playlist_revision.guid = "<< revisionGuid() << " AND playlist_revision.guid = dynamic_playlist_revision.guid"; - - if( controlsQuery.first() ) + QList plists; + if( query.next() ) { - playlist_guid = controlsQuery.value( 0 ).toString(); - QJson::Parser parser; - bool ok; - QVariant v = parser.parse( controlsQuery.value(1).toByteArray(), &ok ); - Q_ASSERT( ok && v.type() == QVariant::List ); //TODO + dynplaylist_ptr p( new DynamicPlaylist( source(), + query.value(7).toString(), //current rev + query.value(1).toString(), //title + query.value(2).toString(), //info + query.value(3).toString(), //creator + query.value(4).toUInt(), //createdOn + query.value(8).toString(), // dynamic type + static_cast(query.value(9).toInt()), // dynamic mode + query.value(6).toBool(), //shared + query.value(5).toInt(), //lastmod + query.value(0).toString() ) ); //GUID + tLog() << "Loaded individual dynamic playlist:" << query.value(7).toString() //current rev + << query.value(1).toString() //title + << query.value(2).toString() //info + << query.value(3).toString() //creator + << query.value(4).toString() //createdOn + << query.value(8).toString() // dynamic type + << static_cast(query.value(9).toInt()) // dynamic mode + << query.value(6).toBool() //shared + << query.value(5).toInt() //lastmod + << query.value(0).toString(); //GUID - type = controlsQuery.value( 3 ).toString(); - mode = static_cast( controlsQuery.value( 2 ).toInt() ); - - QStringList controlIds = v.toStringList(); -// qDebug() << "Got controls in dynamic playlist, loading:" << controlIds << controlsQuery.value(1); - 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() ) - { - QVariantMap c; - c[ "type" ] = type; - c[ "id" ] = controlId; - c[ "selectedType" ] = controlQuery.value( 0 ).toString(); - c[ "match" ] = controlQuery.value( 1 ).toString(); - c[ "input" ] = controlQuery.value( 2 ).toString(); - controls << c; - } - } - } - else - { - // No controls, lets load the info we need directly from the playlist table - 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; - } - type = info.value( 0 ).toString(); - mode = static_cast( info.value( 1 ).toInt() ); + emit dynamicPlaylistLoaded( p ); } - 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 ); - } + emit done(); } + diff --git a/src/libtomahawk/database/databasecommand_loaddynamicplaylist.h b/src/libtomahawk/database/databasecommand_loaddynamicplaylist.h index 08c831b6f..a21bb8140 100644 --- a/src/libtomahawk/database/databasecommand_loaddynamicplaylist.h +++ b/src/libtomahawk/database/databasecommand_loaddynamicplaylist.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,45 +22,31 @@ #include #include -#include "typedefs.h" #include "databasecommand.h" -#include "databasecommand_loadplaylistentries.h" -#include "playlist.h" -#include "dynamic/DynamicControl.h" +#include "typedefs.h" -class DatabaseCommand_LoadDynamicPlaylist : public DatabaseCommand_LoadPlaylistEntries +namespace Tomahawk +{ + +class DatabaseCommand_LoadDynamicPlaylist : public DatabaseCommand { Q_OBJECT public: - explicit DatabaseCommand_LoadDynamicPlaylist( QString revision_guid, QObject* parent = 0 ) - : DatabaseCommand_LoadPlaylistEntries( revision_guid, parent ) - { -// qDebug() << "loaded with:" << revision_guid << guid(); - } + explicit DatabaseCommand_LoadDynamicPlaylist( const source_ptr& s, const QString& guid, QObject* parent = 0 ); virtual void exec( DatabaseImpl* ); virtual bool doesMutates() const { return false; } - virtual QString commandname() const { return "loaddynamicplaylist"; } + virtual QString commandname() const { return "loadsingledynamicplaylist"; } signals: - // used if loading an ondemand playlist - void done( QString, - bool, - QString, - QList< QVariantMap>, - bool ); - // used when loading a static playlist - void done( QString, - QList< QString >, - QList< QString >, - QString, - QList< QVariantMap>, - bool, - QMap< QString, Tomahawk::plentry_ptr >, - bool ); + void dynamicPlaylistLoaded( const Tomahawk::dynplaylist_ptr& pl ); + void done(); private: + QString m_plid; }; -#endif // DATABASECOMMAND_LOADDYNAMICPLAYLIST_H +} + +#endif diff --git a/src/libtomahawk/database/databasecommand_loaddynamicplaylistentries.cpp b/src/libtomahawk/database/databasecommand_loaddynamicplaylistentries.cpp new file mode 100644 index 000000000..d76399e9a --- /dev/null +++ b/src/libtomahawk/database/databasecommand_loaddynamicplaylistentries.cpp @@ -0,0 +1,120 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#include "databasecommand_loaddynamicplaylistentries.h" + +#include +#include + +#include "databaseimpl.h" +#include "tomahawksqlquery.h" +#include "dynamic/DynamicControl.h" +#include "dynamic/GeneratorInterface.h" +#include +#include "utils/logger.h" + +using namespace Tomahawk; + + +void +DatabaseCommand_LoadDynamicPlaylistEntries::exec( DatabaseImpl* dbi ) +{ +// qDebug() << "Loading dynamic playlist guid" << 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(); + + QString type; + GeneratorMode mode; + + QList< QVariantMap > controls; + QString playlist_guid; +// qDebug() << "Loading controls..." << revisionGuid(); +// qDebug() << "SELECT playlist_revision.playlist, controls, plmode, pltype " +// "FROM dynamic_playlist_revision, playlist_revision " +// "WHERE dynamic_playlist_revision.guid = "<< revisionGuid() << " AND playlist_revision.guid = dynamic_playlist_revision.guid"; + + if( controlsQuery.first() ) + { + playlist_guid = controlsQuery.value( 0 ).toString(); + QJson::Parser parser; + bool ok; + QVariant v = parser.parse( controlsQuery.value(1).toByteArray(), &ok ); + Q_ASSERT( ok && v.type() == QVariant::List ); //TODO + + + type = controlsQuery.value( 3 ).toString(); + mode = static_cast( controlsQuery.value( 2 ).toInt() ); + + QStringList controlIds = v.toStringList(); +// qDebug() << "Got controls in dynamic playlist, loading:" << controlIds << controlsQuery.value(1); + 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() ) + { + QVariantMap c; + c[ "type" ] = type; + c[ "id" ] = controlId; + c[ "selectedType" ] = controlQuery.value( 0 ).toString(); + c[ "match" ] = controlQuery.value( 1 ).toString(); + c[ "input" ] = controlQuery.value( 2 ).toString(); + controls << c; + } + } + } + else + { + // No controls, lets load the info we need directly from the playlist table + 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; + } + type = info.value( 0 ).toString(); + mode = static_cast( 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 ); + } +} diff --git a/src/libtomahawk/database/databasecommand_loaddynamicplaylistentries.h b/src/libtomahawk/database/databasecommand_loaddynamicplaylistentries.h new file mode 100644 index 000000000..ab6571c8b --- /dev/null +++ b/src/libtomahawk/database/databasecommand_loaddynamicplaylistentries.h @@ -0,0 +1,66 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#ifndef DATABASECOMMAND_LOADDYNAMICPLAYLISTENTRIES_H +#define DATABASECOMMAND_LOADDYNAMICPLAYLISTENTRIES_H + +#include +#include + +#include "typedefs.h" +#include "databasecommand.h" +#include "databasecommand_loadplaylistentries.h" +#include "playlist.h" +#include "dynamic/DynamicControl.h" + +class DatabaseCommand_LoadDynamicPlaylistEntries : public DatabaseCommand_LoadPlaylistEntries +{ + Q_OBJECT + +public: + explicit DatabaseCommand_LoadDynamicPlaylistEntries( 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< QVariantMap>, + bool ); + // used when loading a static playlist + void done( QString, + QList< QString >, + QList< QString >, + QString, + QList< QVariantMap>, + bool, + QMap< QString, Tomahawk::plentry_ptr >, + bool ); + +private: +}; + +#endif // DATABASECOMMAND_LOADDYNAMICPLAYLIST_H diff --git a/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.cpp b/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.cpp index f18011933..6a7aa6b1b 100644 --- a/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.cpp +++ b/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -82,10 +82,9 @@ DatabaseCommand_SetDynamicPlaylistRevision::controlsV() void DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook() { - qDebug() << Q_FUNC_INFO; if ( source().isNull() || source()->collection().isNull() ) { - qDebug() << "Source has gone offline, not emitting to GUI."; + tDebug() << "Source has gone offline, not emitting to GUI."; return; } @@ -95,7 +94,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook() Q_ASSERT( !source().isNull() ); Q_ASSERT( !source()->collection().isNull() ); - qDebug() << "Postcommitting this playlist:" << playlistguid() << source().isNull() << source().data(); + tLog() << "Postcommitting this playlist:" << playlistguid() << source().isNull(); // private, but we are a friend. will recall itself in its own thread: dynplaylist_ptr playlist = source()->collection()->autoPlaylist( playlistguid() ); @@ -106,7 +105,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook() // now that we separate them, if we get them as one and then get a changed mode, the playlist ends up in the wrong bucket in Collection. // so here we fix it if we have to. // HACK - qDebug() << "Does this need FIXING?" << playlist->mode() << source()->collection()->autoPlaylist( playlistguid() ).isNull() << source()->collection()->station( playlistguid() ).isNull(); + tDebug() << "Does this need FIXING?" << playlist->mode() << source()->collection()->autoPlaylist( playlistguid() ).isNull() << source()->collection()->station( playlistguid() ).isNull(); if( playlist->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() ) // should be here source()->collection()->moveStationToAuto( playlistguid() ); else if ( playlist->mode() == OnDemand && source()->collection()->station( playlistguid() ).isNull() ) // should be here @@ -114,7 +113,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook() if ( playlist.isNull() ) { - qDebug() <<"Got null playlist with guid:" << playlistguid() << "from source and collection:" << source()->friendlyName() << source()->collection()->name() << "and mode is static?:" << (m_mode == Static); + tLog() <<"Got null playlist with guid:" << playlistguid() << "from source and collection:" << source()->friendlyName() << source()->collection()->name() << "and mode is static?:" << (m_mode == Static); Q_ASSERT( !playlist.isNull() ); return; } @@ -205,7 +204,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::exec( DatabaseImpl* lib ) delQuery.prepare( "DELETE FROM dynamic_playlist_controls WHERE playlist = ?" ); delQuery.addBindValue( m_playlistguid ); if ( !delQuery.exec() ) - qWarning() << "Failed to delete controls from dynamic playlist controls table"; + tLog() << "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 ) " @@ -242,7 +241,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::exec( DatabaseImpl* lib ) } if ( m_applied ) { - qDebug() << "updating dynamic playlist, optimistic locking okay"; + tLog() << "updating dynamic playlist, optimistic locking okay"; TomahawkSqlQuery query2 = lib->newquery(); query2.prepare( "UPDATE dynamic_playlist SET pltype = ?, plmode = ? WHERE guid = ?" ); diff --git a/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.h b/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.h index 238aa163f..f9f9c1a63 100644 --- a/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.h +++ b/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser + * + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,12 +34,12 @@ class DatabaseCommand_SetDynamicPlaylistRevision : public DatabaseCommand_SetPla 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, @@ -50,7 +50,7 @@ public: const QString& type, GeneratorMode mode, const QList< dyncontrol_ptr >& controls ); - + explicit DatabaseCommand_SetDynamicPlaylistRevision( const source_ptr& s, const QString& playlistguid, const QString& newrev, @@ -58,26 +58,26 @@ public: 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; } int mode() const { return (int)m_mode; } - + void setType( const QString& type ) { m_type = type; } void setMode( int mode ) { m_mode = (GeneratorMode)mode; } - + private: QString m_type; GeneratorMode m_mode; diff --git a/src/libtomahawk/database/databaseimpl.cpp b/src/libtomahawk/database/databaseimpl.cpp index 389838e3a..b8490ee2d 100644 --- a/src/libtomahawk/database/databaseimpl.cpp +++ b/src/libtomahawk/database/databaseimpl.cpp @@ -39,7 +39,7 @@ */ #include "schema.sql.h" -#define CURRENT_SCHEMA_VERSION 25 +#define CURRENT_SCHEMA_VERSION 26 DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) @@ -54,11 +54,11 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) if ( version > 0 && version != CURRENT_SCHEMA_VERSION ) { QString newname = QString( "%1.v%2" ).arg( dbname ).arg( version ); - qDebug() << endl << "****************************" << endl; - qDebug() << "Schema version too old: " << version << ". Current version is:" << CURRENT_SCHEMA_VERSION; - qDebug() << "Moving" << dbname << newname; - qDebug() << "If the migration fails, you can recover your DB by copying" << newname << "back to" << dbname; - qDebug() << endl << "****************************" << endl; + tLog() << endl << "****************************" << endl; + tLog() << "Schema version too old: " << version << ". Current version is:" << CURRENT_SCHEMA_VERSION; + tLog() << "Moving" << dbname << newname; + tLog() << "If the migration fails, you can recover your DB by copying" << newname << "back to" << dbname; + tLog() << endl << "****************************" << endl; QFile::copy( dbname, newname ); { @@ -84,7 +84,7 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) db.setDatabaseName( dbname ); if ( !db.open() ) { - qDebug() << "Failed to open database" << dbname; + tLog() << "Failed to open database" << dbname; throw "failed to open db"; // TODO } @@ -103,7 +103,7 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) m_dbid = uuid(); query.exec( QString( "INSERT INTO settings(k,v) VALUES('dbid','%1')" ).arg( m_dbid ) ); } - qDebug() << "Database ID:" << m_dbid; + tLog() << "Database ID:" << m_dbid; // make sqlite behave how we want: query.exec( "PRAGMA synchronous = ON" ); @@ -145,7 +145,7 @@ DatabaseImpl::updateSchema( int oldVersion ) // we are called here with the old database. we must migrate it to the CURRENT_SCHEMA_VERSION from the oldVersion if ( oldVersion == 0 ) // empty database, so create our tables and stuff { - qDebug() << "Create tables... old version is" << oldVersion; + tLog() << "Create tables... old version is" << oldVersion; QString sql( get_tomahawk_sql() ); QStringList statements = sql.split( ";", QString::SkipEmptyParts ); db.transaction(); @@ -156,7 +156,7 @@ DatabaseImpl::updateSchema( int oldVersion ) if ( s.length() == 0 ) continue; - qDebug() << "Executing:" << s; + tLog() << "Executing:" << s; TomahawkSqlQuery query = newquery(); query.exec( s ); } @@ -176,7 +176,7 @@ DatabaseImpl::updateSchema( int oldVersion ) QFile script( path ); if ( !script.exists() || !script.open( QIODevice::ReadOnly ) ) { - qWarning() << "Failed to find or open upgrade script from" << (cur-1) << "to" << cur << " (" << path << ")! Aborting upgrade..."; + tLog() << "Failed to find or open upgrade script from" << (cur-1) << "to" << cur << " (" << path << ")! Aborting upgrade..."; return false; } @@ -188,13 +188,13 @@ DatabaseImpl::updateSchema( int oldVersion ) if ( clean.isEmpty() ) continue; - qDebug() << "Executing upgrade statement:" << clean; + tLog() << "Executing upgrade statement:" << clean; TomahawkSqlQuery q = newquery(); q.exec( clean ); } } db.commit(); - qDebug() << "DB Upgrade successful!"; + tLog() << "DB Upgrade successful!"; return true; } } @@ -299,7 +299,7 @@ DatabaseImpl::artistId( const QString& name_orig, bool& autoCreate ) query.addBindValue( sortname ); if ( !query.exec() ) { - qDebug() << "Failed to insert artist:" << name_orig; + tDebug() << "Failed to insert artist:" << name_orig; return 0; } @@ -345,7 +345,7 @@ DatabaseImpl::trackId( int artistid, const QString& name_orig, bool& isnew ) query.addBindValue( sortname ); if( !query.exec() ) { - qDebug() << "Failed to insert track:" << name_orig ; + tDebug() << "Failed to insert track:" << name_orig ; return 0; } @@ -396,7 +396,7 @@ DatabaseImpl::albumId( int artistid, const QString& name_orig, bool& isnew ) query.addBindValue( sortname ); if( !query.exec() ) { - qDebug() << "Failed to insert album: " << name_orig ; + tDebug() << "Failed to insert album: " << name_orig ; return 0; } @@ -533,7 +533,7 @@ DatabaseImpl::resultFromHint( const Tomahawk::query_ptr& origquery ) else { // Q_ASSERT( false ); - qDebug() << "We don't support non-servent / non-file result-hints yet."; + tDebug() << "We don't support non-servent / non-file result-hints yet."; /* res = Tomahawk::result_ptr( new Tomahawk::Result() ); s = SourceList::instance()->webSource(); res->setUrl( url ); @@ -630,7 +630,7 @@ DatabaseImpl::getDatabaseVersion( const QString& dbname ) db.setDatabaseName( dbname ); if ( !db.open() ) { - qDebug() << "Failed to open database" << dbname; + tLog() << "Failed to open database" << dbname; throw "failed to open db"; // TODO } @@ -639,7 +639,7 @@ DatabaseImpl::getDatabaseVersion( const QString& dbname ) if ( qry.next() ) { version = qry.value( 0 ).toInt(); - qDebug() << "Database schema of" << dbname << "is" << version; + tLog() << "Database schema of" << dbname << "is" << version; } } diff --git a/src/libtomahawk/database/schema.sql b/src/libtomahawk/database/schema.sql index 723943106..7e2ff8daa 100644 --- a/src/libtomahawk/database/schema.sql +++ b/src/libtomahawk/database/schema.sql @@ -108,7 +108,8 @@ CREATE TABLE IF NOT EXISTS playlist_revision ( CREATE TABLE IF NOT EXISTS dynamic_playlist ( guid TEXT NOT NULL REFERENCES playlist(guid) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, pltype TEXT, -- the generator type - plmode INTEGER -- the mode of this playlist + plmode INTEGER, -- the mode of this playlist + autoload BOOLEAN DEFAULT true -- if this playlist should be autoloaded or not. true except for the case of special playlists we want to display elsewhere ); --INSERT INTO dynamic_playlist(guid, pltype, plmode) @@ -282,4 +283,4 @@ CREATE TABLE IF NOT EXISTS settings ( v TEXT NOT NULL DEFAULT '' ); -INSERT INTO settings(k,v) VALUES('schema_version', '25'); +INSERT INTO settings(k,v) VALUES('schema_version', '26'); diff --git a/src/libtomahawk/database/schema.sql.h b/src/libtomahawk/database/schema.sql.h index b9ff40493..22168f55e 100644 --- a/src/libtomahawk/database/schema.sql.h +++ b/src/libtomahawk/database/schema.sql.h @@ -1,5 +1,5 @@ /* - This file was automatically generated from ./schema.sql on Fri Jun 24 09:10:23 CEST 2011. + This file was automatically generated from schema.sql on Mon Jul 25 20:38:55 EDT 2011. */ static const char * tomahawk_schema_sql = @@ -78,7 +78,8 @@ static const char * tomahawk_schema_sql = "CREATE TABLE IF NOT EXISTS dynamic_playlist (" " guid TEXT NOT NULL REFERENCES playlist(guid) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED," " pltype TEXT, " -" plmode INTEGER " +" plmode INTEGER, " +" autoload BOOLEAN DEFAULT true " ");" "CREATE TABLE IF NOT EXISTS dynamic_playlist_controls (" " id TEXT PRIMARY KEY," @@ -183,7 +184,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', '25');" +"INSERT INTO settings(k,v) VALUES('schema_version', '26');" ; const char * get_tomahawk_sql() diff --git a/src/libtomahawk/playlist/dynamic/DynamicControl.h b/src/libtomahawk/playlist/dynamic/DynamicControl.h index c03d386fd..99d1f5371 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicControl.h +++ b/src/libtomahawk/playlist/dynamic/DynamicControl.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -25,7 +25,7 @@ #include #include "typedefs.h" -namespace Tomahawk +namespace Tomahawk { /** @@ -34,11 +34,11 @@ namespace Tomahawk * - 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 +class DynamicControl : public QObject { Q_OBJECT Q_PROPERTY( QString type READ type WRITE setType ) // the generator type associated with this control @@ -47,67 +47,67 @@ class DynamicControl : public QObject Q_PROPERTY( QString match READ match WRITE setMatch ) Q_PROPERTY( QString input READ input WRITE setInput ) Q_PROPERTY( QString summary READ summary ) // a summary of the control in phrase form - + 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 user-readable match value, for showing in read-only playlists virtual QString matchString() const { Q_ASSERT( false ); return QString(); } - + /// the serializable value of the match virtual QString match() const { Q_ASSERT( false ); return QString(); } /// the serializable value of the input virtual QString input() const { Q_ASSERT( false ); return QString(); } /// the user-readable summary phrase virtual QString summary() const { Q_ASSERT( false ); return QString(); } - + // used by JSON serialization virtual void setMatch( const QString& /*match*/ ) { Q_ASSERT( false ); } virtual void setInput( const QString& /*input*/ ) { Q_ASSERT( false ); } /// 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; } - + void setType( const QString& type ) { m_type = type; } QString type() const { return m_type; } - + signals: void changed(); - + 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 ); - + private: QString m_type; QString m_selectedType; diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp index c456fc1c5..aa32ad200 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp +++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp @@ -24,7 +24,7 @@ #include "database/databasecommand.h" #include "database/databasecommand_createdynamicplaylist.h" #include "database/databasecommand_setdynamicplaylistrevision.h" -#include "database/databasecommand_loaddynamicplaylist.h" +#include "database/databasecommand_loaddynamicplaylistentries.h" #include "database/databasecommand_deletedynamicplaylist.h" #include "tomahawksettings.h" #include "utils/logger.h" @@ -221,7 +221,7 @@ DynamicPlaylist::loadRevision( const QString& rev ) // qDebug() << Q_FUNC_INFO << "Loading with:" << ( rev.isEmpty() ? currentrevision() : rev ); setBusy( true ); - DatabaseCommand_LoadDynamicPlaylist* cmd = new DatabaseCommand_LoadDynamicPlaylist( rev.isEmpty() ? currentrevision() : rev ); + DatabaseCommand_LoadDynamicPlaylistEntries* cmd = new DatabaseCommand_LoadDynamicPlaylistEntries( rev.isEmpty() ? currentrevision() : rev ); if( m_generator->mode() == OnDemand ) { connect( cmd, SIGNAL( done( QString, diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h index e8ab3cc0a..dad43c38c 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h +++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h @@ -36,6 +36,8 @@ class DatabaseCollection; namespace Tomahawk { +class DatabaseCommand_LoadDynamicPlaylist; + /** * 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 @@ -70,6 +72,7 @@ class DLLEXPORT DynamicPlaylist : public Playlist friend class ::DatabaseCommand_SetDynamicPlaylistRevision; friend class ::DatabaseCommand_CreateDynamicPlaylist; + friend class Tomahawk::DatabaseCommand_LoadDynamicPlaylist; friend class ::DatabaseCollection; /// :-( public: diff --git a/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.h b/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.h index a242769d0..68b9cc646 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.h +++ b/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ #define COLLAPSIBLE_CONTROLS_H #include "typedefs.h" +#include "source.h" #include @@ -42,35 +43,35 @@ public: CollapsibleControls( QWidget* parent ); CollapsibleControls( const dynplaylist_ptr& playlist, bool isLocal, QWidget* parent = 0 ); virtual ~CollapsibleControls(); - + void setControls( const dynplaylist_ptr& playlist, bool isLocal ); QList< DynamicControlWrapper* > controls() const; - + virtual QSize sizeHint() const; signals: void controlsChanged(); void controlChanged( const Tomahawk::dyncontrol_ptr& control ); - + private slots: void toggleCollapse(); - + void onAnimationStep( int ); void onAnimationFinished(); - + private: void init(); - + dynplaylist_ptr m_dynplaylist; QStackedLayout* m_layout; DynamicControlList* m_controls; bool m_isLocal; - + QWidget* m_summaryWidget; QHBoxLayout* m_summaryLayout; ElidedLabel* m_summary; QStackedLayout* m_expandL; QToolButton* m_summaryExpand; - + // animations! QTimeLine* m_timeline; int m_animHeight; diff --git a/src/libtomahawk/playlist/trackview.h b/src/libtomahawk/playlist/trackview.h index 4b47d2d0d..b7cc34b8f 100644 --- a/src/libtomahawk/playlist/trackview.h +++ b/src/libtomahawk/playlist/trackview.h @@ -24,6 +24,7 @@ #include "contextMenu.h" #include "playlistitemdelegate.h" +#include "album.h" #include "dllmacro.h" diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp new file mode 100644 index 000000000..8f7d39da8 --- /dev/null +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp @@ -0,0 +1,94 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#include "SocialPlaylistWidget.h" +#include "ui_SocialPlaylistWidget.h" + +#include "database/databasecommand_loaddynamicplaylist.h" +#include "database/database.h" +#include "sourcelist.h" + +#define COOLPLAYLIST_GUID "TOMAHAWK_COOLPLAYLISTOHAI_GUID" + +using namespace Tomahawk; + +SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) + : QWidget ( parent ) + , ui( new Ui_SocialPlaylistWidget ) + , m_coolQuery1Model( new PlaylistModel( this ) ) +{ + ui->setupUi( this ); + + ui->playlistView->setPlaylistModel( m_coolQuery1Model ); + + load(); +} + +SocialPlaylistWidget::~SocialPlaylistWidget() +{ + +} + +void +SocialPlaylistWidget::load() +{ + // Load the pre-baked custom playlists that we are going to show. + // They also might not exist yet if this the first time this is shown, so then we create them. + DatabaseCommand_LoadDynamicPlaylist* cmd = new DatabaseCommand_LoadDynamicPlaylist( SourceList::instance()->getLocal(), COOLPLAYLIST_GUID, 0 ); + connect( cmd, SIGNAL( dynamicPlaylistLoaded( Tomahawk::dynplaylist_ptr ) ), this, SLOT( dynamicPlaylistLoaded( Tomahawk::dynplaylist_ptr ) ) ); + connect( cmd, SIGNAL( done() ), this, SLOT( dynamicPlaylistLoadDone() ) ); + + Database::instance()->enqueue( QSharedPointer( cmd ) ); +} + +PlaylistInterface* +SocialPlaylistWidget::playlistInterface() const +{ + return ui->playlistView->proxyModel(); +} + +void +SocialPlaylistWidget::dynamicPlaylistLoaded ( const dynplaylist_ptr& ptr ) +{ + m_coolQuery1 = ptr; + tLog() << "SocialPlaylistWidget got dynplaylist loaded with currev: " << m_coolQuery1->currentrevision(); + connect( m_coolQuery1.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) ); + m_coolQuery1->loadRevision( m_coolQuery1->currentrevision() ); +} + +void +SocialPlaylistWidget::playlistRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) +{ + m_coolQuery1Model->loadPlaylist( m_coolQuery1 ); +} + +void +SocialPlaylistWidget::dynamicPlaylistLoadDone() +{ + if ( m_coolQuery1.isNull() ) /// Load failed so we need to create the playlist, doesn't exist yet + { + tLog() << "SocialPlaylistWidget didn't find the magic dynamic playlist, creating!"; + createPlaylist(); + } +} + +void +SocialPlaylistWidget::createPlaylist() +{ + // TODO +} diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.h b/src/libtomahawk/widgets/SocialPlaylistWidget.h new file mode 100644 index 000000000..30acd72b0 --- /dev/null +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.h @@ -0,0 +1,96 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +/** + * \class SocialPlaylistWidget + * \brief ViewPage, which displays some interesting lists of songs mined from the database + * + * This Tomahawk ViewPage displays various interesting database searches that expose cool + * lists of songs. It is accessed from the sidebar, and contains a few custom-created DatabaseGenerator-backed + * playlists. + * + */ + +#ifndef SOCIALPLAYLISTWIDGET_H +#define SOCIALPLAYLISTWIDGET_H + +#include + +#include "viewpage.h" + +#include "dllmacro.h" +#include "typedefs.h" +#include "playlist/dynamic/DynamicPlaylist.h" +#include "source.h" + +class PlaylistModel; +class TreeModel; + +class Ui_SocialPlaylistWidget; + +namespace Tomahawk +{ + +class DLLEXPORT SocialPlaylistWidget : public QWidget, public Tomahawk::ViewPage +{ + Q_OBJECT + +public: + SocialPlaylistWidget( QWidget* parent = 0 ); + ~SocialPlaylistWidget(); + + virtual QWidget* widget() { return this; } + virtual Tomahawk::PlaylistInterface* playlistInterface() const; + + virtual QString title() const { return m_title; } + virtual QString description() const { return m_description; } + virtual QString longDescription() const { return m_longDescription; } + virtual QPixmap pixmap() const { if ( m_pixmap.isNull() ) return Tomahawk::ViewPage::pixmap(); else return m_pixmap; } + + virtual bool showStatsBar() const { return false; } + + virtual bool jumpToCurrentTrack() { return false; } + +signals: + void longDescriptionChanged( const QString& description ); + void descriptionChanged( const QString& description ); + void pixmapChanged( const QPixmap& pixmap ); + +private slots: + void dynamicPlaylistLoaded( const Tomahawk::dynplaylist_ptr& ptr ); + void playlistRevisionLoaded ( Tomahawk::DynamicPlaylistRevision ); + void dynamicPlaylistLoadDone(); + +private: + void load(); + void createPlaylist(); + + Ui_SocialPlaylistWidget *ui; + + Tomahawk::dynplaylist_ptr m_coolQuery1; + PlaylistModel* m_coolQuery1Model; + + QString m_title; + QString m_description; + QString m_longDescription; + QPixmap m_pixmap; +}; + +} + +#endif // SOCIALPLAYLISTWIDGET_H diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.ui b/src/libtomahawk/widgets/SocialPlaylistWidget.ui new file mode 100644 index 000000000..bd3748bff --- /dev/null +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.ui @@ -0,0 +1,46 @@ + + + SocialPlaylistWidget + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 4 + + + + + Social Stuff! + + + + + + + + + + + PlaylistView + QTreeView +
playlist/playlistview.h
+
+ + HeaderLabel + QLabel +
widgets/HeaderLabel.h
+
+
+ + +
diff --git a/src/sourcetree/items/collectionitem.cpp b/src/sourcetree/items/collectionitem.cpp index 1fd27bdf9..ece973e6f 100644 --- a/src/sourcetree/items/collectionitem.cpp +++ b/src/sourcetree/items/collectionitem.cpp @@ -23,6 +23,7 @@ #include "genericpageitems.h" #include "utils/tomahawkutils.h" #include "utils/logger.h" +#include /// CollectionItem @@ -35,12 +36,21 @@ CollectionItem::CollectionItem( SourcesModel* mdl, SourceTreeItem* parent, cons , m_stations( 0 ) , m_tempItem( 0 ) , m_sourceInfoItem( 0 ) + , m_coolPlaylistsItem( 0 ) , m_curTempPage( 0 ) , m_sourceInfoPage( 0 ) + , m_coolPlaylistsPage( 0 ) { if( m_source.isNull() ) { // super collection connect( ViewManager::instance(), SIGNAL( tempPageActivated( Tomahawk::ViewPage*) ), this, SLOT( tempPageActivated( Tomahawk::ViewPage* ) ) ); + m_coolPlaylistsItem = new GenericPageItem( model(), this, tr( "Cool Stuff" ), QIcon( RESPATH "images/new-additions.png" ), + boost::bind( &CollectionItem::coolPlaylistsClicked, this ), + boost::bind( &CollectionItem::getCoolPlaylistsPage, this ) + ); + m_coolPlaylistsItem->setSortValue( 200 ); + + return; } @@ -50,6 +60,8 @@ CollectionItem::CollectionItem( SourcesModel* mdl, SourceTreeItem* parent, cons ); m_sourceInfoItem->setSortValue( -300 ); + + // create category items if there are playlists to show, or stations to show QList< playlist_ptr > playlists = source->collection()->playlists(); QList< dynplaylist_ptr > autoplaylists = source->collection()->autoPlaylists(); @@ -338,3 +350,20 @@ CollectionItem::getSourceInfoPage() const { return m_sourceInfoPage; } + +ViewPage* +CollectionItem::coolPlaylistsClicked() +{ + if( !m_source.isNull() ) + return 0; + + m_coolPlaylistsPage = new SocialPlaylistWidget( ViewManager::instance()->widget() ); + ViewManager::instance()->show( m_coolPlaylistsPage ); + return m_coolPlaylistsPage; +} + +ViewPage* +CollectionItem::getCoolPlaylistsPage() const +{ + return m_coolPlaylistsPage; +} diff --git a/src/sourcetree/items/collectionitem.h b/src/sourcetree/items/collectionitem.h index 90615dac0..5737cbb9e 100644 --- a/src/sourcetree/items/collectionitem.h +++ b/src/sourcetree/items/collectionitem.h @@ -58,6 +58,9 @@ private slots: Tomahawk::ViewPage* sourceInfoClicked(); Tomahawk::ViewPage* getSourceInfoPage() const; + Tomahawk::ViewPage* coolPlaylistsClicked(); + Tomahawk::ViewPage* getCoolPlaylistsPage() const; + private: void playlistsAddedInternal( SourceTreeItem* parent, const QList< Tomahawk::dynplaylist_ptr >& playlists ); template< typename T > @@ -69,8 +72,11 @@ private: GenericPageItem* m_tempItem; GenericPageItem* m_sourceInfoItem; + GenericPageItem* m_coolPlaylistsItem; + Tomahawk::ViewPage* m_curTempPage; Tomahawk::ViewPage* m_sourceInfoPage; + Tomahawk::ViewPage* m_coolPlaylistsPage; }; From c76fabbc2b49c5ede2cc6a9c1da86bf839caccdc Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 30 Jul 2011 15:35:32 -0400 Subject: [PATCH 04/17] Create and load database-backed special dynamic playlists, and fix some debugs and stuff --- .../databasecommand_createplaylist.cpp | 4 -- .../databasecommand_genericselect.cpp | 20 ++++++-- .../database/databasecommand_genericselect.h | 4 +- ...basecommand_setdynamicplaylistrevision.cpp | 33 ++++++++---- ...tabasecommand_setdynamicplaylistrevision.h | 5 ++ src/libtomahawk/database/tomahawksqlquery.h | 11 ++-- .../playlist/dynamic/DynamicPlaylist.cpp | 22 ++++++-- .../playlist/dynamic/DynamicPlaylist.h | 11 +++- .../dynamic/database/DatabaseControl.cpp | 2 +- .../dynamic/database/DatabaseGenerator.cpp | 51 ++++++++++++++----- .../dynamic/database/DatabaseGenerator.h | 1 + .../widgets/SocialPlaylistWidget.cpp | 46 ++++++++++++++++- .../widgets/SocialPlaylistWidget.h | 3 ++ src/sip/twitter/twitter.h | 3 -- src/tomahawkapp.cpp | 3 ++ 15 files changed, 169 insertions(+), 50 deletions(-) diff --git a/src/libtomahawk/database/databasecommand_createplaylist.cpp b/src/libtomahawk/database/databasecommand_createplaylist.cpp index b451394be..f7ca227c5 100644 --- a/src/libtomahawk/database/databasecommand_createplaylist.cpp +++ b/src/libtomahawk/database/databasecommand_createplaylist.cpp @@ -31,7 +31,6 @@ DatabaseCommand_CreatePlaylist::DatabaseCommand_CreatePlaylist( QObject* parent : DatabaseCommandLoggable( parent ) , m_report( true ) { - qDebug() << Q_FUNC_INFO << "def"; } @@ -41,7 +40,6 @@ DatabaseCommand_CreatePlaylist::DatabaseCommand_CreatePlaylist( const source_ptr , m_playlist( playlist ) , m_report( false ) //this ctor used when creating locally, reporting done elsewhere { - qDebug() << Q_FUNC_INFO; } @@ -55,7 +53,6 @@ DatabaseCommand_CreatePlaylist::exec( DatabaseImpl* lib ) void DatabaseCommand_CreatePlaylist::postCommitHook() { - qDebug() << Q_FUNC_INFO; if ( m_report == false ) return; @@ -122,7 +119,6 @@ DatabaseCommand_CreatePlaylist::createPlaylist( DatabaseImpl* lib, bool dynamic) cre.bindValue( ":creator", m.value( "creator" ) ); cre.bindValue( ":lastmodified", m.value( "lastmodified", 0 ) ); } - tDebug() << "CREATE PLAYLIST:" << cre.boundValues(); cre.exec(); } diff --git a/src/libtomahawk/database/databasecommand_genericselect.cpp b/src/libtomahawk/database/databasecommand_genericselect.cpp index 63c439b9c..aff0a8236 100644 --- a/src/libtomahawk/database/databasecommand_genericselect.cpp +++ b/src/libtomahawk/database/databasecommand_genericselect.cpp @@ -37,14 +37,13 @@ DatabaseCommand_GenericSelect::DatabaseCommand_GenericSelect( const QString& sql void DatabaseCommand_GenericSelect::exec( DatabaseImpl* dbi ) { - Q_ASSERT( source()->isLocal() || source()->id() >= 1 ); TomahawkSqlQuery query = dbi->newquery(); - query.exec( m_sqlSelect ); + query.prepare( m_sqlSelect ); + query.exec(); QList< query_ptr > queries; - // Expecting while ( query.next() ) { @@ -54,9 +53,20 @@ DatabaseCommand_GenericSelect::exec( DatabaseImpl* dbi ) QString artist, track, album; track = query.value( 0 ).toString(); artist = query.value( 1 ).toString(); - album = query.value( 2 ).toString(); - Tomahawk::query_ptr qry = Tomahawk::Query::get( artist, track, album, uuid(), true ); // Only auto-resolve non-local results + + Tomahawk::query_ptr qry = Tomahawk::Query::get( artist, track, QString(), uuid(), true ); // Only auto-resolve non-local results + + QVariantList extraData; + int count = 2; + while ( query.value( count ).isValid() ) + { + extraData << query.value( count ); + count++; + } + if( !extraData.isEmpty() ) + qry->setProperty( "data", extraData ); + queries << qry; } diff --git a/src/libtomahawk/database/databasecommand_genericselect.h b/src/libtomahawk/database/databasecommand_genericselect.h index 931f452e9..fc35494f4 100644 --- a/src/libtomahawk/database/databasecommand_genericselect.h +++ b/src/libtomahawk/database/databasecommand_genericselect.h @@ -32,7 +32,9 @@ * that match. * * In order for the conversion to query_ptr to work, the SELECT command should select the following items: - * track.name, artist.name, album.name + * track.name, artist.name [, optional extra values ] + * + * Any extra values in the resultset will be returned as a QVariantList attached to the "data" property of each query_ptr * */ class DLLEXPORT DatabaseCommand_GenericSelect : public DatabaseCommand diff --git a/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.cpp b/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.cpp index 6a7aa6b1b..fdf9fb67b 100644 --- a/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.cpp +++ b/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.cpp @@ -40,6 +40,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::DatabaseCommand_SetDynamicPlaylistRe , m_type( type ) , m_mode( mode ) , m_controls( controls ) + , m_playlist( 0 ) { } @@ -56,6 +57,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::DatabaseCommand_SetDynamicPlaylistRe , m_type( type ) , m_mode( mode ) , m_controls( controls ) + , m_playlist( 0 ) { } @@ -100,21 +102,28 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook() dynplaylist_ptr playlist = source()->collection()->autoPlaylist( playlistguid() ); if ( playlist.isNull() ) playlist = source()->collection()->station( playlistguid() ); + // UGH we don't have a sharedptr from DynamicPlaylist+ + + DynamicPlaylist* rawPl = playlist.data(); + if( playlist.isNull() ) // if it's neither an auto or station, it must not be auto-loaded, so we MUST have been told about it directly + rawPl = m_playlist; // workaround a bug in pre-0.1.0 tomahawks. they created dynamic playlists in OnDemand mode *always*, and then set the mode to the real one. // now that we separate them, if we get them as one and then get a changed mode, the playlist ends up in the wrong bucket in Collection. // so here we fix it if we have to. // HACK - tDebug() << "Does this need FIXING?" << playlist->mode() << source()->collection()->autoPlaylist( playlistguid() ).isNull() << source()->collection()->station( playlistguid() ).isNull(); - if( playlist->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() ) // should be here + tDebug() << "Does this need the 0.3->0.1 playlist category hack fix?" << ( rawPl->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() ) + << ( rawPl->mode() == OnDemand && source()->collection()->station( playlistguid() ).isNull() ) + << rawPl->mode() << source()->collection()->autoPlaylist( playlistguid() ).isNull() << source()->collection()->station( playlistguid() ).isNull(); + if( rawPl->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() ) // should be here source()->collection()->moveStationToAuto( playlistguid() ); - else if ( playlist->mode() == OnDemand && source()->collection()->station( playlistguid() ).isNull() ) // should be here + else if ( rawPl->mode() == OnDemand && source()->collection()->station( playlistguid() ).isNull() ) // should be here source()->collection()->moveAutoToStation( playlistguid() ); - if ( playlist.isNull() ) + if ( rawPl == 0 ) { tLog() <<"Got null playlist with guid:" << playlistguid() << "from source and collection:" << source()->friendlyName() << source()->collection()->name() << "and mode is static?:" << (m_mode == Static); - Q_ASSERT( !playlist.isNull() ); + Q_ASSERT( false ); return; } if ( !m_controlsV.isEmpty() && m_controls.isEmpty() ) @@ -124,13 +133,13 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook() controlMap << v.toMap(); if ( m_mode == OnDemand ) - playlist->setRevision( newrev(), + rawPl->setRevision( newrev(), true, // this *is* the newest revision so far m_type, controlMap, m_applied ); else - playlist->setRevision( newrev(), + rawPl->setRevision( newrev(), orderedentriesguids, m_previous_rev_orderedguids, m_type, @@ -142,13 +151,13 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook() else { if ( m_mode == OnDemand ) - playlist->setRevision( newrev(), + rawPl->setRevision( newrev(), true, // this *is* the newest revision so far m_type, m_controls, m_applied ); else - playlist->setRevision( newrev(), + rawPl->setRevision( newrev(), orderedentriesguids, m_previous_rev_orderedguids, m_type, @@ -251,3 +260,9 @@ DatabaseCommand_SetDynamicPlaylistRevision::exec( DatabaseImpl* lib ) query2.exec(); } } + +void +DatabaseCommand_SetDynamicPlaylistRevision::setPlaylist( DynamicPlaylist* pl ) +{ + m_playlist = pl; +} diff --git a/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.h b/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.h index f9f9c1a63..f40dbe4c6 100644 --- a/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.h +++ b/src/libtomahawk/database/databasecommand_setdynamicplaylistrevision.h @@ -78,11 +78,16 @@ public: void setType( const QString& type ) { m_type = type; } void setMode( int mode ) { m_mode = (GeneratorMode)mode; } + void setPlaylist( DynamicPlaylist* pl ); // raw pointer b/c we don't have the shared pointer from inside the shared pointer + private: QString m_type; GeneratorMode m_mode; QList< dyncontrol_ptr > m_controls; QList< QVariant > m_controlsV; + + // ARG i hate sharedpointers sometimes + DynamicPlaylist* m_playlist; // Only used if setting revision of a non-autoloaded playlist, as those aren't able to be looked up by guid }; #endif // DATABASECOMMAND_SETDYNAMICPLAYLISTREVISION_H diff --git a/src/libtomahawk/database/tomahawksqlquery.h b/src/libtomahawk/database/tomahawksqlquery.h index a50d59124..827476df8 100644 --- a/src/libtomahawk/database/tomahawksqlquery.h +++ b/src/libtomahawk/database/tomahawksqlquery.h @@ -59,7 +59,7 @@ public: int e = t.elapsed(); if ( e >= TOMAHAWK_QUERY_THRESHOLD ) - qDebug() << "TomahawkSqlQuery (" << lastQuery() << ") finished in" << t.elapsed() << "ms"; + tLog() << "TomahawkSqlQuery (" << lastQuery() << ") finished in" << t.elapsed() << "ms"; return ret; } @@ -67,11 +67,10 @@ public: private: void showError() { - qDebug() - << endl << "*** DATABASE ERROR ***" << endl - << this->lastQuery() << endl - << "boundValues:" << this->boundValues() << endl - << this->lastError().text() << endl + tLog() << "\n" << "*** DATABASE ERROR ***" << "\n" + << this->lastQuery() << "\n" + << "boundValues:" << this->boundValues() << "\n" + << this->lastError().text() << "\n" ; Q_ASSERT( false ); } diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp index aa32ad200..5ad9ac14a 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp +++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp @@ -59,6 +59,7 @@ DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& src, int lastmod, const QString& guid ) : Playlist( src, currentrevision, title, info, creator, createdOn, shared, lastmod, guid ) + , m_autoLoad( false ) { // qDebug() << "Creating Dynamic Playlist 1"; // TODO instantiate generator @@ -75,8 +76,10 @@ DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& author, const QString& creator, const QString& type, GeneratorMode mode, - bool shared ) + bool shared, + bool autoLoad ) : Playlist ( author, guid, title, info, creator, shared ) + , m_autoLoad( autoLoad ) { // qDebug() << "Creating Dynamic Playlist 2"; m_generator = geninterface_ptr( GeneratorFactory::create( type ) ); @@ -127,14 +130,17 @@ DynamicPlaylist::create( const Tomahawk::source_ptr& author, const QString& creator, GeneratorMode mode, bool shared, - const QString& type ) + const QString& type, + bool autoLoad + ) { - dynplaylist_ptr dynplaylist = dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared ) ); + dynplaylist_ptr dynplaylist = dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared, autoLoad ) ); - DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist ); + DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist, autoLoad ); connect( cmd, SIGNAL(finished()), dynplaylist.data(), SIGNAL(created()) ); Database::instance()->enqueue( QSharedPointer(cmd) ); - dynplaylist->reportCreated( dynplaylist ); + if( autoLoad ) + dynplaylist->reportCreated( dynplaylist ); return dynplaylist; } @@ -187,6 +193,9 @@ DynamicPlaylist::createNewRevision( const QString& newrev, type, Static, controls ); + if( !m_autoLoad ) + cmd->setPlaylist( this ); + Database::instance()->enqueue( QSharedPointer( cmd ) ); } @@ -211,6 +220,9 @@ DynamicPlaylist::createNewRevision( const QString& newrev, type, OnDemand, controls ); + if( !m_autoLoad ) + cmd->setPlaylist( this ); + Database::instance()->enqueue( QSharedPointer( cmd ) ); } diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h index dad43c38c..289a819fb 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h +++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h @@ -69,6 +69,7 @@ class DLLEXPORT DynamicPlaylist : public Playlist // :-( int becuase qjson chokes on my enums Q_PROPERTY( int mode WRITE setMode READ mode ) Q_PROPERTY( QString type WRITE setType READ type ) + Q_PROPERTY( bool autoLoad READ autoLoad ) friend class ::DatabaseCommand_SetDynamicPlaylistRevision; friend class ::DatabaseCommand_CreateDynamicPlaylist; @@ -86,7 +87,9 @@ public: const QString& creator, GeneratorMode mode, bool shared, - const QString& type = QString() ); + const QString& type = QString(), + bool autoLoad = true + ); static bool remove( const dynplaylist_ptr& playlist ); virtual void loadRevision( const QString& rev = "" ); @@ -95,6 +98,7 @@ public: int mode() const; QString type() const; geninterface_ptr generator() const; + bool autoLoad() const { return m_autoLoad; } // Creates a new revision from the playlist in memory. Use this is you change the controls or // mode of a playlist and want to save it to db/others. @@ -186,10 +190,13 @@ private: const QString& creator, const QString& type, GeneratorMode mode, - bool shared ); + bool shared, + bool autoLoad = true ); QList< dyncontrol_ptr > variantsToControl( const QList< QVariantMap >& controlsV ); + geninterface_ptr m_generator; + bool m_autoLoad; }; }; // namespace diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseControl.cpp b/src/libtomahawk/playlist/dynamic/database/DatabaseControl.cpp index 6cdb650e3..4aa6146e6 100644 --- a/src/libtomahawk/playlist/dynamic/database/DatabaseControl.cpp +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseControl.cpp @@ -36,7 +36,7 @@ DatabaseControl::DatabaseControl( const QString& selectedType, const QStringList } DatabaseControl::DatabaseControl( const QString& sql, const QString& summary, const QStringList& typeSelectors, QObject* parent ) - : DynamicControl ( typeSelectors ) + : DynamicControl ( "SQL", typeSelectors ) , m_sql( sql ) , m_sqlSummary( summary ) { diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp index 29f4ca92b..9e097d633 100644 --- a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp @@ -53,7 +53,11 @@ DatabaseFactory::typeSelectors() const DatabaseGenerator::DatabaseGenerator ( QObject* parent ) : GeneratorInterface ( parent ) + , m_curCountRequested( 0 ) { + // defaults + m_type = "database"; + m_mode = Static; // m_logo.load( RESPATH "images ) } @@ -85,41 +89,62 @@ void DatabaseGenerator::generate( int number ) { tLog() << "Generating" << number << "tracks for this database dynamic playlist with" << m_controls.size() << "controls:"; + if ( m_controls.isEmpty() ) + { + qWarning() << "No controls, can't generate...!"; + emit error( "Failed to generate tracks", "No controls!" ); + return; + } + foreach ( const dyncontrol_ptr& ctrl, m_controls ) qDebug() << ctrl->selectedType() << ctrl->match() << ctrl->input(); // TODO for now, we just support the special "SQL" control, not meant to be shown to the user. Just does a raw query. - bool isSql = false; + bool hasSql = false; + bool hasOther = false; foreach ( const dyncontrol_ptr& ctrl, m_controls ) { - if( ctrl->selectedType() == "SQL" ) - isSql = true; - else if( !isSql ) - { - qWarning() << "Cannot mix sql and non-sql controls!"; - emit error( "Failed to generate tracks", "Cannot mix sql and non-sql controls" ); - } + if ( ctrl->selectedType() == "SQL" ) + hasSql = true; + else + hasOther = true; + } + if ( hasSql == hasOther ) + { + qWarning() << "Cannot mix sql and non-sql controls!"; + emit error( "Failed to generate tracks", "Cannot mix sql and non-sql controls" ); + return; } // TODO for now we just support 1 sql query if we're a sql type - if ( isSql ) + if ( hasSql ) { dyncontrol_ptr control = m_controls.first(); - DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( control.dynamicCast< DatabaseControl >()->sql(), this ); - connect( cmd, SIGNAL( tracks( QList ) ), this, SIGNAL( tracksGenerated( QList ) ) ); + tDebug() << "Generated sql query:" << control.dynamicCast< DatabaseControl >()->sql(); + DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( control.dynamicCast< DatabaseControl >()->sql() ); + m_curCountRequested = number; // Can't set count on dbcmd itself as sender() in slot is 0 + + connect( cmd, SIGNAL( tracks( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) ); return; } - } void DatabaseGenerator::tracksGenerated ( const QList< query_ptr >& tracks ) { - emit generated( tracks ); + if( m_curCountRequested == 0 ) + return; + + if ( m_curCountRequested < tracks.size() ) + emit generated( tracks.mid( 0, m_curCountRequested ) ); + else + emit generated( tracks ); + + m_curCountRequested = 0; } diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h index 81627de88..da654408e 100644 --- a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h @@ -73,6 +73,7 @@ namespace Tomahawk private: QPixmap m_logo; + int m_curCountRequested; }; }; diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp index 8f7d39da8..3cd86a38c 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp @@ -22,6 +22,9 @@ #include "database/databasecommand_loaddynamicplaylist.h" #include "database/database.h" #include "sourcelist.h" +#include "dynamic/GeneratorInterface.h" +#include "dynamic/database/DatabaseGenerator.h" +#include "utils/logger.h" #define COOLPLAYLIST_GUID "TOMAHAWK_COOLPLAYLISTOHAI_GUID" @@ -68,6 +71,9 @@ SocialPlaylistWidget::dynamicPlaylistLoaded ( const dynplaylist_ptr& ptr ) m_coolQuery1 = ptr; tLog() << "SocialPlaylistWidget got dynplaylist loaded with currev: " << m_coolQuery1->currentrevision(); connect( m_coolQuery1.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) ); + connect( m_coolQuery1->generator().data(), SIGNAL(generated( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); + + connect( m_coolQuery1->generator().data(), SIGNAL(generated( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); m_coolQuery1->loadRevision( m_coolQuery1->currentrevision() ); } @@ -75,6 +81,11 @@ void SocialPlaylistWidget::playlistRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) { m_coolQuery1Model->loadPlaylist( m_coolQuery1 ); + m_coolQuery1->resolve(); + + if ( m_coolQuery1->entries().isEmpty() ) // Generate some + m_coolQuery1->generator()->generate( 30 ); + } void @@ -90,5 +101,38 @@ SocialPlaylistWidget::dynamicPlaylistLoadDone() void SocialPlaylistWidget::createPlaylist() { - // TODO + // Ok, lets create our playlist + /** + * select count(*) as counter, track.name, artist.name from (select track from playback_log group by track, source), track, artist where track.id = track and artist.id = track.artist group by track order by counter desc limit 0,20; + s elect count(*) as counter, playback_log.track, track.name, artist.name from playback_log, track, artist where track.id = playback_log.track and artist.id = track.artist group by playback_log.track order by counter desc limit 0,10; * + select count(*) as counter, track.name, artist.name from (select track from playback_log group by track, source), track, artist where track not in (select track from playback_log where source is null group by track) and track.id = track and artist.id = track.artist group by track order by counter desc limit 0,20; + select count(*) as counter, track.name, artist.name from (select track from playback_log where source > 0 group by track, source), track, artist where track.id = track and artist.id = track.artist group by track order by counter desc limit 0,20; + */ + m_coolQuery1 = DynamicPlaylist::create( SourceList::instance()->getLocal(), COOLPLAYLIST_GUID, "Cool Playlist!", QString(), QString(), Static, false, "database", false ); + connect( m_coolQuery1.data(), SIGNAL( created() ), this, SLOT( playlist1Created() ) ); +} + +void +SocialPlaylistWidget::playlist1Created() +{ + Q_ASSERT( m_coolQuery1->generator().dynamicCast< DatabaseGenerator >() ); + + QString sql = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track.id = track and artist.id = track.artist group by track order by counter desc limit 0,100;"; + + dyncontrol_ptr control = m_coolQuery1->generator().dynamicCast< DatabaseGenerator >()->createControl( sql, "This is a cool playlist!" ); + m_coolQuery1->createNewRevision( uuid() ); + + connect( m_coolQuery1.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) ); + connect( m_coolQuery1->generator().data(), SIGNAL(generated( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); +} + +void +SocialPlaylistWidget::tracksGenerated( QList< query_ptr > queries ) +{ + if ( sender() == m_coolQuery1->generator().data() ) + { + tDebug() << "Got generated tracks from playlist, adding" << queries.size() << "tracks"; + m_coolQuery1Model->clear(); + m_coolQuery1->addEntries( queries, m_coolQuery1->currentrevision() ); + } } diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.h b/src/libtomahawk/widgets/SocialPlaylistWidget.h index 30acd72b0..ebbd76963 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.h +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.h @@ -74,8 +74,11 @@ signals: private slots: void dynamicPlaylistLoaded( const Tomahawk::dynplaylist_ptr& ptr ); void playlistRevisionLoaded ( Tomahawk::DynamicPlaylistRevision ); + void tracksGenerated ( QList ); void dynamicPlaylistLoadDone(); + void playlist1Created(); + private: void load(); void createPlaylist(); diff --git a/src/sip/twitter/twitter.h b/src/sip/twitter/twitter.h index 1846e0b8a..cdeaa8306 100644 --- a/src/sip/twitter/twitter.h +++ b/src/sip/twitter/twitter.h @@ -72,9 +72,6 @@ public: virtual QIcon icon() const; virtual QWidget* configWidget(); -signals: - void avatarReceived( QString, QPixmap ); - public slots: virtual bool connectPlugin( bool startup ); void disconnectPlugin(); diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index b2cdc6df3..f7833d3f5 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -40,6 +40,7 @@ #include "sip/SipHandler.h" #include "playlist/dynamic/GeneratorFactory.h" #include "playlist/dynamic/echonest/EchonestGenerator.h" +#include "playlist/dynamic/database/DatabaseGenerator.h" #include "web/api_v1.h" #include "resolvers/scriptresolver.h" #include "resolvers/qtscriptresolver.h" @@ -175,6 +176,8 @@ TomahawkApp::init() tDebug() << "Init Echonest Factory."; GeneratorFactory::registerFactory( "echonest", new EchonestFactory ); + tDebug() << "Init Database Factory."; + GeneratorFactory::registerFactory( "database", new DatabaseFactory ); // Register shortcut handler for this platform #ifdef Q_WS_MAC From 9c36b32e8e167205c995b0f7c1d96da1c6b8bc15 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 30 Jul 2011 16:13:29 -0400 Subject: [PATCH 05/17] add migrate script --- data/sql/dbmigrate-25_to_26.sql | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 data/sql/dbmigrate-25_to_26.sql diff --git a/data/sql/dbmigrate-25_to_26.sql b/data/sql/dbmigrate-25_to_26.sql new file mode 100644 index 000000000..12cd2ce51 --- /dev/null +++ b/data/sql/dbmigrate-25_to_26.sql @@ -0,0 +1,8 @@ +-- Script to migate from db version 25 to 26. +-- Added the "autoload" column to dynamic_playlist +-- + + +ALTER TABLE dynamic_playlist ADD COLUMN autoload BOOLEAN DEFAULT 1; + +UPDATE settings SET v = '26' WHERE k == 'schema_version'; From ce60c173b7aacd6e4a941691ef4e11202e05181f Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 30 Jul 2011 17:05:01 -0400 Subject: [PATCH 06/17] Add support for track, artist, and album generic queries --- .../databasecommand_genericselect.cpp | 62 +++++++++++++++---- .../database/databasecommand_genericselect.h | 21 ++++++- .../dynamic/database/DatabaseGenerator.cpp | 12 ++-- .../dynamic/database/DatabaseGenerator.h | 6 +- .../widgets/SocialPlaylistWidget.cpp | 3 +- 5 files changed, 83 insertions(+), 21 deletions(-) diff --git a/src/libtomahawk/database/databasecommand_genericselect.cpp b/src/libtomahawk/database/databasecommand_genericselect.cpp index aff0a8236..56899a309 100644 --- a/src/libtomahawk/database/databasecommand_genericselect.cpp +++ b/src/libtomahawk/database/databasecommand_genericselect.cpp @@ -27,9 +27,10 @@ using namespace Tomahawk; -DatabaseCommand_GenericSelect::DatabaseCommand_GenericSelect( const QString& sqlSelect, QObject* parent ) +DatabaseCommand_GenericSelect::DatabaseCommand_GenericSelect( const QString& sqlSelect, QueryType type, QObject* parent ) : DatabaseCommand( parent ) , m_sqlSelect( sqlSelect ) + , m_queryType( type ) { } @@ -43,19 +44,40 @@ DatabaseCommand_GenericSelect::exec( DatabaseImpl* dbi ) query.exec(); QList< query_ptr > queries; + QList< artist_ptr > arts; + QList< album_ptr > albs; // Expecting while ( query.next() ) { - Tomahawk::result_ptr result = Tomahawk::result_ptr( new Tomahawk::Result() ); - Tomahawk::source_ptr s; + query_ptr qry; + artist_ptr artist; + album_ptr album; - QString artist, track, album; - track = query.value( 0 ).toString(); - artist = query.value( 1 ).toString(); + if ( m_queryType == Track ) + { + QString artist, track; + track = query.value( 0 ).toString(); + artist = query.value( 1 ).toString(); - Tomahawk::query_ptr qry = Tomahawk::Query::get( artist, track, QString(), uuid(), true ); // Only auto-resolve non-local results + qry = Tomahawk::Query::get( artist, track, QString(), uuid(), true ); // Only auto-resolve non-local results + } else if ( m_queryType == Artist ) + { + int artistId = query.value( 0 ).toInt(); + QString artistName = query.value( 1 ).toString(); + + artist = Tomahawk::Artist::get( artistId, artistName ); + } else if ( m_queryType == Album ) + { + int albumId = query.value( 0 ).toInt(); + QString albumName = query.value( 1 ).toString(); + int artistId = query.value( 2 ).toInt(); + QString artistName = query.value( 3 ).toString(); + + artist = Tomahawk::Artist::get( artistId, artistName ); + album = Tomahawk::Album::get( albumId, albumName, artist ); + } QVariantList extraData; int count = 2; @@ -64,11 +86,29 @@ DatabaseCommand_GenericSelect::exec( DatabaseImpl* dbi ) extraData << query.value( count ); count++; } - if( !extraData.isEmpty() ) - qry->setProperty( "data", extraData ); - queries << qry; + if ( m_queryType == Track ) + { + if ( !extraData.isEmpty() ) + qry->setProperty( "data", extraData ); + queries << qry; + } else if ( m_queryType == Artist ) + { + if ( !extraData.isEmpty() ) + artist->setProperty( "data", extraData ); + arts << artist; + } else if ( m_queryType == Album ) + { + if ( !extraData.isEmpty() ) + album->setProperty( "data", extraData ); + albs << album; + } } - emit tracks( queries ); + if ( m_queryType == Track ) + emit tracks( queries ); + else if ( m_queryType == Artist ) + emit artists( arts ); + else if ( m_queryType == Album ) + emit albums( albs ); } diff --git a/src/libtomahawk/database/databasecommand_genericselect.h b/src/libtomahawk/database/databasecommand_genericselect.h index fc35494f4..e469cd671 100644 --- a/src/libtomahawk/database/databasecommand_genericselect.h +++ b/src/libtomahawk/database/databasecommand_genericselect.h @@ -32,7 +32,15 @@ * that match. * * In order for the conversion to query_ptr to work, the SELECT command should select the following items: - * track.name, artist.name [, optional extra values ] + * + * track query: + * track.name, artist.name [, optional extra values ] + * + * artist query: + * artist.id, artist.name [, optional extra values ] + * + * album query: + * album.id, album.name, artist.id, artist.name [, optional extra values ] * * Any extra values in the resultset will be returned as a QVariantList attached to the "data" property of each query_ptr * @@ -42,7 +50,13 @@ class DLLEXPORT DatabaseCommand_GenericSelect : public DatabaseCommand Q_OBJECT public: - explicit DatabaseCommand_GenericSelect( const QString& sqlSelect, QObject* parent = 0 ); + enum QueryType { + Track, + Artist, + Album + }; + + explicit DatabaseCommand_GenericSelect( const QString& sqlSelect, QueryType type, QObject* parent = 0 ); virtual void exec( DatabaseImpl* lib ); virtual bool doesMutates() const { return false; } @@ -50,9 +64,12 @@ public: signals: void tracks( const QList< Tomahawk::query_ptr >& tracks ); + void artists( const QList< Tomahawk::artist_ptr >& artists ); + void albums( const QList< Tomahawk::album_ptr >& albums ); private: QString m_sqlSelect; + QueryType m_queryType; }; #endif // DATABASECOMMAND_GENERICSELECT_H diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp index 9e097d633..a0f449377 100644 --- a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp @@ -38,9 +38,11 @@ DatabaseFactory::createControl ( const QString& controlType ) } dyncontrol_ptr -DatabaseFactory::createControl ( const QString& sql, const QString& summary ) +DatabaseFactory::createControl ( const QString& sql, DatabaseCommand_GenericSelect::QueryType type, const QString& summary ) { - return dyncontrol_ptr( new DatabaseControl( sql, summary, typeSelectors() ) ); + dyncontrol_ptr control = dyncontrol_ptr( new DatabaseControl( sql, summary, typeSelectors() ) ); + control->setMatch( QString::number( type ) ); + return control; } @@ -122,7 +124,8 @@ DatabaseGenerator::generate( int number ) dyncontrol_ptr control = m_controls.first(); tDebug() << "Generated sql query:" << control.dynamicCast< DatabaseControl >()->sql(); - DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( control.dynamicCast< DatabaseControl >()->sql() ); + DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( control.dynamicCast< DatabaseControl >()->sql(), + static_cast< DatabaseCommand_GenericSelect::QueryType >( control->match().toInt() ) ); m_curCountRequested = number; // Can't set count on dbcmd itself as sender() in slot is 0 connect( cmd, SIGNAL( tracks( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); @@ -156,9 +159,10 @@ DatabaseGenerator::createControl( const QString& type ) } dyncontrol_ptr -DatabaseGenerator::createControl ( const QString& sql, const QString& summary ) +DatabaseGenerator::createControl ( const QString& sql, DatabaseCommand_GenericSelect::QueryType type, const QString& summary ) { m_controls << dyncontrol_ptr( new DatabaseControl( sql, summary, GeneratorFactory::typeSelectors( m_type ) ) ); + m_controls.last()->setMatch( QString::number( type ) ); return m_controls.last(); } diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h index da654408e..83802d6c3 100644 --- a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h @@ -24,7 +24,7 @@ #include "playlist/dynamic/GeneratorInterface.h" #include "playlist/dynamic/GeneratorFactory.h" #include "playlist/dynamic/DynamicControl.h" - +#include "database/databasecommand_genericselect.h" #include "dllmacro.h" namespace Tomahawk @@ -39,7 +39,7 @@ namespace Tomahawk virtual dyncontrol_ptr createControl( const QString& controlType = QString() ); // TO create a special SQL resolver that consists of a pre-baked SQL query and a description of it - virtual dyncontrol_ptr createControl( const QString& sql, const QString& summary ); + virtual dyncontrol_ptr createControl( const QString& sql, DatabaseCommand_GenericSelect::QueryType type, const QString& summary ); virtual QStringList typeSelectors() const; }; @@ -56,7 +56,7 @@ namespace Tomahawk virtual ~DatabaseGenerator(); virtual dyncontrol_ptr createControl( const QString& type = QString() ); - virtual dyncontrol_ptr createControl( const QString& sql, const QString& summary ); + virtual dyncontrol_ptr createControl( const QString& sql, DatabaseCommand_GenericSelect::QueryType type, const QString& summary ); virtual QPixmap logo(); virtual void generate ( int number = -1 ); diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp index 3cd86a38c..dc2295bfb 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp @@ -25,6 +25,7 @@ #include "dynamic/GeneratorInterface.h" #include "dynamic/database/DatabaseGenerator.h" #include "utils/logger.h" +#include "database/databasecommand_genericselect.h" #define COOLPLAYLIST_GUID "TOMAHAWK_COOLPLAYLISTOHAI_GUID" @@ -119,7 +120,7 @@ SocialPlaylistWidget::playlist1Created() QString sql = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track.id = track and artist.id = track.artist group by track order by counter desc limit 0,100;"; - dyncontrol_ptr control = m_coolQuery1->generator().dynamicCast< DatabaseGenerator >()->createControl( sql, "This is a cool playlist!" ); + dyncontrol_ptr control = m_coolQuery1->generator().dynamicCast< DatabaseGenerator >()->createControl( sql, DatabaseCommand_GenericSelect::Track, "This is a cool playlist!" ); m_coolQuery1->createNewRevision( uuid() ); connect( m_coolQuery1.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) ); From 91bdfec734d84844a3e88bac7532d6382d9a98a2 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 30 Jul 2011 17:16:56 -0400 Subject: [PATCH 07/17] Limit results to what was asked for --- .../database/databasecommand_genericselect.cpp | 5 +++-- .../database/databasecommand_genericselect.h | 7 ++++++- .../dynamic/database/DatabaseGenerator.cpp | 16 ++++------------ .../dynamic/database/DatabaseGenerator.h | 1 - src/libtomahawk/widgets/SocialPlaylistWidget.cpp | 2 +- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/libtomahawk/database/databasecommand_genericselect.cpp b/src/libtomahawk/database/databasecommand_genericselect.cpp index 56899a309..8b151928c 100644 --- a/src/libtomahawk/database/databasecommand_genericselect.cpp +++ b/src/libtomahawk/database/databasecommand_genericselect.cpp @@ -27,10 +27,11 @@ using namespace Tomahawk; -DatabaseCommand_GenericSelect::DatabaseCommand_GenericSelect( const QString& sqlSelect, QueryType type, QObject* parent ) +DatabaseCommand_GenericSelect::DatabaseCommand_GenericSelect( const QString& sqlSelect, QueryType type, int limit, QObject* parent ) : DatabaseCommand( parent ) , m_sqlSelect( sqlSelect ) , m_queryType( type ) + , m_limit( limit ) { } @@ -40,7 +41,7 @@ DatabaseCommand_GenericSelect::exec( DatabaseImpl* dbi ) { TomahawkSqlQuery query = dbi->newquery(); - query.prepare( m_sqlSelect ); + query.prepare( QString( "%1 %2;" ).arg( m_sqlSelect ).arg( m_limit > -1 ? QString( " LIMIT %1" ).arg( m_limit ) : QString() ) ); query.exec(); QList< query_ptr > queries; diff --git a/src/libtomahawk/database/databasecommand_genericselect.h b/src/libtomahawk/database/databasecommand_genericselect.h index e469cd671..da2989543 100644 --- a/src/libtomahawk/database/databasecommand_genericselect.h +++ b/src/libtomahawk/database/databasecommand_genericselect.h @@ -44,6 +44,10 @@ * * Any extra values in the resultset will be returned as a QVariantList attached to the "data" property of each query_ptr * + * Notes: + * * Do not trail your SQL command with ; + * * Do not use the LIMIT command if you pass limitResults > -1 + * */ class DLLEXPORT DatabaseCommand_GenericSelect : public DatabaseCommand { @@ -56,7 +60,7 @@ public: Album }; - explicit DatabaseCommand_GenericSelect( const QString& sqlSelect, QueryType type, QObject* parent = 0 ); + explicit DatabaseCommand_GenericSelect( const QString& sqlSelect, QueryType type, int limitResults = -1, QObject* parent = 0 ); virtual void exec( DatabaseImpl* lib ); virtual bool doesMutates() const { return false; } @@ -70,6 +74,7 @@ signals: private: QString m_sqlSelect; QueryType m_queryType; + int m_limit; }; #endif // DATABASECOMMAND_GENERICSELECT_H diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp index a0f449377..1a71a3c5b 100644 --- a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.cpp @@ -55,7 +55,6 @@ DatabaseFactory::typeSelectors() const DatabaseGenerator::DatabaseGenerator ( QObject* parent ) : GeneratorInterface ( parent ) - , m_curCountRequested( 0 ) { // defaults m_type = "database"; @@ -125,8 +124,9 @@ DatabaseGenerator::generate( int number ) tDebug() << "Generated sql query:" << control.dynamicCast< DatabaseControl >()->sql(); DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( control.dynamicCast< DatabaseControl >()->sql(), - static_cast< DatabaseCommand_GenericSelect::QueryType >( control->match().toInt() ) ); - m_curCountRequested = number; // Can't set count on dbcmd itself as sender() in slot is 0 + static_cast< DatabaseCommand_GenericSelect::QueryType >( control->match().toInt() ), + number + ); connect( cmd, SIGNAL( tracks( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) ); @@ -139,15 +139,7 @@ DatabaseGenerator::generate( int number ) void DatabaseGenerator::tracksGenerated ( const QList< query_ptr >& tracks ) { - if( m_curCountRequested == 0 ) - return; - - if ( m_curCountRequested < tracks.size() ) - emit generated( tracks.mid( 0, m_curCountRequested ) ); - else - emit generated( tracks ); - - m_curCountRequested = 0; + emit generated( tracks ); } diff --git a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h index 83802d6c3..db2a52df6 100644 --- a/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h +++ b/src/libtomahawk/playlist/dynamic/database/DatabaseGenerator.h @@ -73,7 +73,6 @@ namespace Tomahawk private: QPixmap m_logo; - int m_curCountRequested; }; }; diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp index dc2295bfb..965d6f552 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp @@ -118,7 +118,7 @@ SocialPlaylistWidget::playlist1Created() { Q_ASSERT( m_coolQuery1->generator().dynamicCast< DatabaseGenerator >() ); - QString sql = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track.id = track and artist.id = track.artist group by track order by counter desc limit 0,100;"; + QString sql = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track.id = track and artist.id = track.artist group by track order by counter desc"; dyncontrol_ptr control = m_coolQuery1->generator().dynamicCast< DatabaseGenerator >()->createControl( sql, DatabaseCommand_GenericSelect::Track, "This is a cool playlist!" ); m_coolQuery1->createNewRevision( uuid() ); From 8e519534277478b787ceb9626ed6aab3b88eec22 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 31 Jul 2011 11:44:23 -0400 Subject: [PATCH 08/17] Switch to using direct GenericSelect command --- src/libtomahawk/playlist/albummodel.cpp | 15 +- src/libtomahawk/playlist/albummodel.h | 5 +- .../widgets/SocialPlaylistWidget.cpp | 151 ++++++++++-------- .../widgets/SocialPlaylistWidget.h | 20 +-- .../widgets/SocialPlaylistWidget.ui | 85 ++++++++-- 5 files changed, 178 insertions(+), 98 deletions(-) diff --git a/src/libtomahawk/playlist/albummodel.cpp b/src/libtomahawk/playlist/albummodel.cpp index 1d215040d..972ac372f 100644 --- a/src/libtomahawk/playlist/albummodel.cpp +++ b/src/libtomahawk/playlist/albummodel.cpp @@ -244,7 +244,7 @@ AlbumModel::addCollection( const collection_ptr& collection ) DatabaseCommand_AllAlbums* cmd = new DatabaseCommand_AllAlbums( collection ); connect( cmd, SIGNAL( albums( QList, QVariant ) ), - SLOT( onAlbumsAdded( QList ) ) ); + SLOT( addAlbums( QList ) ) ); Database::instance()->enqueue( QSharedPointer( cmd ) ); @@ -266,7 +266,7 @@ AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned in cmd->setSortDescending( true ); connect( cmd, SIGNAL( albums( QList, QVariant ) ), - SLOT( onAlbumsAdded( QList ) ) ); + SLOT( addAlbums( QList ) ) ); Database::instance()->enqueue( QSharedPointer( cmd ) ); @@ -278,7 +278,7 @@ AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned in void -AlbumModel::onAlbumsAdded( const QList& albums ) +AlbumModel::addAlbums( const QList& albums ) { if ( !albums.count() ) return; @@ -303,6 +303,15 @@ AlbumModel::onAlbumsAdded( const QList& albums ) qDebug() << rowCount( QModelIndex() ); } +void +AlbumModel::clear() +{ + beginResetModel(); + delete m_rootItem; + m_rootItem = new AlbumItem( 0, this ); + endResetModel(); +} + void AlbumModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) diff --git a/src/libtomahawk/playlist/albummodel.h b/src/libtomahawk/playlist/albummodel.h index 9265440e5..3730acde4 100644 --- a/src/libtomahawk/playlist/albummodel.h +++ b/src/libtomahawk/playlist/albummodel.h @@ -66,6 +66,8 @@ public: void addCollection( const Tomahawk::collection_ptr& collection ); void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllAlbums::SortOrder order ); + void clear(); + virtual QString title() const { return m_title; } virtual QString description() const { return m_description; } virtual void setTitle( const QString& title ) { m_title = title; } @@ -85,6 +87,8 @@ public slots: virtual void setRepeatMode( Tomahawk::PlaylistInterface::RepeatMode /*mode*/ ) {} virtual void setShuffled( bool /*shuffled*/ ) {} + void addAlbums( const QList& albums ); + signals: void repeatModeChanged( Tomahawk::PlaylistInterface::RepeatMode mode ); void shuffleModeChanged( bool enabled ); @@ -94,7 +98,6 @@ signals: protected: private slots: - void onAlbumsAdded( const QList& albums ); void onDataChanged(); void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp index 965d6f552..86877acde 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp @@ -26,21 +26,70 @@ #include "dynamic/database/DatabaseGenerator.h" #include "utils/logger.h" #include "database/databasecommand_genericselect.h" - -#define COOLPLAYLIST_GUID "TOMAHAWK_COOLPLAYLISTOHAI_GUID" +#include "widgets/overlaywidget.h" using namespace Tomahawk; +QString SocialPlaylistWidget::s_popularAlbumsQuery = "SELECT * from album"; +QString SocialPlaylistWidget::s_mostPlayedPlaylistsQuery = "asd"; +QString SocialPlaylistWidget::s_topForeignTracksQuery = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track not in (select track from playback_log where source is null group by track) and track.id = track and artist.id = track.artist group by track order by counter desc"; SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) : QWidget ( parent ) , ui( new Ui_SocialPlaylistWidget ) - , m_coolQuery1Model( new PlaylistModel( this ) ) + , m_topForeignTracksModel( 0 ) + , m_popularNewAlbumsModel( 0 ) { ui->setupUi( this ); - ui->playlistView->setPlaylistModel( m_coolQuery1Model ); - load(); + ui->splitter->setHandleWidth( 1 ); + ui->splitter_2->setHandleWidth( 1 ); + ui->splitter_2->setStretchFactor( 0, 2 ); + ui->splitter_2->setStretchFactor( 0, 1 ); + + /* + WelcomePlaylistModel* model = new WelcomePlaylistModel( this ); + model->setMaxPlaylists( HISTORY_PLAYLIST_ITEMS ); + */ + + ui->mostPlayedPlaylists->setFrameShape( QFrame::NoFrame ); + ui->mostPlayedPlaylists->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + ui->newTracksView->setFrameShape( QFrame::NoFrame ); + ui->newTracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + ui->newAlbumsView->setFrameShape( QFrame::NoFrame ); + ui->newAlbumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + TomahawkUtils::unmarginLayout( layout() ); + TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() ); + TomahawkUtils::unmarginLayout( ui->verticalLayout_2->layout() ); + TomahawkUtils::unmarginLayout( ui->verticalLayout_3->layout() ); + TomahawkUtils::unmarginLayout( ui->verticalLayout_4->layout() ); + +// ui->mostPlayedPlaylists->setItemDelegate( new PlaylistDelegate() ); +// ui->mostPlayedPlaylists->setModel( model ); +// ui->mostPlayedPlaylists->overlay()->resize( 380, 86 ); + +// connect( model, SIGNAL( emptinessChanged( bool) ), this, SLOT( updatePlaylists() ) ); + + m_topForeignTracksModel = new PlaylistModel( ui->newTracksView ); + ui->newTracksView->setPlaylistModel( m_topForeignTracksModel ); + m_topForeignTracksModel->setStyle( TrackModel::Short ); + ui->newTracksView->overlay()->setEnabled( false ); + + m_popularNewAlbumsModel = new AlbumModel( ui->newAlbumsView ); + ui->newAlbumsView->setAlbumModel( m_popularNewAlbumsModel ); + // TODO run the genericselect command +// m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime ); +/* + m_timer = new QTimer( this ); + connect( m_timer, SIGNAL( timeout() ), SLOT( checkQueries() ) ); + + connect( SourceList::instance(), SIGNAL( ready() ), SLOT( updateRecentTracks() ) ); + connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) ); + connect( ui->playlistWidget, SIGNAL( activated( QModelIndex ) ), SLOT( onPlaylistActivated( QModelIndex ) ) ); + connect( AudioEngine::instance() ,SIGNAL( playlistChanged( Tomahawk::PlaylistInterface* ) ), this, SLOT( updatePlaylists() ), Qt::QueuedConnection ); +*/ + fetchFromDB(); } SocialPlaylistWidget::~SocialPlaylistWidget() @@ -49,91 +98,55 @@ SocialPlaylistWidget::~SocialPlaylistWidget() } void -SocialPlaylistWidget::load() +SocialPlaylistWidget::fetchFromDB() { // Load the pre-baked custom playlists that we are going to show. - // They also might not exist yet if this the first time this is shown, so then we create them. - DatabaseCommand_LoadDynamicPlaylist* cmd = new DatabaseCommand_LoadDynamicPlaylist( SourceList::instance()->getLocal(), COOLPLAYLIST_GUID, 0 ); - connect( cmd, SIGNAL( dynamicPlaylistLoaded( Tomahawk::dynplaylist_ptr ) ), this, SLOT( dynamicPlaylistLoaded( Tomahawk::dynplaylist_ptr ) ) ); - connect( cmd, SIGNAL( done() ), this, SLOT( dynamicPlaylistLoadDone() ) ); + QSharedPointer albumsCmd = QSharedPointer( new DatabaseCommand_GenericSelect( s_popularAlbumsQuery, DatabaseCommand_GenericSelect::Album, 30, 0 ) ); + connect( albumsCmd.data(), SIGNAL( albums( QList ) ), this, SLOT( popularAlbumsFetched( QList ) ) ); + Database::instance()->enqueue( QSharedPointer( albumsCmd ) ); - Database::instance()->enqueue( QSharedPointer( cmd ) ); +// QSharedPointer plCmd = QSharedPointer( new DatabaseCommand_GenericSelect( s_mostPlayedPlaylistsQuery, DatabaseCommand_GenericSelect::, 30, 0 ) ); +// connect( albumsCmd.data(), SIGNAL( albums( QList ) ), this, SLOT( popularAlbumsFetched( QList ) ) ); +// Database::instance()->enqueue( QSharedPointer( albumsCmd ) ); + + QSharedPointer trackCmd = QSharedPointer( new DatabaseCommand_GenericSelect( s_topForeignTracksQuery, DatabaseCommand_GenericSelect::Track, 50, 0 ) ); + connect( trackCmd.data(), SIGNAL( tracks( QList ) ), this, SLOT( topForeignTracksFetched( QList ) ) ); + Database::instance()->enqueue( QSharedPointer( trackCmd ) ); } + PlaylistInterface* SocialPlaylistWidget::playlistInterface() const { - return ui->playlistView->proxyModel(); + return 0; } - -void -SocialPlaylistWidget::dynamicPlaylistLoaded ( const dynplaylist_ptr& ptr ) -{ - m_coolQuery1 = ptr; - tLog() << "SocialPlaylistWidget got dynplaylist loaded with currev: " << m_coolQuery1->currentrevision(); - connect( m_coolQuery1.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) ); - connect( m_coolQuery1->generator().data(), SIGNAL(generated( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); - - connect( m_coolQuery1->generator().data(), SIGNAL(generated( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); - m_coolQuery1->loadRevision( m_coolQuery1->currentrevision() ); -} - -void -SocialPlaylistWidget::playlistRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) -{ - m_coolQuery1Model->loadPlaylist( m_coolQuery1 ); - m_coolQuery1->resolve(); - - if ( m_coolQuery1->entries().isEmpty() ) // Generate some - m_coolQuery1->generator()->generate( 30 ); - -} - -void -SocialPlaylistWidget::dynamicPlaylistLoadDone() -{ - if ( m_coolQuery1.isNull() ) /// Load failed so we need to create the playlist, doesn't exist yet - { - tLog() << "SocialPlaylistWidget didn't find the magic dynamic playlist, creating!"; - createPlaylist(); - } -} - +/* void SocialPlaylistWidget::createPlaylist() { // Ok, lets create our playlist - /** + * select count(*) as counter, track.name, artist.name from (select track from playback_log group by track, source), track, artist where track.id = track and artist.id = track.artist group by track order by counter desc limit 0,20; s elect count(*) as counter, playback_log.track, track.name, artist.name from playback_log, track, artist where track.id = playback_log.track and artist.id = track.artist group by playback_log.track order by counter desc limit 0,10; * select count(*) as counter, track.name, artist.name from (select track from playback_log group by track, source), track, artist where track not in (select track from playback_log where source is null group by track) and track.id = track and artist.id = track.artist group by track order by counter desc limit 0,20; select count(*) as counter, track.name, artist.name from (select track from playback_log where source > 0 group by track, source), track, artist where track.id = track and artist.id = track.artist group by track order by counter desc limit 0,20; - */ + m_coolQuery1 = DynamicPlaylist::create( SourceList::instance()->getLocal(), COOLPLAYLIST_GUID, "Cool Playlist!", QString(), QString(), Static, false, "database", false ); connect( m_coolQuery1.data(), SIGNAL( created() ), this, SLOT( playlist1Created() ) ); +}*/ + +void +SocialPlaylistWidget::popularAlbumsFetched( QList< album_ptr > albums ) +{ + m_popularNewAlbumsModel->clear(); + + m_popularNewAlbumsModel->addAlbums( albums ); } void -SocialPlaylistWidget::playlist1Created() +SocialPlaylistWidget::topForeignTracksFetched( QList< query_ptr > tracks ) { - Q_ASSERT( m_coolQuery1->generator().dynamicCast< DatabaseGenerator >() ); - - QString sql = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track.id = track and artist.id = track.artist group by track order by counter desc"; - - dyncontrol_ptr control = m_coolQuery1->generator().dynamicCast< DatabaseGenerator >()->createControl( sql, DatabaseCommand_GenericSelect::Track, "This is a cool playlist!" ); - m_coolQuery1->createNewRevision( uuid() ); - - connect( m_coolQuery1.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) ); - connect( m_coolQuery1->generator().data(), SIGNAL(generated( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); -} - -void -SocialPlaylistWidget::tracksGenerated( QList< query_ptr > queries ) -{ - if ( sender() == m_coolQuery1->generator().data() ) - { - tDebug() << "Got generated tracks from playlist, adding" << queries.size() << "tracks"; - m_coolQuery1Model->clear(); - m_coolQuery1->addEntries( queries, m_coolQuery1->currentrevision() ); - } + m_topForeignTracksModel->clear(); + foreach( const query_ptr& q, tracks ) + m_topForeignTracksModel->append( q ); } diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.h b/src/libtomahawk/widgets/SocialPlaylistWidget.h index ebbd76963..e485ea88e 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.h +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.h @@ -38,6 +38,7 @@ #include "playlist/dynamic/DynamicPlaylist.h" #include "source.h" +class AlbumModel; class PlaylistModel; class TreeModel; @@ -72,26 +73,25 @@ signals: void pixmapChanged( const QPixmap& pixmap ); private slots: - void dynamicPlaylistLoaded( const Tomahawk::dynplaylist_ptr& ptr ); - void playlistRevisionLoaded ( Tomahawk::DynamicPlaylistRevision ); - void tracksGenerated ( QList ); - void dynamicPlaylistLoadDone(); - - void playlist1Created(); + void popularAlbumsFetched( QList ); + void topForeignTracksFetched( QList ); private: - void load(); - void createPlaylist(); + void fetchFromDB(); Ui_SocialPlaylistWidget *ui; + PlaylistModel* m_topForeignTracksModel; + AlbumModel* m_popularNewAlbumsModel; - Tomahawk::dynplaylist_ptr m_coolQuery1; - PlaylistModel* m_coolQuery1Model; QString m_title; QString m_description; QString m_longDescription; QPixmap m_pixmap; + + static QString s_popularAlbumsQuery; + static QString s_mostPlayedPlaylistsQuery; + static QString s_topForeignTracksQuery; }; } diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.ui b/src/libtomahawk/widgets/SocialPlaylistWidget.ui index bd3748bff..91a99dc6c 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.ui +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.ui @@ -6,27 +6,72 @@ 0 0 - 400 - 300 + 875 + 513 - - Form - - - - 4 - + - - - Social Stuff! + + + Qt::Horizontal + + + Qt::Vertical + + + + + + + Popular New Albums From Your Friends + + + + + + + + + + + + + + Most Played Playlists + + + + + + + + + + + + + + + Most Played Tracks You Don't Have + + + + + + + + 320 + 0 + + + + + + - - - @@ -40,6 +85,16 @@ QLabel
widgets/HeaderLabel.h
+ + AlbumView + QListView +
playlist/albumview.h
+
+ + PlaylistWidget + QListWidget +
widgets/welcomewidget.h
+
From d3eb8df91a8acb842a04030f7092d480f363bd95 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Wed, 3 Aug 2011 23:25:31 -0400 Subject: [PATCH 09/17] Add support for JSPF playlists, remote and local --- src/libtomahawk/CMakeLists.txt | 4 +- src/libtomahawk/globalactionmanager.cpp | 9 ++ src/libtomahawk/utils/jspfloader.cpp | 191 ++++++++++++++++++++++++ src/libtomahawk/utils/jspfloader.h | 77 ++++++++++ src/tomahawkapp.cpp | 11 +- 5 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 src/libtomahawk/utils/jspfloader.cpp create mode 100644 src/libtomahawk/utils/jspfloader.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 459cdc881..ff3a500f2 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -166,6 +166,7 @@ set( libSources utils/animatedsplitter.cpp utils/xspfloader.cpp utils/xspfgenerator.cpp + utils/jspfloader.cpp widgets/newplaylistwidget.cpp widgets/searchwidget.cpp @@ -336,6 +337,7 @@ set( libHeaders utils/animatedsplitter.h utils/xspfloader.h utils/xspfgenerator.h + utils/jspfloader.h widgets/newplaylistwidget.h widgets/searchwidget.h @@ -419,7 +421,7 @@ IF( APPLE ) FIND_LIBRARY( SCRIPTINGBRIDGE_LIBRARY ScriptingBridge ) MARK_AS_ADVANCED( COREAUDIO_LIBRARY COREFOUNDATION_LIBRARY FOUNDATION_LIBRARY SCRIPTINGBRIDGE_LIBRARY ) - SET( libSources ${libSources} + SET( libSources ${libSources} infosystem/infoplugins/mac/adium.mm infosystem/infoplugins/mac/adiumplugin.cpp widgets/maclineedit.mm diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index 2b28be069..b83238c98 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -41,6 +41,7 @@ #include #include +#include "utils/jspfloader.h" GlobalActionManager* GlobalActionManager::s_instance = 0; @@ -195,6 +196,14 @@ GlobalActionManager::parseTomahawkLink( const QString& url ) l->load( xspf ); connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) ); + return true; + } else if( u.hasQueryItem( "jspf" ) ) { + QUrl jspf = QUrl::fromUserInput( u.queryItemValue( "jspf" ) ); + Tomahawk::JSPFLoader* l = new Tomahawk::JSPFLoader( true, this ); + tDebug() << "Loading jspiff:" << jspf.toString(); + l->load( jspf ); + connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) ); + return true; } } diff --git a/src/libtomahawk/utils/jspfloader.cpp b/src/libtomahawk/utils/jspfloader.cpp new file mode 100644 index 000000000..1bd896bf8 --- /dev/null +++ b/src/libtomahawk/utils/jspfloader.cpp @@ -0,0 +1,191 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi . + */ + + +#include "jspfloader.h" + + +#include +#include +#include + +#include + +#include "utils/tomahawkutils.h" +#include "utils/logger.h" + +#include "sourcelist.h" +#include "playlist.h" + +using namespace Tomahawk; + +void +JSPFLoader::load( const QUrl& url ) +{ + QNetworkRequest request( url ); + Q_ASSERT( TomahawkUtils::nam() != 0 ); + QNetworkReply* reply = TomahawkUtils::nam()->get( request ); + + // isn't there a race condition here? something could happen before we connect() + // no---the event loop is needed to make the request, i think (leo) + connect( reply, SIGNAL( finished() ), + SLOT( networkLoadFinished() ) ); + + connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), + SLOT( networkError( QNetworkReply::NetworkError ) ) ); +} + + +void +JSPFLoader::load( QFile& file ) +{ + if( file.open( QFile::ReadOnly ) ) + { + m_body = file.readAll(); + gotBody(); + } + else + { + tLog() << "Failed to open jspf file"; + reportError(); + } +} + + +void +JSPFLoader::reportError() +{ + emit failed(); + deleteLater(); +} + + +void +JSPFLoader::networkLoadFinished() +{ + QNetworkReply* reply = qobject_cast(sender()); + m_body = reply->readAll(); + gotBody(); +} + + +void +JSPFLoader::networkError( QNetworkReply::NetworkError e ) +{ + tLog() << Q_FUNC_INFO << "Network error loading jspf" << e; + reportError(); +} + + +void +JSPFLoader::gotBody() +{ + QJson::Parser p; + bool retOk; + QVariantMap wrapper = p.parse( m_body, &retOk ).toMap(); + + if ( !retOk ) + { + tLog() << "Failed to parse jspf json:" << p.errorString() << "on line" << p.errorLine(); + return; + } + + if ( !wrapper.contains( "playlist" ) ) + { + tLog() << "No playlist element in JSPF!"; + return; + } + + QVariantMap pl = wrapper.value( "playlist" ).toMap(); + QString origTitle = pl.value( "title" ).toString(); + m_info = pl.value( "info" ).toString(); + m_creator = pl.value( "creator" ).toString(); + + m_title = origTitle; + if ( m_title.isEmpty() ) + m_title = tr( "New Playlist" ); + if ( !m_overrideTitle.isEmpty() ) + m_title = m_overrideTitle; + + if ( pl.contains( "track" ) ) + { + QVariantList tracks = pl.value( "track" ).toList(); + + bool shownError = false; + foreach ( const QVariant& track, tracks ) + { + QVariantMap tM = track.toMap(); + QString artist, album, track, duration, annotation, url; + + artist = tM.value( "creator" ).toString(); + album = tM.value( "album" ).toString(); + track = tM.value( "title" ).toString(); + duration = tM.value( "duration" ).toString(); + annotation = tM.value( "annotation" ).toString(); + if ( tM.value( "location" ).toList().size() > 0 ) + url = tM.value( "location" ).toList().first().toString(); + + if( artist.isEmpty() || track.isEmpty() ) + { + if( !shownError ) + { + QMessageBox::warning( 0, tr( "Failed to save tracks" ), tr( "Some tracks in the playlist do not contain an artist and a title. They will be ignored." ), QMessageBox::Ok ); + shownError = true; + } + continue; + } + + query_ptr q = Tomahawk::Query::get( artist, track, album, uuid() ); + q->setDuration( duration.toInt() / 1000 ); + if( !url.isEmpty() ) + q->setResultHint( url ); + + m_entries << q; + } + } + + if ( origTitle.isEmpty() && m_entries.isEmpty() ) + { + if ( m_autoCreate ) + { + QMessageBox::critical( 0, tr( "XSPF Error" ), tr( "This is not a valid XSPF playlist." ) ); + deleteLater(); + return; + } + else + { + emit failed(); + return; + } + } + + if ( m_autoCreate ) + { + m_playlist = Playlist::create( SourceList::instance()->getLocal(), + uuid(), + m_title, + m_info, + m_creator, + false, + m_entries ); + + deleteLater(); + } + + emit ok( m_playlist ); +} diff --git a/src/libtomahawk/utils/jspfloader.h b/src/libtomahawk/utils/jspfloader.h new file mode 100644 index 000000000..1228eac2f --- /dev/null +++ b/src/libtomahawk/utils/jspfloader.h @@ -0,0 +1,77 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi . + */ + + +#ifndef JSPFLOADER_H +#define JSPFLOADER_H + +#include +#include +#include +#include +#include + +#include "playlist.h" +#include "typedefs.h" + +#include "dllmacro.h" +namespace Tomahawk +{ + +class DLLEXPORT JSPFLoader : public QObject +{ +Q_OBJECT + +public: + explicit JSPFLoader( bool autoCreate = true, QObject* parent = 0 ) + : QObject( parent ) + , m_autoCreate( autoCreate ) + {} + + virtual ~JSPFLoader() {} + + QList< Tomahawk::query_ptr > entries() const { return m_entries; } + void setOverrideTitle( const QString& newTitle ) { m_overrideTitle = newTitle; } + +signals: + void failed(); + void ok( const Tomahawk::playlist_ptr& ); + +public slots: + void load( const QUrl& url ); + void load( QFile& file ); + +private slots: + void networkLoadFinished(); + void networkError( QNetworkReply::NetworkError e ); + +private: + void reportError(); + void gotBody(); + + bool m_autoCreate; + QList< Tomahawk::query_ptr > m_entries; + QString m_title, m_info, m_creator, m_overrideTitle; + + QByteArray m_body; + Tomahawk::playlist_ptr m_playlist; +}; + +} + +#endif // JSPFLOADER_H diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 76a332a00..cd2c7a502 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -54,6 +54,7 @@ #include "audio/audioengine.h" #include "utils/xspfloader.h" +#include "utils/jspfloader.h" #include "utils/logger.h" #include "utils/tomahawkutils.h" @@ -520,11 +521,19 @@ TomahawkApp::loadUrl( const QString& url ) { QFile f( url ); QFileInfo info( f ); - if ( f.exists() && info.suffix() == "xspf" ) { + if ( info.suffix() == "xspf" ) + { XSPFLoader* l = new XSPFLoader( true, this ); tDebug( LOGINFO ) << "Loading spiff:" << url; l->load( QUrl::fromUserInput( url ) ); + return true; + } else if ( info.suffix() == "jspf" ) + { + JSPFLoader* l = new JSPFLoader( true, this ); + tDebug( LOGINFO ) << "Loading j-spiff:" << url; + l->load( QUrl::fromUserInput( url ) ); + return true; } } From 5d5b5fa3afd35b7abcffc58239ff567bfd519a6b Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 5 Aug 2011 14:55:39 -0400 Subject: [PATCH 10/17] Paint dynamic controls the same hue as overlay widget. TWK-309 --- .../playlist/dynamic/echonest/EchonestSteerer.cpp | 2 +- .../playlist/dynamic/widgets/DynamicSetupWidget.cpp | 2 +- src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp index 1678a1fbe..c9fcc1aa4 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp @@ -118,7 +118,7 @@ EchonestSteerer::EchonestSteerer( QWidget* parent ) m_fadeAnim = new QPropertyAnimation( this, "opacity", this ); m_fadeAnim->setDuration( ANIM_DURATION ); m_fadeAnim->setStartValue( 0 ); - m_fadeAnim->setEndValue( .86 ); + m_fadeAnim->setEndValue( .7 ); resize( sizeHint() ); } diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp index d3c05aff3..fb23be2fc 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp @@ -90,7 +90,7 @@ DynamicSetupWidget::DynamicSetupWidget( const Tomahawk::dynplaylist_ptr& playlis m_fadeAnim = new QPropertyAnimation( this, "opacity" ); m_fadeAnim->setDuration( 250 ); m_fadeAnim->setStartValue( 0.00 ); - m_fadeAnim->setEndValue( .86 ); + m_fadeAnim->setEndValue( .70 ); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); resize( sizeHint() ); diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp index f3248eccc..0098a927f 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp @@ -413,9 +413,11 @@ DynamicWidget::paintRoundedFilledRect( QPainter& p, QPalette& pal, QRect& r, qre p.setRenderHint( QPainter::Antialiasing ); p.setOpacity( opacity ); - QPen pen( pal.dark().color(), .5 ); + QColor c( 30, 30, 30 ); + + QPen pen( c.darker(), .5 ); p.setPen( pen ); - p.setBrush( pal.highlight() ); + p.setBrush( c ); p.drawRoundedRect( r, 10, 10 ); From b2deebe0c25232955cbbf5bb5847557d1c615306 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 5 Aug 2011 15:36:04 -0400 Subject: [PATCH 11/17] Hide generator combobox until we have more than one generator --- .../playlist/dynamic/widgets/DynamicSetupWidget.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp index fb23be2fc..88e2bf25b 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp @@ -59,6 +59,9 @@ DynamicSetupWidget::DynamicSetupWidget( const Tomahawk::dynplaylist_ptr& playlis m_generatorCombo->setLabel( playlist->generator()->type().replace( 0, 1, playlist->generator()->type().at( 0 ).toUpper() ) ); m_layout->addWidget( m_generatorCombo ); + // TODO until there are more... no point in choices + m_headerText->hide(); + m_generatorCombo->hide(); m_generateButton = new QPushButton( tr( "Generate" ), this ); m_generateButton->setAttribute( Qt::WA_LayoutUsesWidgetRect ); @@ -76,7 +79,8 @@ DynamicSetupWidget::DynamicSetupWidget( const Tomahawk::dynplaylist_ptr& playlis else m_layout->addWidget( m_genNumber ); - m_layout->addSpacing( 30 ); + if( m_playlist->mode() == Static ) + m_layout->addSpacing( 30 ); m_logo = new QLabel( this ); if( !m_playlist->generator()->logo().isNull() ) { From aeb949aa23ad4cc79d6174b326fb5c8b58a6cc9d Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 5 Aug 2011 15:39:04 -0400 Subject: [PATCH 12/17] Fix merge --- src/libtomahawk/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 1b5a435bb..4dfe323c0 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -443,13 +443,8 @@ IF( APPLE ) utils/tomahawkutils_mac.mm ) SET( libHeaders ${libHeaders} -<<<<<<< HEAD infosystem/infoplugins/mac/adium.h infosystem/infoplugins/mac/adiumplugin.h ) -======= - infosystem/infoplugins/mac/adiumplugin.h - widgets/maclineedit.h ) ->>>>>>> master SET( OS_SPECIFIC_LINK_LIBRARIES ${OS_SPECIFIC_LINK_LIBRARIES} From 703823f5531dc952561ad0d058d3584f8c764eef Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 5 Aug 2011 16:05:53 -0400 Subject: [PATCH 13/17] fix up some copyrights from muesli's script --- .../dynamic/echonest/EchonestControl.cpp | 2 +- .../dynamic/echonest/EchonestControl.h | 2 +- .../dynamic/echonest/EchonestGenerator.cpp | 2 +- .../dynamic/echonest/EchonestGenerator.h | 2 +- .../dynamic/echonest/EchonestSteerer.cpp | 2 +- .../dynamic/echonest/EchonestSteerer.h | 38 +++++++++---------- .../dynamic/widgets/CollapsibleControls.cpp | 2 +- .../dynamic/widgets/CollapsibleControls.h | 2 +- .../dynamic/widgets/DynamicControlList.cpp | 2 +- .../dynamic/widgets/DynamicControlList.h | 24 ++++++------ .../dynamic/widgets/DynamicControlWrapper.cpp | 2 +- .../dynamic/widgets/DynamicControlWrapper.h | 24 ++++++------ .../dynamic/widgets/DynamicSetupWidget.cpp | 2 +- .../dynamic/widgets/DynamicSetupWidget.h | 26 ++++++------- .../dynamic/widgets/DynamicWidget.cpp | 2 +- .../playlist/dynamic/widgets/DynamicWidget.h | 2 +- 16 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp index cca7ad8a7..ad828f0de 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.h b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.h index 6544a8643..03a06114a 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.h +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp index 985a7fc7f..dea04b55e 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h index f9147f900..50d6b1963 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp index c9fcc1aa4..0192ece0a 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.h b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.h index 614b12007..b4ca3d9b8 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.h +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser + * + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,22 +30,22 @@ class QVBoxLayout; class QLineEdit; class QHBoxLayout; -namespace Tomahawk +namespace Tomahawk { - + class EchonestSteerer : public QWidget { Q_OBJECT Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) - + public: EchonestSteerer( QWidget* parent = 0 ); - + virtual void paintEvent(QPaintEvent* ); - + public slots: void resetSteering( bool automatic = false ); - + void fadeIn(); void fadeOut(); qreal opacity() const { return m_opacity; } @@ -54,39 +54,39 @@ signals: void steerField( const QString& field ); void steerDescription( const QString& desc ); void reset(); - + void resized(); private slots: void changed(); - + void resizeFrame( int ); - + private: QToolButton* initButton( QWidget* parent ); - + QHBoxLayout* m_layout; - + QComboBox* m_amplifier; QComboBox* m_field; - + QLineEdit* m_description; - + // text on the left QVBoxLayout* m_textL; QLabel* m_steerTop; QLabel* m_steerBottom; - + // icons on the right QToolButton* m_reset; - + // animations QTimeLine m_resizeAnim; bool m_expanding; - + QPropertyAnimation* m_fadeAnim; qreal m_opacity; }; - + }; #endif diff --git a/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.cpp b/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.cpp index 7c4fc1640..17f63d244 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.h b/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.h index 68b9cc646..d393ede3d 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.h +++ b/src/libtomahawk/playlist/dynamic/widgets/CollapsibleControls.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicControlList.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicControlList.cpp index b074d07fa..b73e30bc2 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicControlList.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicControlList.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicControlList.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicControlList.h index 985a1ccba..1b38e989a 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicControlList.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicControlList.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser + * + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,44 +36,44 @@ namespace Tomahawk class DynamicControlWrapper; - + /** * This widget encapsulates the list of dynamic controls. It can hide or show the controls. */ class DynamicControlList : public QWidget { - Q_OBJECT + Q_OBJECT public: DynamicControlList( QWidget* parent = 0 ); explicit DynamicControlList( const geninterface_ptr& generator, const QList< dyncontrol_ptr >& controls, QWidget* parent = 0 ); virtual ~DynamicControlList(); - + void setControls( const geninterface_ptr& generator, const QList< dyncontrol_ptr >& controls ); QList< DynamicControlWrapper* > controls() const { return m_controls; } - + signals: void controlsChanged(); void controlChanged( const Tomahawk::dyncontrol_ptr& control ); void toggleCollapse(); - + public slots: void addNewControl(); void removeControl(); void controlChanged(); - + private: void init(); - + geninterface_ptr m_generator; - + QGridLayout* m_layout; QList< DynamicControlWrapper* > m_controls; - + QHBoxLayout* m_collapseLayout; QPushButton* m_collapse; QToolButton* m_addControl; - + }; }; diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicControlWrapper.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicControlWrapper.cpp index e62d3a170..ed15d9184 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicControlWrapper.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicControlWrapper.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicControlWrapper.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicControlWrapper.h index b0c3df109..2ba42470a 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicControlWrapper.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicControlWrapper.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser + * + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,42 +39,42 @@ namespace Tomahawk */ class DynamicControlWrapper : public QObject { - Q_OBJECT + Q_OBJECT public: explicit DynamicControlWrapper( const dyncontrol_ptr& control, QGridLayout* layout, int row, QWidget* parent = 0 ); virtual ~DynamicControlWrapper(); - + // virtual void enterEvent(QEvent* ); // virtual void leaveEvent(QEvent* ); - + dyncontrol_ptr control() const; - + void removeFromLayout(); - - + + static QToolButton* initButton( QWidget* parent ); static QWidget* createDummy( QWidget* fromW, QWidget* parent ); signals: void collapse(); void removeControl(); void changed(); - + private slots: void typeSelectorChanged( const QString& selectedType, bool firstLoad = false ); - + private: QWidget* m_parent; int m_row; QStackedLayout* m_plusL; QToolButton* m_minusButton; - + dyncontrol_ptr m_control; QComboBox* m_typeSelector; QWeakPointer m_matchSelector; QWeakPointer m_entryWidget; QWeakPointer m_layout; }; - + }; #endif diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp index 88e2bf25b..3df01068a 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.h index 78568b19e..a0bd4e4ae 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicSetupWidget.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser + * + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,39 +44,39 @@ class DynamicSetupWidget : public QWidget public: DynamicSetupWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget* parent = 0 ); virtual ~DynamicSetupWidget(); - + void setPlaylist( const dynplaylist_ptr& playlist ); - + qreal opacity() const { return m_opacity; } void setOpacity( qreal opacity ); - + virtual void paintEvent( QPaintEvent* ); - -public slots: + +public slots: void fadeIn(); void fadeOut(); - + signals: void generatePressed( int num ); void typeChanged( const QString& playlistType ); - + private slots: void generatePressed( bool ); - + private: dynplaylist_ptr m_playlist; - + QLabel* m_headerText; QHBoxLayout* m_layout; ReadOrWriteWidget* m_generatorCombo; QLabel* m_logo; QPushButton* m_generateButton; QSpinBox* m_genNumber; - + QPropertyAnimation* m_fadeAnim; qreal m_opacity; }; - + }; #endif diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp index 0098a927f..9fa4d0e24 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h index 2db798dcb..4b6e7a5b3 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 1759d1ea198a8a68d30674afcb0d46b4d2bf630c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 5 Aug 2011 17:17:28 -0400 Subject: [PATCH 14/17] Add a loved tracks playlist, and aggregate loved tracks playlist, minus the actual valid tracks --- resources.qrc | 1 + src/libtomahawk/CMakeLists.txt | 2 + .../playlist/customplaylistview.cpp | 99 +++++++++++++++++++ src/libtomahawk/playlist/customplaylistview.h | 64 ++++++++++++ src/sourcetree/items/collectionitem.cpp | 51 ++++++++-- src/sourcetree/items/collectionitem.h | 5 + src/sourcetree/sourcesmodel.cpp | 6 -- 7 files changed, 214 insertions(+), 14 deletions(-) create mode 100644 src/libtomahawk/playlist/customplaylistview.cpp create mode 100644 src/libtomahawk/playlist/customplaylistview.h diff --git a/resources.qrc b/resources.qrc index 83175a04d..0b79cbc41 100644 --- a/resources.qrc +++ b/resources.qrc @@ -83,6 +83,7 @@ ./data/images/automatic-playlist.png ./data/images/station.png ./data/images/new-additions.png + ./data/images/loved_playlist.png ./data/stylesheets/topbar-radiobuttons.css ./data/icons/tomahawk-icon-16x16.png ./data/icons/tomahawk-icon-32x32.png diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 4dfe323c0..03f1bb709 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -120,6 +120,7 @@ set( libSources playlist/albumitemdelegate.cpp playlist/albumview.cpp playlist/artistview.cpp + playlist/customplaylistview.cpp playlist/topbar/topbar.cpp playlist/topbar/clearbutton.cpp @@ -310,6 +311,7 @@ set( libHeaders playlist/albumitemdelegate.h playlist/albumview.h playlist/artistview.h + playlist/customplaylistview.h playlist/topbar/topbar.h playlist/topbar/clearbutton.h diff --git a/src/libtomahawk/playlist/customplaylistview.cpp b/src/libtomahawk/playlist/customplaylistview.cpp new file mode 100644 index 000000000..d1dfb8cfb --- /dev/null +++ b/src/libtomahawk/playlist/customplaylistview.cpp @@ -0,0 +1,99 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + + +#include "customplaylistview.h" + +#include "database/databasecommand_genericselect.h" +#include "database/database.h" +#include "utils/tomahawkutils.h" + +using namespace Tomahawk; + +CustomPlaylistView::CustomPlaylistView( CustomPlaylistView::PlaylistType type, const source_ptr& s, QWidget* parent ) + : PlaylistView ( parent ) + , m_type( type ) + , m_source( s ) + , m_model( new PlaylistModel( this ) ) +{ + // Generate the tracks, add them to the playlist + setFrameShape( QFrame::NoFrame ); + setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + setPlaylistModel( m_model ); + generateTracks(); +} + + +void +CustomPlaylistView::generateTracks() +{ + QString sql; + switch ( m_type ) + { + // TODO + case SourceLovedTracks: + sql = "SELECT track.name, artist.name FROM track, artist WHERE track.artist = artist.id"; + break; + case AllLovedTracks: + sql = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track not in (select track from playback_log where source is null group by track) and track.id = track and artist.id = track.artist group by track order by counter desc"; + break; + } + + DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( sql, DatabaseCommand_GenericSelect::Track, 30, 0 ); + connect( cmd, SIGNAL( tracks( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); + Database::instance()->enqueue( QSharedPointer( cmd ) ); +} + +void +CustomPlaylistView::tracksGenerated( QList< query_ptr > tracks ) +{ + foreach ( const query_ptr& q, tracks ) + m_model->append( q ); +} + +QString +CustomPlaylistView::title() const +{ + if ( m_source.isNull() ) + return tr( "Top Loved Tracks" ); + else + return tr( "Your Loved Tracks" ); +} + + +QString +CustomPlaylistView::description() const +{ + if ( m_source.isNull() ) + return tr( "The most loved tracks from all your friends" ); + else + return tr( "Your top loved tracks" ); +} + +QString +CustomPlaylistView::longDescription() const +{ + return QString(); +} + +QPixmap +CustomPlaylistView::pixmap() const +{ + return QPixmap( RESPATH "images/loved_playlist.png" ); +} diff --git a/src/libtomahawk/playlist/customplaylistview.h b/src/libtomahawk/playlist/customplaylistview.h new file mode 100644 index 000000000..4871c028e --- /dev/null +++ b/src/libtomahawk/playlist/customplaylistview.h @@ -0,0 +1,64 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + + +#ifndef CUSTOMPLAYLISTVIEW_H +#define CUSTOMPLAYLISTVIEW_H + +#include "playlistview.h" + +#include "dllmacro.h" + +namespace Tomahawk +{ + +class DLLEXPORT CustomPlaylistView : public PlaylistView +{ + Q_OBJECT +public: + enum PlaylistType { + SourceLovedTracks, + AllLovedTracks + }; + + explicit CustomPlaylistView( PlaylistType type, const source_ptr& s, QWidget* parent = 0 ); + virtual ~CustomPlaylistView() {} + + virtual bool showFilter() const { return false; } + virtual bool showStatsBar() const { return false; } + + virtual QString title() const; + virtual QPixmap pixmap() const; + virtual QString description() const; + virtual QString longDescription() const; + virtual bool isTemporaryPage() const { return false; } + +private slots: + void tracksGenerated( QList tracks ); + +private: + void generateTracks(); + + PlaylistType m_type; + source_ptr m_source; + PlaylistModel* m_model; +}; + +} + +#endif // CUSTOMPLAYLISTVIEW_H diff --git a/src/sourcetree/items/collectionitem.cpp b/src/sourcetree/items/collectionitem.cpp index e26bcc2c5..84abafbcd 100644 --- a/src/sourcetree/items/collectionitem.cpp +++ b/src/sourcetree/items/collectionitem.cpp @@ -24,6 +24,7 @@ #include "utils/tomahawkutils.h" #include "utils/logger.h" #include +#include /// CollectionItem @@ -37,18 +38,36 @@ CollectionItem::CollectionItem( SourcesModel* mdl, SourceTreeItem* parent, cons , m_tempItem( 0 ) , m_sourceInfoItem( 0 ) , m_coolPlaylistsItem( 0 ) + , m_lovedTracksItem() , m_curTempPage( 0 ) , m_sourceInfoPage( 0 ) , m_coolPlaylistsPage( 0 ) + , m_lovedTracksPage( 0 ) { + + m_lovedTracksItem = new GenericPageItem( model(), this, ( m_source.isNull() ? tr( "Top Loved Tracks" ) : tr( "Loved Tracks" ) ), QIcon( RESPATH "images/loved_playlist.png" ), + boost::bind( &CollectionItem::lovedTracksClicked, this ), + boost::bind( &CollectionItem::getLovedTracksPage, this ) + ); + m_lovedTracksItem->setSortValue( -250 ); + + if( m_source.isNull() ) { // super collection connect( ViewManager::instance(), SIGNAL( tempPageActivated( Tomahawk::ViewPage*) ), this, SLOT( tempPageActivated( Tomahawk::ViewPage* ) ) ); - m_coolPlaylistsItem = new GenericPageItem( model(), this, tr( "Cool Stuff" ), QIcon( RESPATH "images/new-additions.png" ), - boost::bind( &CollectionItem::coolPlaylistsClicked, this ), - boost::bind( &CollectionItem::getCoolPlaylistsPage, this ) - ); - m_coolPlaylistsItem->setSortValue( 200 ); + // add misc children of root node + GenericPageItem* recent = new GenericPageItem( model(), this, tr( "Recently Played" ), QIcon( RESPATH "images/recently-played.png" ), + boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ), + boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() ) + ); + recent->setSortValue( -300 ); + + // TODO finish implementing and making pretty +// m_coolPlaylistsItem = new GenericPageItem( model(), this, tr( "Cool Stuff" ), QIcon( RESPATH "images/new-additions.png" ), +// boost::bind( &CollectionItem::coolPlaylistsClicked, this ), +// boost::bind( &CollectionItem::getCoolPlaylistsPage, this ) +// ); +// m_coolPlaylistsItem->setSortValue( 200 ); return; @@ -60,8 +79,6 @@ CollectionItem::CollectionItem( SourcesModel* mdl, SourceTreeItem* parent, cons ); m_sourceInfoItem->setSortValue( -300 ); - - // create category items if there are playlists to show, or stations to show QList< playlist_ptr > playlists = source->collection()->playlists(); QList< dynplaylist_ptr > autoplaylists = source->collection()->autoPlaylists(); @@ -387,7 +404,9 @@ CollectionItem::coolPlaylistsClicked() if( !m_source.isNull() ) return 0; - m_coolPlaylistsPage = new SocialPlaylistWidget( ViewManager::instance()->widget() ); + if( !m_coolPlaylistsPage ) + m_coolPlaylistsPage = new SocialPlaylistWidget( ViewManager::instance()->widget() ); + ViewManager::instance()->show( m_coolPlaylistsPage ); return m_coolPlaylistsPage; } @@ -397,3 +416,19 @@ CollectionItem::getCoolPlaylistsPage() const { return m_coolPlaylistsPage; } + +ViewPage* +CollectionItem::lovedTracksClicked() +{ + if( !m_lovedTracksPage ) + m_lovedTracksPage = new CustomPlaylistView( m_source.isNull() ? CustomPlaylistView::AllLovedTracks : CustomPlaylistView::SourceLovedTracks, m_source, ViewManager::instance()->widget() ); + + ViewManager::instance()->show( m_lovedTracksPage ); + return m_lovedTracksPage; +} + +ViewPage* +CollectionItem::getLovedTracksPage() const +{ + return m_lovedTracksPage; +} diff --git a/src/sourcetree/items/collectionitem.h b/src/sourcetree/items/collectionitem.h index 5737cbb9e..b92a75e47 100644 --- a/src/sourcetree/items/collectionitem.h +++ b/src/sourcetree/items/collectionitem.h @@ -61,6 +61,9 @@ private slots: Tomahawk::ViewPage* coolPlaylistsClicked(); Tomahawk::ViewPage* getCoolPlaylistsPage() const; + Tomahawk::ViewPage* lovedTracksClicked(); + Tomahawk::ViewPage* getLovedTracksPage() const; + private: void playlistsAddedInternal( SourceTreeItem* parent, const QList< Tomahawk::dynplaylist_ptr >& playlists ); template< typename T > @@ -73,10 +76,12 @@ private: GenericPageItem* m_tempItem; GenericPageItem* m_sourceInfoItem; GenericPageItem* m_coolPlaylistsItem; + GenericPageItem* m_lovedTracksItem; Tomahawk::ViewPage* m_curTempPage; Tomahawk::ViewPage* m_sourceInfoPage; Tomahawk::ViewPage* m_coolPlaylistsPage; + Tomahawk::ViewPage* m_lovedTracksPage; }; diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp index 94bd3e332..f97d3cb71 100644 --- a/src/sourcetree/sourcesmodel.cpp +++ b/src/sourcetree/sourcesmodel.cpp @@ -46,12 +46,6 @@ SourcesModel::SourcesModel( QObject* parent ) appendItem( source_ptr() ); - // add misc children of root node - new GenericPageItem( this, m_rootItem->children().at( 0 ), tr( "Recently Played" ), QIcon( RESPATH "images/recently-played.png" ), - boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ), - boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() ) - ); - onSourcesAdded( SourceList::instance()->sources() ); connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) ); From 4cfd039c40a57633c830335670351fcaa2e1200e Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 6 Aug 2011 12:40:29 -0400 Subject: [PATCH 15/17] social action stuff --- .../database/databasecommand_socialaction.h | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/libtomahawk/database/databasecommand_socialaction.h b/src/libtomahawk/database/databasecommand_socialaction.h index 578075189..9f62259e9 100644 --- a/src/libtomahawk/database/databasecommand_socialaction.h +++ b/src/libtomahawk/database/databasecommand_socialaction.h @@ -6,7 +6,7 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * Tomahawk 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 @@ -20,7 +20,7 @@ #define DATABASECOMMAND_SOCIALACTION_H #include -#include "database/databasecommand.h" +#include "database/databasecommandloggable.h" #include "sourcelist.h" #include "typedefs.h" @@ -31,43 +31,45 @@ /** * \class DatabaseCommand_SocialAction * \brief Database command used to write social actions to database. - * + * * This Database command allows Tomahawk to write social actions to * the local database. These social actions can be interfaced with social * networking API's such as LastFm, Facebook, or Twitter to allow the user * to sync these actions with their accounts on these sites. - * + * * \see DatabaseCommand_LoadSocialActions */ -class DLLEXPORT DatabaseCommand_SocialAction : public DatabaseCommand +class DLLEXPORT DatabaseCommand_SocialAction : public DatabaseCommandLoggable { -Q_OBJECT -Q_PROPERTY( QString action READ action WRITE setAction ) -Q_PROPERTY( QString comment READ comment WRITE setComment ) -Q_PROPERTY( int timestamp READ timestamp WRITE setTimestamp ) + Q_OBJECT + Q_PROPERTY( QString action READ action WRITE setAction ) + Q_PROPERTY( QString comment READ comment WRITE setComment ) + Q_PROPERTY( int timestamp READ timestamp WRITE setTimestamp ) + Q_PROPERTY( QString artist READ artist WRITE setArtist ) + Q_PROPERTY( QString track READ track WRITE setTrack ) public: - + /** * \brief Default constructor for DatabaseCommand_SocialAction. - * + * * Constructs an empty database command for a social action. */ explicit DatabaseCommand_SocialAction( QObject* parent = 0 ) - : DatabaseCommand( parent ) + : DatabaseCommandLoggable( parent ) {} - + /** * \brief Overloaded constructor for DatabaseCommand_SocialAction. * \param result Pointer to a Tomahawk::Result. * \param action Name of the social action to be written to the database. * \param comment Comment associated with this social action. * \param parent Parent class. - * + * * Constructor which creates a new database command for the specified social action. */ explicit DatabaseCommand_SocialAction( const Tomahawk::result_ptr& result, QString action, QString comment="", QObject* parent = 0 ) - : DatabaseCommand( parent ), m_result( result ), m_action( action ) + : DatabaseCommandLoggable( parent ), m_result( result ), m_action( action ) { setSource( SourceList::instance()->getLocal() ); @@ -86,12 +88,12 @@ public: /** * \brief Executes the database command. * \param dbi Database instance. - * + * * This method prepares an sql query to write this social action * into the local database. */ virtual void exec( DatabaseImpl* dbi ); - + /** * \brief Triggers a Database Sync. */ @@ -103,7 +105,7 @@ public: * \see setArtist() */ QString artist() const { return m_artist; } - + /** * \brief Sets the artist name for this database command. * \param s QString containing the artist name. @@ -117,49 +119,49 @@ public: * \see setTrack() */ QString track() const { return m_track; } - + /** * \brief Sets the track name associated with this database command. * \param track QString containing the track name. * \see track() */ void setTrack( const QString& track ) { m_track = track; } - + /** * \brief Returns the social action for this database command instance. * \return QString containing the action name. * \see setAction() */ QString action() const { return m_action; } - + /** * \brief Sets the social actions * \param a QString containing action to be set in this class. * \see action() */ void setAction( QString a ) { m_action = a; } - + /** * \brief Returns comment associated with this social action. * \return QString containing comment associated with this social action. * \see setComment() */ QString comment() const { return m_comment; } - + /** * \brief Sets the comment associated with this social action. * \param com Comment associated with this social action. * \see comment() */ void setComment( const QString& com ) { m_comment = com; } - + /** * \brief Returns the timestamp associated with this social action. * \return unsigned integer containing timestamp * \see setTimesetamp() */ int timestamp() const { return m_timestamp; } - + /** * \brief Sets the timestamp associated with this social action. * \param ts unsigned integer associated with this social action. @@ -167,6 +169,8 @@ public: */ void setTimestamp( const int ts ) { m_timestamp = ts; } + virtual bool doesMutates() const { return true; } + private: Tomahawk::result_ptr m_result; From cdfd6a3464b978a1bf288ffef6616c89892be1d7 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 6 Aug 2011 14:35:51 -0400 Subject: [PATCH 16/17] dd proper loved tracks queries --- src/libtomahawk/playlist/customplaylistview.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/playlist/customplaylistview.cpp b/src/libtomahawk/playlist/customplaylistview.cpp index d1dfb8cfb..4447d6488 100644 --- a/src/libtomahawk/playlist/customplaylistview.cpp +++ b/src/libtomahawk/playlist/customplaylistview.cpp @@ -48,10 +48,18 @@ CustomPlaylistView::generateTracks() { // TODO case SourceLovedTracks: - sql = "SELECT track.name, artist.name FROM track, artist WHERE track.artist = artist.id"; + sql = QString( "SELECT track.name, artist.name, COUNT(*) as counter " + "FROM social_attributes, track, artist " + "WHERE social_attributes.id = track.id AND artist.id = track.artist AND social_attributes.k = 'Love' AND source IS NULL " + "GROUP BY track.id " + "ORDER BY counter DESC " ); break; case AllLovedTracks: - sql = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track not in (select track from playback_log where source is null group by track) and track.id = track and artist.id = track.artist group by track order by counter desc"; + sql = QString( "SELECT track.name, artist.name, source, COUNT(*) as counter " + "FROM social_attributes, track, artist " + "WHERE social_attributes.id = track.id AND artist.id = track.artist AND social_attributes.k = 'Love' " + "GROUP BY track.id " + "ORDER BY counter DESC " ); break; } From b960be9d971be44779e43a1b92160d565d90c080 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 6 Aug 2011 14:41:35 -0400 Subject: [PATCH 17/17] Get top 60 loved tracks, not 30 --- src/libtomahawk/playlist/customplaylistview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/customplaylistview.cpp b/src/libtomahawk/playlist/customplaylistview.cpp index 4447d6488..e12e34e6e 100644 --- a/src/libtomahawk/playlist/customplaylistview.cpp +++ b/src/libtomahawk/playlist/customplaylistview.cpp @@ -63,7 +63,7 @@ CustomPlaylistView::generateTracks() break; } - DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( sql, DatabaseCommand_GenericSelect::Track, 30, 0 ); + DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( sql, DatabaseCommand_GenericSelect::Track, 60, 0 ); connect( cmd, SIGNAL( tracks( QList ) ), this, SLOT( tracksGenerated( QList ) ) ); Database::instance()->enqueue( QSharedPointer( cmd ) ); }