diff --git a/data/images/back.png b/data/images/back.png new file mode 100644 index 000000000..88db1dc23 Binary files /dev/null and b/data/images/back.png differ diff --git a/data/images/forward.png b/data/images/forward.png new file mode 100644 index 000000000..3e0c42476 Binary files /dev/null and b/data/images/forward.png differ diff --git a/data/images/home.png b/data/images/home.png new file mode 100644 index 000000000..e36f187f6 Binary files /dev/null and b/data/images/home.png differ diff --git a/data/www/auth.html b/data/www/auth.html new file mode 100644 index 000000000..a8aac4c37 --- /dev/null +++ b/data/www/auth.html @@ -0,0 +1,64 @@ + + + + + Allow Tomahawk Access + + + + + Tomahawk - Powered by Playdar + + +
+
+

Allow access to Tomahawk from <%NAME%>

+

+ + +

+ + + + +
+
+ + diff --git a/data/www/auth.na.html b/data/www/auth.na.html new file mode 100644 index 000000000..450a2b114 --- /dev/null +++ b/data/www/auth.na.html @@ -0,0 +1,44 @@ + + + + + Allow Tomahawk Access + + + + + Tomahawk - Powered by Playdar + + +
+

You have allowed access to Tomahawk from <%NAME%>

+

Copy and paste this authentication token into the status bar then close this window.

+

Token: + + diff --git a/data/www/playdar_auth_logo.gif b/data/www/playdar_auth_logo.gif new file mode 100644 index 000000000..22b06bfa3 Binary files /dev/null and b/data/www/playdar_auth_logo.gif differ diff --git a/resources.qrc b/resources.qrc index e1bc45cf5..fc3705795 100644 --- a/resources.qrc +++ b/resources.qrc @@ -70,6 +70,9 @@ ./data/images/volume-slider-level.png ./data/images/echonest_logo.png ./data/images/loading-animation.gif +./data/images/home.png +./data/images/back.png +./data/images/forward.png ./data/topbar-radiobuttons.css ./data/icons/tomahawk-icon-16x16.png ./data/icons/tomahawk-icon-32x32.png @@ -80,5 +83,7 @@ ./data/icons/audio-x-generic-22x22.png ./data/icons/audio-x-generic-32x32.png ./data/icons/audio-x-generic-16x16.png +./data/www/auth.html +./data/www/auth.na.html diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index de0164864..90c3ec204 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -25,6 +25,7 @@ set( libSources query.cpp result.cpp source.cpp + viewpage.cpp sip/SipPlugin.cpp @@ -65,6 +66,8 @@ set( libSources database/databasecommand_loaddynamicplaylist.cpp database/databasecommand_loadalldynamicplaylists.cpp database/databasecommand_deletedynamicplaylist.cpp + database/databasecommand_addclientauth.cpp + database/databasecommand_clientauthvalid.cpp database/database.cpp playlist/collectionmodel.cpp @@ -156,6 +159,7 @@ set( libHeaders resolver.h result.h source.h + viewpage.h artist.h album.h @@ -200,6 +204,8 @@ set( libHeaders database/databasecommand_loaddynamicplaylist.h database/databasecommand_deletedynamicplaylist.h database/databasecommand_loadalldynamicplaylists.h + database/databasecommand_addclientauth.h + database/databasecommand_clientauthvalid.h network/bufferiodevice.h network/msgprocessor.h diff --git a/src/libtomahawk/database/databasecommand_addclientauth.cpp b/src/libtomahawk/database/databasecommand_addclientauth.cpp new file mode 100644 index 000000000..d8e705952 --- /dev/null +++ b/src/libtomahawk/database/databasecommand_addclientauth.cpp @@ -0,0 +1,46 @@ +/**************************************************************************************** + * Copyright (c) 2011 Leo Franchi * + * * + * This program is free software; you can redistribute it and/or modify it under * + * the terms of the GNU General Public License as published by the Free Software * + * Foundation; either version 2 of the License, or (at your option) any later * + * version. * + * * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY * + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along with * + * this program. If not, see . * + ****************************************************************************************/ + +#include "databasecommand_addclientauth.h" + +DatabaseCommand_AddClientAuth::DatabaseCommand_AddClientAuth( const QString& clientToken, + const QString& website, + const QString& name, + const QString& userAgent, + QObject* parent ) + : DatabaseCommand( parent ) + , m_clientToken( clientToken ) + , m_website( website ) + , m_name( name ) + , m_userAgent( userAgent ) +{ +} + +void DatabaseCommand_AddClientAuth::exec(DatabaseImpl* lib) +{ + TomahawkSqlQuery q = lib->newquery(); + q.prepare( "INSERT INTO http_client_auth (token, website, name, ua, mtime, permissions) VALUES (?, ?, ?, ?, ?, ?)" ); + q.addBindValue( m_clientToken ); + q.addBindValue( m_website ); + q.addBindValue( m_name ); + q.addBindValue( m_userAgent ); + q.addBindValue( 0 ); + q.addBindValue( "*" ); + + if( !q.exec() ) { + qWarning() << "Failed to insert http client into auth table!"; + } +} diff --git a/src/libtomahawk/database/databasecommand_addclientauth.h b/src/libtomahawk/database/databasecommand_addclientauth.h new file mode 100644 index 000000000..fccec5947 --- /dev/null +++ b/src/libtomahawk/database/databasecommand_addclientauth.h @@ -0,0 +1,45 @@ +/**************************************************************************************** + * Copyright (c) 2011 Leo Franchi * + * * + * This program is free software; you can redistribute it and/or modify it under * + * the terms of the GNU General Public License as published by the Free Software * + * Foundation; either version 2 of the License, or (at your option) any later * + * version. * + * * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY * + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along with * + * this program. If not, see . * + ****************************************************************************************/ + +#ifndef DATABASECOMMAND_ADDCLIENTAUTH_H +#define DATABASECOMMAND_ADDCLIENTAUTH_H + +#include "databaseimpl.h" +#include "databasecommand.h" +#include "dllmacro.h" + +#include + +class DLLEXPORT DatabaseCommand_AddClientAuth : public DatabaseCommand +{ + Q_OBJECT +public: + explicit DatabaseCommand_AddClientAuth( QObject* parent = 0 ) + : DatabaseCommand( parent ) + {} + + explicit DatabaseCommand_AddClientAuth( const QString& clientToken, const QString& website, const QString& name, const QString& userAgent, QObject* parent = 0 ); + + QString commandname() const { return "addclientauth"; } + + virtual void exec( DatabaseImpl* lib ); + virtual bool doesMutates() const { return true; } + +private: + QString m_clientToken, m_website, m_name, m_userAgent; +}; + +#endif // DATABASECOMMAND_ADDCLIENTAUTH_H diff --git a/src/libtomahawk/database/databasecommand_clientauthvalid.cpp b/src/libtomahawk/database/databasecommand_clientauthvalid.cpp new file mode 100644 index 000000000..e751748bf --- /dev/null +++ b/src/libtomahawk/database/databasecommand_clientauthvalid.cpp @@ -0,0 +1,42 @@ +/**************************************************************************************** + * Copyright (c) 2011 Leo Franchi * + * * + * This program is free software; you can redistribute it and/or modify it under * + * the terms of the GNU General Public License as published by the Free Software * + * Foundation; either version 2 of the License, or (at your option) any later * + * version. * + * * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY * + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along with * + * this program. If not, see . * + ****************************************************************************************/ + +#include "databasecommand_clientauthvalid.h" + +DatabaseCommand_ClientAuthValid::DatabaseCommand_ClientAuthValid( const QString& clientToken, QObject* parent ) + : DatabaseCommand( parent ) + , m_clientToken( clientToken ) +{ + +} + +void DatabaseCommand_ClientAuthValid::exec(DatabaseImpl* lib) +{ + TomahawkSqlQuery q = lib->newquery(); + q.prepare( "SELECT name FROM http_client_auth WHERE token = ?" ); + q.addBindValue( m_clientToken ); + + if( q.exec() ) { + if( q.next() ) { + QString name = q.value( 0 ).toString(); + emit authValid( m_clientToken, name, true ); + } else { + emit authValid( m_clientToken, QString(), false ); + } + } else { + qWarning() << "Failed to query http auth table for client:" << m_clientToken; + } +} diff --git a/src/libtomahawk/database/databasecommand_clientauthvalid.h b/src/libtomahawk/database/databasecommand_clientauthvalid.h new file mode 100644 index 000000000..efb3c7bb1 --- /dev/null +++ b/src/libtomahawk/database/databasecommand_clientauthvalid.h @@ -0,0 +1,49 @@ +/**************************************************************************************** + * Copyright (c) 2011 Leo Franchi * + * * + * This program is free software; you can redistribute it and/or modify it under * + * the terms of the GNU General Public License as published by the Free Software * + * Foundation; either version 2 of the License, or (at your option) any later * + * version. * + * * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY * + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along with * + * this program. If not, see . * + ****************************************************************************************/ + +#ifndef DATABASECOMMAND_CLIENTAUTHVALID_H +#define DATABASECOMMAND_CLIENTAUTHVALID_H + +#include "databaseimpl.h" +#include "databasecommand.h" +#include "dllmacro.h" + +#include + +class DLLEXPORT DatabaseCommand_ClientAuthValid : public DatabaseCommand +{ + Q_OBJECT +public: + explicit DatabaseCommand_ClientAuthValid( QObject* parent = 0 ) + : DatabaseCommand( parent ) + {} + + explicit DatabaseCommand_ClientAuthValid( const QString& clientToken, QObject* parent = 0 ); + + QString commandname() const { return "clientauthvalid"; } + + virtual void exec( DatabaseImpl* lib ); + virtual bool doesMutates() const { return false; } + +signals: + // if auth is invalid name is empty + void authValid( const QString& clientToken, const QString& name, bool valid ); + +private: + QString m_clientToken; +}; + +#endif // DATABASECOMMAND_CLIENTAUTHVALID_H diff --git a/src/libtomahawk/database/databaseimpl.cpp b/src/libtomahawk/database/databaseimpl.cpp index 7746f8a0f..5652dfae8 100644 --- a/src/libtomahawk/database/databaseimpl.cpp +++ b/src/libtomahawk/database/databaseimpl.cpp @@ -16,8 +16,7 @@ */ #include "schema.sql.h" -#define CURRENT_SCHEMA_VERSION 20 - +#define CURRENT_SCHEMA_VERSION 21 DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) : QObject( (QObject*) parent ) diff --git a/src/libtomahawk/database/schema.sql b/src/libtomahawk/database/schema.sql index ad8b000d1..c30132ab9 100644 --- a/src/libtomahawk/database/schema.sql +++ b/src/libtomahawk/database/schema.sql @@ -241,6 +241,16 @@ CREATE TABLE IF NOT EXISTS playback_log ( CREATE INDEX playback_log_source ON playback_log(source); CREATE INDEX playback_log_track ON playback_log(track); +-- auth information for http clients + +CREATE TABLE IF NOT EXISTS http_client_auth ( + token TEXT NOT NULL PRIMARY KEY, + website TEXT NOT NULL, + name TEXT NOT NULL, + ua TEXT, + mtime INTEGER, + permissions TEXT NOT NULL +); -- Schema version, and misc tomahawk settings relating to the collection db @@ -250,4 +260,4 @@ CREATE TABLE IF NOT EXISTS settings ( v TEXT NOT NULL DEFAULT '' ); -INSERT INTO settings(k,v) VALUES('schema_version', '20'); +INSERT INTO settings(k,v) VALUES('schema_version', '21'); diff --git a/src/libtomahawk/database/schema.sql.h b/src/libtomahawk/database/schema.sql.h index a580c1851..9283091f3 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 Wed Feb 23 12:39:07 CET 2011. + This file was automatically generated from schema.sql on Thu Feb 24 19:05:46 EST 2011. */ static const char * tomahawk_schema_sql = @@ -161,11 +161,19 @@ static const char * tomahawk_schema_sql = ");" "CREATE INDEX playback_log_source ON playback_log(source);" "CREATE INDEX playback_log_track ON playback_log(track);" +"CREATE TABLE IF NOT EXISTS http_client_auth (" +" token TEXT NOT NULL PRIMARY KEY," +" website TEXT NOT NULL," +" name TEXT NOT NULL," +" ua TEXT," +" mtime INTEGER," +" permissions TEXT NOT NULL" +");" "CREATE TABLE IF NOT EXISTS settings (" " k TEXT NOT NULL PRIMARY KEY," " v TEXT NOT NULL DEFAULT ''" ");" -"INSERT INTO settings(k,v) VALUES('schema_version', '20');" +"INSERT INTO settings(k,v) VALUES('schema_version', '21');" ; const char * get_tomahawk_sql() diff --git a/src/libtomahawk/network/controlconnection.cpp b/src/libtomahawk/network/controlconnection.cpp index d2cf61004..cb7fcb647 100644 --- a/src/libtomahawk/network/controlconnection.cpp +++ b/src/libtomahawk/network/controlconnection.cpp @@ -104,7 +104,7 @@ ControlConnection::registerSource() void ControlConnection::setupDbSyncConnection( bool ondemand ) { - if( m_dbsyncconn != NULL || ! m_registered ) + if( m_dbsyncconn != NULL || !m_registered ) return; qDebug() << Q_FUNC_INFO << ondemand << m_source->id(); @@ -115,12 +115,6 @@ ControlConnection::setupDbSyncConnection( bool ondemand ) qDebug() << "Connecting to DBSync offer from peer..."; m_dbsyncconn = new DBSyncConnection( m_servent, m_source ); - connect( m_dbsyncconn, SIGNAL( finished() ), - m_dbsyncconn, SLOT( deleteLater() ) ); - - connect( m_dbsyncconn, SIGNAL( destroyed( QObject* ) ), - SLOT( dbSyncConnFinished( QObject* ) ), Qt::DirectConnection ); - m_servent->createParallelConnection( this, m_dbsyncconn, m_dbconnkey ); m_dbconnkey.clear(); } @@ -129,12 +123,6 @@ ControlConnection::setupDbSyncConnection( bool ondemand ) qDebug() << "Offering a DBSync key to peer..."; m_dbsyncconn = new DBSyncConnection( m_servent, m_source ); - connect( m_dbsyncconn, SIGNAL( finished() ), - m_dbsyncconn, SLOT( deleteLater()) ); - - connect( m_dbsyncconn, SIGNAL( destroyed(QObject* ) ), - SLOT( dbSyncConnFinished( QObject* ) ), Qt::DirectConnection ); - QString key = uuid(); m_servent->registerOffer( key, m_dbsyncconn ); QVariantMap m; @@ -142,6 +130,12 @@ ControlConnection::setupDbSyncConnection( bool ondemand ) m.insert( "key", key ); sendMsg( m ); } + + connect( m_dbsyncconn, SIGNAL( finished() ), + m_dbsyncconn, SLOT( deleteLater() ) ); + + connect( m_dbsyncconn, SIGNAL( destroyed( QObject* ) ), + SLOT( dbSyncConnFinished( QObject* ) ), Qt::DirectConnection ); } diff --git a/src/libtomahawk/network/dbsyncconnection.cpp b/src/libtomahawk/network/dbsyncconnection.cpp index 3172a5252..334fe86d9 100644 --- a/src/libtomahawk/network/dbsyncconnection.cpp +++ b/src/libtomahawk/network/dbsyncconnection.cpp @@ -92,7 +92,7 @@ DBSyncConnection::trigger() qDebug() << Q_FUNC_INFO; // if we're still setting up the connection, do nothing - we sync on first connect anyway: - if ( !this->isRunning() ) + if ( !isRunning() ) return; QMetaObject::invokeMethod( this, "sendMsg", Qt::QueuedConnection, @@ -195,7 +195,7 @@ DBSyncConnection::handleMsg( msg_ptr msg ) QVariantMap m = msg->json().toMap(); if ( m.empty() ) { - qDebug() << "Failed to parse msg in dbsync"; + qDebug() << "Failed to parse msg in dbsync" << m_source->id() << m_source->friendlyName(); Q_ASSERT( false ); return; } diff --git a/src/libtomahawk/network/servent.cpp b/src/libtomahawk/network/servent.cpp index e3eb71a9e..24407f087 100644 --- a/src/libtomahawk/network/servent.cpp +++ b/src/libtomahawk/network/servent.cpp @@ -707,8 +707,8 @@ Servent::triggerDBSync() QList sources = SourceList::instance()->sources(); foreach( const source_ptr& src, sources ) { - // local src doesnt have a control connection, skip it: - if( src.isNull() || src->isLocal() ) + // skip local source + if ( src.isNull() || src->isLocal() ) continue; if ( src->controlConnection() ) // source online? diff --git a/src/libtomahawk/playlist/albummodel.cpp b/src/libtomahawk/playlist/albummodel.cpp index f22d389d8..fbbad77bd 100644 --- a/src/libtomahawk/playlist/albummodel.cpp +++ b/src/libtomahawk/playlist/albummodel.cpp @@ -225,6 +225,8 @@ AlbumModel::addCollection( const collection_ptr& collection ) SLOT( onAlbumsAdded( QList, Tomahawk::collection_ptr ) ) ); Database::instance()->enqueue( QSharedPointer( cmd ) ); + + m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() ); } @@ -245,6 +247,8 @@ AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned in SLOT( onAlbumsAdded( QList, Tomahawk::collection_ptr ) ) ); Database::instance()->enqueue( QSharedPointer( cmd ) ); + + m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() ); } diff --git a/src/libtomahawk/playlist/albummodel.h b/src/libtomahawk/playlist/albummodel.h index 445538b86..f25724ad4 100644 --- a/src/libtomahawk/playlist/albummodel.h +++ b/src/libtomahawk/playlist/albummodel.h @@ -40,9 +40,6 @@ public: virtual void removeIndex( const QModelIndex& index ); virtual void removeIndexes( const QList& indexes ); - virtual PlaylistInterface::RepeatMode repeatMode() const { return PlaylistInterface::NoRepeat; } - virtual bool shuffled() const { return false; } - virtual QMimeData* mimeData( const QModelIndexList& indexes ) const; virtual QStringList mimeTypes() const; virtual Qt::ItemFlags flags( const QModelIndex& index ) const; @@ -50,6 +47,11 @@ public: void addCollection( const Tomahawk::collection_ptr& collection ); void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllAlbums::SortOrder order ); + virtual QString title() const { return m_title; } + virtual QString description() const { return m_description; } + virtual void setTitle( const QString& title ) { m_title = title; } + virtual void setDescription( const QString& description ) { m_description = description; } + AlbumItem* itemFromIndex( const QModelIndex& index ) const { if ( index.isValid() ) @@ -81,6 +83,9 @@ private: QPersistentModelIndex m_currentIndex; AlbumItem* m_rootItem; QPixmap m_defaultCover; + + QString m_title; + QString m_description; }; #endif // ALBUMMODEL_H diff --git a/src/libtomahawk/playlist/albumproxymodel.h b/src/libtomahawk/playlist/albumproxymodel.h index d87c855db..3e694e2a6 100644 --- a/src/libtomahawk/playlist/albumproxymodel.h +++ b/src/libtomahawk/playlist/albumproxymodel.h @@ -33,7 +33,8 @@ public: virtual PlaylistInterface::RepeatMode repeatMode() const { return m_repeatMode; } virtual bool shuffled() const { return m_shuffled; } - + virtual PlaylistInterface::ViewMode viewMode() const { return PlaylistInterface::Album; } + signals: void repeatModeChanged( PlaylistInterface::RepeatMode mode ); void shuffleModeChanged( bool enabled ); diff --git a/src/libtomahawk/playlist/albumview.cpp b/src/libtomahawk/playlist/albumview.cpp index 9e954cc7f..83ecb28b9 100644 --- a/src/libtomahawk/playlist/albumview.cpp +++ b/src/libtomahawk/playlist/albumview.cpp @@ -10,8 +10,6 @@ #include "tomahawksettings.h" #include "albumitemdelegate.h" -#include "albummodel.h" -#include "albumproxymodel.h" #include "playlistmanager.h" using namespace Tomahawk; diff --git a/src/libtomahawk/playlist/albumview.h b/src/libtomahawk/playlist/albumview.h index a2445971f..d4616cd3c 100644 --- a/src/libtomahawk/playlist/albumview.h +++ b/src/libtomahawk/playlist/albumview.h @@ -4,12 +4,13 @@ #include #include +#include "albummodel.h" +#include "albumproxymodel.h" +#include "viewpage.h" + #include "dllmacro.h" -class AlbumModel; -class AlbumProxyModel; - -class DLLEXPORT AlbumView : public QListView +class DLLEXPORT AlbumView : public QListView, public Tomahawk::ViewPage { Q_OBJECT @@ -19,12 +20,22 @@ public: void setProxyModel( AlbumProxyModel* model ); - AlbumModel* model() { return m_model; } - AlbumProxyModel* proxyModel() { return m_proxyModel; } + AlbumModel* model() const { return m_model; } + AlbumProxyModel* proxyModel() const { return m_proxyModel; } // PlaylistItemDelegate* delegate() { return m_delegate; } void setModel( AlbumModel* model ); + virtual QWidget* widget() { return this; } + virtual PlaylistInterface* playlistInterface() const { return proxyModel(); } + + virtual QString title() const { return m_model->title(); } + virtual QString description() const { return m_model->description(); } + + virtual bool showModes() const { return true; } + + virtual bool jumpToCurrentTrack() { return false; } + public slots: void onItemActivated( const QModelIndex& index ); diff --git a/src/libtomahawk/playlist/collectionflatmodel.cpp b/src/libtomahawk/playlist/collectionflatmodel.cpp index 54c4bdc04..6e63feeba 100644 --- a/src/libtomahawk/playlist/collectionflatmodel.cpp +++ b/src/libtomahawk/playlist/collectionflatmodel.cpp @@ -60,6 +60,11 @@ CollectionFlatModel::addCollection( const collection_ptr& collection ) SLOT( onTracksAdded( QList, Tomahawk::collection_ptr ) ) ); connect( collection.data(), SIGNAL( tracksFinished( Tomahawk::collection_ptr ) ), SLOT( onTracksAddingFinished( Tomahawk::collection_ptr ) ) ); + + if ( collection->source()->isLocal() ) + setTitle( tr( "Your Collection" ) ); + else + setTitle( tr( "Collection of %1" ).arg( collection->source()->friendlyName() ) ); } diff --git a/src/libtomahawk/playlist/collectionproxymodel.h b/src/libtomahawk/playlist/collectionproxymodel.h index e6ea9311d..af46be8c4 100644 --- a/src/libtomahawk/playlist/collectionproxymodel.h +++ b/src/libtomahawk/playlist/collectionproxymodel.h @@ -12,6 +12,8 @@ Q_OBJECT public: explicit CollectionProxyModel( QObject* parent = 0 ); + virtual PlaylistInterface::ViewMode viewMode() const { return PlaylistInterface::Flat; } + protected: bool lessThan( const QModelIndex& left, const QModelIndex& right ) const; }; diff --git a/src/libtomahawk/playlist/collectionview.cpp b/src/libtomahawk/playlist/collectionview.cpp index dc1490595..09b557611 100644 --- a/src/libtomahawk/playlist/collectionview.cpp +++ b/src/libtomahawk/playlist/collectionview.cpp @@ -45,7 +45,6 @@ CollectionView::setModel( TrackModel* model ) void CollectionView::dragEnterEvent( QDragEnterEvent* event ) { - qDebug() << Q_FUNC_INFO; event->ignore(); } @@ -94,3 +93,10 @@ CollectionView::onTrackCountChanged( unsigned int tracks ) else overlay()->hide(); } + + +bool +CollectionView::jumpToCurrentTrack() +{ + scrollTo( proxyModel()->currentItem(), QAbstractItemView::PositionAtCenter ); +} diff --git a/src/libtomahawk/playlist/collectionview.h b/src/libtomahawk/playlist/collectionview.h index 9fd3f3483..cddd1e98c 100644 --- a/src/libtomahawk/playlist/collectionview.h +++ b/src/libtomahawk/playlist/collectionview.h @@ -3,11 +3,14 @@ #include +#include "trackproxymodel.h" +#include "trackmodel.h" #include "trackview.h" +#include "viewpage.h" #include "dllmacro.h" -class DLLEXPORT CollectionView : public TrackView +class DLLEXPORT CollectionView : public TrackView, public Tomahawk::ViewPage { Q_OBJECT @@ -17,6 +20,16 @@ public: virtual void setModel( TrackModel* model ); + virtual QWidget* widget() { return this; } + virtual PlaylistInterface* playlistInterface() const { return proxyModel(); } + + virtual QString title() const { return model()->title(); } + virtual QString description() const { return model()->description(); } + + virtual bool showModes() const { return true; } + + virtual bool jumpToCurrentTrack(); + private slots: void onCustomContextMenu( const QPoint& pos ); void onTrackCountChanged( unsigned int tracks ); diff --git a/src/libtomahawk/playlist/dynamic/DynamicView.h b/src/libtomahawk/playlist/dynamic/DynamicView.h index d7ad8103e..26a63e4f1 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicView.h +++ b/src/libtomahawk/playlist/dynamic/DynamicView.h @@ -45,7 +45,7 @@ public: void setDynamicWorking( bool working ); - virtual void paintEvent(QPaintEvent* event); + virtual void paintEvent( QPaintEvent* event ); public slots: void showMessageTimeout( const QString& title, const QString& body ); diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp index 8bea35d94..20ec27727 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp @@ -386,3 +386,9 @@ DynamicWidget::paintRoundedFilledRect( QPainter& p, QPalette& pal, QRect& r, qre p.setPen( pen ); p.drawRoundedRect( r, 10, 10 ); } + +bool +DynamicWidget::jumpToCurrentTrack() +{ + m_view->scrollTo( m_view->proxyModel()->currentItem(), QAbstractItemView::PositionAtCenter ); +} diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h index 17d31d882..e8653b2b7 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h @@ -20,8 +20,11 @@ #include #include "typedefs.h" +#include "viewpage.h" + #include "dynamic/DynamicPlaylist.h" #include "dynamic/DynamicControl.h" +#include "dynamic/DynamicModel.h" class LoadingSpinner; class QShowEvent; @@ -43,20 +46,15 @@ namespace Tomahawk class DynamicSetupWidget; - -class DynamicModel; - - class DynamicView; - class CollapsibleControls; /** * This class contains the dynamic playlist config and the playlist view itself */ -class DynamicWidget : public QWidget +class DynamicWidget : public QWidget, public Tomahawk::ViewPage { Q_OBJECT public: @@ -65,7 +63,7 @@ public: void loadDynamicPlaylist( const dynplaylist_ptr& playlist ); - PlaylistInterface* playlistInterface() const; + virtual PlaylistInterface* playlistInterface() const; virtual QSize sizeHint() const; virtual void resizeEvent( QResizeEvent* ); @@ -73,6 +71,14 @@ public: virtual void showEvent(QShowEvent* ); static void paintRoundedFilledRect( QPainter& p, QPalette& pal, QRect& r, qreal opacity = .95 ); + + virtual QWidget* widget() { return this; } + + virtual QString title() const { return m_model->title(); } + virtual QString description() const { return m_model->description(); } + + virtual bool jumpToCurrentTrack(); + public slots: void onRevisionLoaded( const Tomahawk::DynamicPlaylistRevision& rev ); void playlistTypeChanged(QString); @@ -94,6 +100,7 @@ private slots: void controlChanged( const Tomahawk::dyncontrol_ptr& control ); void layoutFloatingWidgets(); + private: dynplaylist_ptr m_playlist; QVBoxLayout* m_layout; diff --git a/src/libtomahawk/playlist/infobar/infobar.cpp b/src/libtomahawk/playlist/infobar/infobar.cpp index bb2121e09..8ebd5893f 100644 --- a/src/libtomahawk/playlist/infobar/infobar.cpp +++ b/src/libtomahawk/playlist/infobar/infobar.cpp @@ -7,6 +7,8 @@ #include "utils/tomahawkutils.h" +#define IMAGE_HEIGHT 64 + InfoBar::InfoBar( QWidget* parent ) : QWidget( parent ) @@ -58,7 +60,7 @@ InfoBar::setDescription( const QString& s ) void InfoBar::setPixmap( const QPixmap& p ) { - ui->imageLabel->setPixmap( p.scaledToHeight( ui->imageLabel->height(), Qt::SmoothTransformation ) ); + ui->imageLabel->setPixmap( p.scaledToHeight( IMAGE_HEIGHT, Qt::SmoothTransformation ) ); } diff --git a/src/libtomahawk/playlist/playlistmanager.cpp b/src/libtomahawk/playlist/playlistmanager.cpp index 6b5fac73a..7eceac460 100644 --- a/src/libtomahawk/playlist/playlistmanager.cpp +++ b/src/libtomahawk/playlist/playlistmanager.cpp @@ -7,6 +7,7 @@ #include "infobar/infobar.h" #include "topbar/topbar.h" #include "widgets/infowidgets/sourceinfowidget.h" +#include "widgets/welcomewidget.h" #include "collectionmodel.h" #include "collectionflatmodel.h" @@ -29,6 +30,8 @@ #define FILTER_TIMEOUT 280 +using namespace Tomahawk; + PlaylistManager* PlaylistManager::s_instance = 0; @@ -42,14 +45,13 @@ PlaylistManager::instance() PlaylistManager::PlaylistManager( QObject* parent ) : QObject( parent ) , m_widget( new QWidget() ) - , m_currentInterface( 0 ) + , m_welcomeWidget( new WelcomeWidget() ) , m_currentMode( 0 ) , m_superCollectionVisible( true ) - , m_statsAvailable( false ) - , m_modesAvailable( false ) { s_instance = this; + setHistoryPosition( -1 ); m_widget->setLayout( new QVBoxLayout() ); m_topbar = new TopBar(); @@ -89,49 +91,28 @@ PlaylistManager::PlaylistManager( QObject* parent ) m_superAlbumView = new AlbumView(); m_superAlbumModel = new AlbumModel( m_superAlbumView ); m_superAlbumView->setModel( m_superAlbumModel ); - - m_stack->addWidget( m_superCollectionView ); - m_stack->addWidget( m_superAlbumView ); - - m_currentInterface = m_superCollectionView->proxyModel(); + m_superAlbumView->setFrameShape( QFrame::NoFrame ); + m_superAlbumView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); m_stack->setContentsMargins( 0, 0, 0, 0 ); m_widget->setContentsMargins( 0, 0, 0, 0 ); m_widget->layout()->setContentsMargins( 0, 0, 0, 0 ); m_widget->layout()->setMargin( 0 ); m_widget->layout()->setSpacing( 0 ); - + connect( &m_filterTimer, SIGNAL( timeout() ), SLOT( applyFilter() ) ); connect( m_topbar, SIGNAL( filterTextChanged( QString ) ), - this, SLOT( setFilter( QString ) ) ); - - connect( this, SIGNAL( numSourcesChanged( unsigned int ) ), - m_topbar, SLOT( setNumSources( unsigned int ) ) ); - - connect( this, SIGNAL( numTracksChanged( unsigned int ) ), - m_topbar, SLOT( setNumTracks( unsigned int ) ) ); - - connect( this, SIGNAL( numArtistsChanged( unsigned int ) ), - m_topbar, SLOT( setNumArtists( unsigned int ) ) ); - - connect( this, SIGNAL( numShownChanged( unsigned int ) ), - m_topbar, SLOT( setNumShown( unsigned int ) ) ); + SLOT( setFilter( QString ) ) ); connect( m_topbar, SIGNAL( flatMode() ), - this, SLOT( setTableMode() ) ); - + SLOT( setTableMode() ) ); + connect( m_topbar, SIGNAL( artistMode() ), - this, SLOT( setTreeMode() ) ); - + SLOT( setTreeMode() ) ); + connect( m_topbar, SIGNAL( albumMode() ), - this, SLOT( setAlbumMode() ) ); - - connect( this, SIGNAL( statsAvailable( bool ) ), - m_topbar, SLOT( setStatsVisible( bool ) ) ); - - connect( this, SIGNAL( modesAvailable( bool ) ), - m_topbar, SLOT( setModesVisible( bool ) ) ); + SLOT( setAlbumMode() ) ); } @@ -151,11 +132,10 @@ PlaylistManager::queue() const bool PlaylistManager::show( const Tomahawk::playlist_ptr& playlist ) { - unlinkPlaylist(); - + PlaylistView* view; if ( !m_playlistViews.contains( playlist ) ) { - PlaylistView* view = new PlaylistView(); + view = new PlaylistView(); PlaylistModel* model = new PlaylistModel(); view->setModel( model ); view->setFrameShape( QFrame::NoFrame ); @@ -163,27 +143,15 @@ PlaylistManager::show( const Tomahawk::playlist_ptr& playlist ) model->loadPlaylist( playlist ); playlist->resolve(); - m_currentInterface = view->proxyModel(); m_playlistViews.insert( playlist, view ); - - m_stack->addWidget( view ); - m_stack->setCurrentWidget( view ); } else { - PlaylistView* view = m_playlistViews.value( playlist ); - m_stack->setCurrentWidget( view ); - m_currentInterface = view->proxyModel(); + view = m_playlistViews.value( playlist ); } - m_queueView->show(); - m_infobar->setCaption( playlist->title() ); - m_infobar->setDescription( tr( "A playlist by %1" ).arg( playlist->author()->isLocal() ? tr( "you" ) : playlist->author()->friendlyName() ) ); - + setPage( view ); m_superCollectionVisible = false; - m_statsAvailable = true; - m_modesAvailable = false; - linkPlaylist(); TomahawkSettings::instance()->appendRecentlyPlayedPlaylist( playlist ); @@ -195,34 +163,25 @@ PlaylistManager::show( const Tomahawk::playlist_ptr& playlist ) bool PlaylistManager::show( const Tomahawk::dynplaylist_ptr& playlist ) { - unlinkPlaylist(); - - if( !m_dynamicWidgets.contains( playlist ) ) + if ( !m_dynamicWidgets.contains( playlist ) ) { m_dynamicWidgets[ playlist ] = new Tomahawk::DynamicWidget( playlist, m_stack ); - m_stack->addWidget( m_dynamicWidgets[ playlist ] ); + playlist->resolve(); } - m_stack->setCurrentWidget( m_dynamicWidgets.value( playlist ) ); - m_currentInterface = m_dynamicWidgets.value( playlist )->playlistInterface(); + setPage( m_dynamicWidgets.value( playlist ) ); - m_infobar->setCaption( playlist->title() ); - m_infobar->setDescription( tr( "A playlist by %1" ).arg( playlist->author()->isLocal() ? tr( "you" ) : playlist->author()->friendlyName() ) ); - - if( playlist->mode() == Tomahawk::OnDemand ) + if ( playlist->mode() == Tomahawk::OnDemand ) m_queueView->hide(); - + else + m_queueView->show(); m_superCollectionVisible = false; - m_statsAvailable = true; - m_modesAvailable = false; - linkPlaylist(); TomahawkSettings::instance()->appendRecentlyPlayedPlaylist( playlist ); emit numSourcesChanged( SourceList::instance()->count() ); - return true; } @@ -230,39 +189,26 @@ PlaylistManager::show( const Tomahawk::dynplaylist_ptr& playlist ) bool PlaylistManager::show( const Tomahawk::artist_ptr& artist ) { - qDebug() << Q_FUNC_INFO << &artist << artist.data(); - unlinkPlaylist(); + PlaylistView* view; if ( !m_artistViews.contains( artist ) ) { - PlaylistView* view = new PlaylistView(); + view = new PlaylistView(); PlaylistModel* model = new PlaylistModel(); view->setModel( model ); view->setFrameShape( QFrame::NoFrame ); view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); model->append( artist ); - m_currentInterface = view->proxyModel(); m_artistViews.insert( artist, view ); - - m_stack->addWidget( view ); - m_stack->setCurrentWidget( view ); } else { - PlaylistView* view = m_artistViews.value( artist ); - m_stack->setCurrentWidget( view ); - m_currentInterface = view->proxyModel(); + view = m_artistViews.value( artist ); } - m_queueView->show(); - m_infobar->setCaption( tr( "All tracks by %1" ).arg( artist->name() ) ); - m_infobar->setDescription( "" ); - + setPage( view ); m_superCollectionVisible = false; - m_statsAvailable = false; - m_modesAvailable = false; - linkPlaylist(); emit numSourcesChanged( 1 ); return true; @@ -272,39 +218,25 @@ PlaylistManager::show( const Tomahawk::artist_ptr& artist ) bool PlaylistManager::show( const Tomahawk::album_ptr& album ) { - qDebug() << Q_FUNC_INFO << &album << album.data(); - unlinkPlaylist(); - + PlaylistView* view; if ( !m_albumViews.contains( album ) ) { - PlaylistView* view = new PlaylistView(); + view = new PlaylistView(); PlaylistModel* model = new PlaylistModel(); view->setModel( model ); view->setFrameShape( QFrame::NoFrame ); view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); model->append( album ); - m_currentInterface = view->proxyModel(); m_albumViews.insert( album, view ); - - m_stack->addWidget( view ); - m_stack->setCurrentWidget( view ); } else { - PlaylistView* view = m_albumViews.value( album ); - m_stack->setCurrentWidget( view ); - m_currentInterface = view->proxyModel(); + view = m_albumViews.value( album ); } - m_queueView->show(); - m_infobar->setCaption( tr( "All tracks on %1 by %2" ).arg( album->name() ).arg( album->artist()->name() ) ); - m_infobar->setDescription( "" ); - + setPage( view ); m_superCollectionVisible = false; - m_statsAvailable = false; - m_modesAvailable = false; - linkPlaylist(); emit numSourcesChanged( 1 ); return true; @@ -314,70 +246,52 @@ PlaylistManager::show( const Tomahawk::album_ptr& album ) bool PlaylistManager::show( const Tomahawk::collection_ptr& collection ) { - unlinkPlaylist(); - m_currentCollection = collection; if ( m_currentMode == 0 ) { + CollectionView* view; if ( !m_collectionViews.contains( collection ) ) { - CollectionView* view = new CollectionView(); + view = new CollectionView(); CollectionFlatModel* model = new CollectionFlatModel(); view->setModel( model ); view->setFrameShape( QFrame::NoFrame ); view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); model->addCollection( collection ); - m_currentInterface = view->proxyModel(); m_collectionViews.insert( collection, view ); - - m_stack->addWidget( view ); - m_stack->setCurrentWidget( view ); } else { - CollectionView* view = m_collectionViews.value( collection ); - m_stack->setCurrentWidget( view ); - m_currentInterface = view->proxyModel(); + view = m_collectionViews.value( collection ); } + + setPage( view ); } if ( m_currentMode == 2 ) { + AlbumView* aview; if ( !m_collectionAlbumViews.contains( collection ) ) { - AlbumView* aview = new AlbumView(); + aview = new AlbumView(); AlbumModel* amodel = new AlbumModel( aview ); aview->setModel( amodel ); aview->setFrameShape( QFrame::NoFrame ); aview->setAttribute( Qt::WA_MacShowFocusRect, 0 ); amodel->addCollection( collection ); - m_currentInterface = aview->proxyModel(); m_collectionAlbumViews.insert( collection, aview ); - - m_stack->addWidget( aview ); - m_stack->setCurrentWidget( aview ); } else { - AlbumView* view = m_collectionAlbumViews.value( collection ); - m_stack->setCurrentWidget( view ); - m_currentInterface = view->proxyModel(); + aview = m_collectionAlbumViews.value( collection ); } + + setPage( aview ); } - m_infobar->setDescription( "" ); - if ( collection->source()->isLocal() ) - m_infobar->setCaption( tr( "Your Collection" ) ); - else - m_infobar->setCaption( tr( "Collection of %1" ).arg( collection->source()->friendlyName() ) ); - - m_queueView->show(); m_superCollectionVisible = false; - m_statsAvailable = ( m_currentMode == 0 ); - m_modesAvailable = true; - linkPlaylist(); emit numSourcesChanged( 1 ); return true; @@ -387,32 +301,19 @@ PlaylistManager::show( const Tomahawk::collection_ptr& collection ) bool PlaylistManager::show( const Tomahawk::source_ptr& source ) { - unlinkPlaylist(); - - m_currentInterface = 0; - + SourceInfoWidget* swidget; if ( !m_sourceViews.contains( source ) ) { - SourceInfoWidget* swidget = new SourceInfoWidget( source ); - m_currentInfoWidget = swidget; - m_stack->addWidget( m_currentInfoWidget ); + swidget = new SourceInfoWidget( source ); m_sourceViews.insert( source, swidget ); } else { - m_currentInfoWidget = m_sourceViews.value( source ); + swidget = m_sourceViews.value( source ); } - m_infobar->setCaption( tr( "Info about %1" ).arg( source->isLocal() ? tr( "Your Collection" ) : source->friendlyName() ) ); - m_infobar->setDescription( "" ); - - m_queueView->show(); - m_stack->setCurrentWidget( m_currentInfoWidget ); + setPage( swidget ); m_superCollectionVisible = false; - m_statsAvailable = false; - m_modesAvailable = false; - - linkPlaylist(); emit numSourcesChanged( 1 ); return true; @@ -420,26 +321,15 @@ PlaylistManager::show( const Tomahawk::source_ptr& source ) bool -PlaylistManager::show( QWidget* widget, const QString& title, const QString& desc, const QPixmap& pixmap ) +PlaylistManager::show( ViewPage* page ) { - unlinkPlaylist(); + if ( m_stack->indexOf( page->widget() ) < 0 ) + { + connect( page->widget(), SIGNAL( destroyed( QWidget* ) ), SLOT( onWidgetDestroyed( QWidget* ) ) ); + } - connect( widget, SIGNAL( destroyed( QWidget* ) ), SLOT( onWidgetDestroyed( QWidget* ) ) ); - - m_stack->addWidget( widget ); - m_stack->setCurrentWidget( widget ); - - m_infobar->setCaption( title ); - m_infobar->setDescription( desc ); - m_infobar->setPixmap( pixmap ); - - m_queueView->show(); + setPage( page ); m_superCollectionVisible = false; - m_statsAvailable = false; - m_modesAvailable = false; - m_currentInterface = 0; - - linkPlaylist(); return true; } @@ -456,33 +346,34 @@ PlaylistManager::showSuperCollection() m_superCollectionFlatModel->addCollection( source->collection() ); m_superAlbumModel->addCollection( source->collection() ); } + + m_superCollectionFlatModel->setTitle( tr( "All available tracks" ) ); + m_superAlbumModel->setTitle( tr( "All available albums" ) ); } if ( m_currentMode == 0 ) { - m_stack->setCurrentWidget( m_superCollectionView ); - m_currentInterface = m_superCollectionView->proxyModel(); + setPage( m_superCollectionView ); } else if ( m_currentMode == 2 ) { - m_stack->setCurrentWidget( m_superAlbumView ); - m_currentInterface = m_superAlbumView->proxyModel(); + setPage( m_superAlbumView ); } - m_infobar->setCaption( tr( "Super Collection" ) ); - m_infobar->setDescription( tr( "All available tracks" ) ); - - m_queueView->show(); m_superCollectionVisible = true; - m_statsAvailable = ( m_currentMode == 0 ); - m_modesAvailable = true; - linkPlaylist(); emit numSourcesChanged( m_superCollections.count() ); return true; } +void +PlaylistManager::showWelcomePage() +{ + show( m_welcomeWidget ); +} + + void PlaylistManager::setTableMode() { @@ -533,8 +424,7 @@ PlaylistManager::showQueue() if ( QThread::currentThread() != thread() ) { qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO; - QMetaObject::invokeMethod( this, "showQueue", - Qt::QueuedConnection ); + QMetaObject::invokeMethod( this, "showQueue", Qt::QueuedConnection ); return; } @@ -548,8 +438,7 @@ PlaylistManager::hideQueue() if ( QThread::currentThread() != thread() ) { qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO; - QMetaObject::invokeMethod( this, "hideQueue", - Qt::QueuedConnection ); + QMetaObject::invokeMethod( this, "hideQueue", Qt::QueuedConnection ); return; } @@ -557,6 +446,42 @@ PlaylistManager::hideQueue() } +void +PlaylistManager::historyBack() +{ + if ( m_historyPosition < 1 ) + return; + + showHistory( m_historyPosition - 1 ); +} + + +void +PlaylistManager::historyForward() +{ + if ( m_historyPosition >= m_pageHistory.count() - 1 ) + return; + + showHistory( m_historyPosition + 1 ); +} + + +void +PlaylistManager::showHistory( int historyPosition ) +{ + if ( historyPosition < 0 || historyPosition >= m_pageHistory.count() ) + { + qDebug() << "History position out of bounds!" << historyPosition << m_pageHistory.count(); + Q_ASSERT( false ); + return; + } + + setHistoryPosition( historyPosition ); + ViewPage* page = m_pageHistory.at( historyPosition ); + setPage( page, false ); +} + + void PlaylistManager::setFilter( const QString& filter ) { @@ -574,67 +499,114 @@ PlaylistManager::applyFilter() { qDebug() << Q_FUNC_INFO; - if ( m_currentInterface && m_currentInterface->filter() != m_filter ) - m_currentInterface->setFilter( m_filter ); + if ( currentPlaylistInterface() && currentPlaylistInterface()->filter() != m_filter ) + currentPlaylistInterface()->setFilter( m_filter ); +} + + +void +PlaylistManager::setPage( ViewPage* page, bool trackHistory ) +{ + unlinkPlaylist(); + + if ( !m_pageHistory.contains( page ) ) + { + m_stack->addWidget( page->widget() ); + } + else + { + if ( trackHistory ) + m_pageHistory.removeAll( page ); + } + + if ( trackHistory ) + { + m_pageHistory << page; + setHistoryPosition( m_pageHistory.count() - 1 ); + } + + if ( playlistForInterface( currentPlaylistInterface() ) ) + emit playlistActivated( playlistForInterface( currentPlaylistInterface() ) ); + if ( dynamicPlaylistForInterface( currentPlaylistInterface() ) ) + emit dynamicPlaylistActivated( dynamicPlaylistForInterface( currentPlaylistInterface() ) ); + if ( collectionForInterface( currentPlaylistInterface() ) ) + emit collectionActivated( collectionForInterface( currentPlaylistInterface() ) ); + if ( !currentPlaylistInterface() ) + emit tempPageActivated(); + + if ( !AudioEngine::instance()->playlist() ) + AudioEngine::instance()->setPlaylist( currentPlaylistInterface() ); + + m_stack->setCurrentWidget( page->widget() ); + updateView(); } void PlaylistManager::unlinkPlaylist() { - if ( m_currentInterface ) + if ( currentPlaylistInterface() ) { - disconnect( m_currentInterface->object(), SIGNAL( sourceTrackCountChanged( unsigned int ) ), - this, SIGNAL( numTracksChanged( unsigned int ) ) ); + disconnect( currentPlaylistInterface()->object(), SIGNAL( sourceTrackCountChanged( unsigned int ) ), + this, SIGNAL( numTracksChanged( unsigned int ) ) ); - disconnect( m_currentInterface->object(), SIGNAL( trackCountChanged( unsigned int ) ), - this, SIGNAL( numShownChanged( unsigned int ) ) ); + disconnect( currentPlaylistInterface()->object(), SIGNAL( trackCountChanged( unsigned int ) ), + this, SIGNAL( numShownChanged( unsigned int ) ) ); - disconnect( m_currentInterface->object(), SIGNAL( repeatModeChanged( PlaylistInterface::RepeatMode ) ), - this, SIGNAL( repeatModeChanged( PlaylistInterface::RepeatMode ) ) ); + disconnect( currentPlaylistInterface()->object(), SIGNAL( repeatModeChanged( PlaylistInterface::RepeatMode ) ), + this, SIGNAL( repeatModeChanged( PlaylistInterface::RepeatMode ) ) ); - disconnect( m_currentInterface->object(), SIGNAL( shuffleModeChanged( bool ) ), - this, SIGNAL( shuffleModeChanged( bool ) ) ); + disconnect( currentPlaylistInterface()->object(), SIGNAL( shuffleModeChanged( bool ) ), + this, SIGNAL( shuffleModeChanged( bool ) ) ); } } void -PlaylistManager::linkPlaylist() +PlaylistManager::updateView() { - if ( m_currentInterface ) + if ( currentPlaylistInterface() ) { - connect( m_currentInterface->object(), SIGNAL( sourceTrackCountChanged( unsigned int ) ), - this, SIGNAL( numTracksChanged( unsigned int ) ) ); + connect( currentPlaylistInterface()->object(), SIGNAL( sourceTrackCountChanged( unsigned int ) ), + SIGNAL( numTracksChanged( unsigned int ) ) ); - connect( m_currentInterface->object(), SIGNAL( trackCountChanged( unsigned int ) ), - this, SIGNAL( numShownChanged( unsigned int ) ) ); + connect( currentPlaylistInterface()->object(), SIGNAL( trackCountChanged( unsigned int ) ), + SIGNAL( numShownChanged( unsigned int ) ) ); - connect( m_currentInterface->object(), SIGNAL( repeatModeChanged( PlaylistInterface::RepeatMode ) ), - this, SIGNAL( repeatModeChanged( PlaylistInterface::RepeatMode ) ) ); + connect( currentPlaylistInterface()->object(), SIGNAL( repeatModeChanged( PlaylistInterface::RepeatMode ) ), + SIGNAL( repeatModeChanged( PlaylistInterface::RepeatMode ) ) ); - connect( m_currentInterface->object(), SIGNAL( shuffleModeChanged( bool ) ), - this, SIGNAL( shuffleModeChanged( bool ) ) ); + connect( currentPlaylistInterface()->object(), SIGNAL( shuffleModeChanged( bool ) ), + SIGNAL( shuffleModeChanged( bool ) ) ); - m_interfaceHistory.removeAll( m_currentInterface ); - m_interfaceHistory << m_currentInterface; + m_topbar->setFilter( currentPlaylistInterface()->filter() ); } - AudioEngine::instance()->setPlaylist( m_currentInterface ); - - if ( m_currentInterface && m_statsAvailable ) + if ( currentPage()->showStatsBar() && currentPlaylistInterface() ) { - m_topbar->setFilter( m_currentInterface->filter() ); - - emit numTracksChanged( m_currentInterface->unfilteredTrackCount() ); - emit numShownChanged( m_currentInterface->trackCount() ); - emit repeatModeChanged( m_currentInterface->repeatMode() ); - emit shuffleModeChanged( m_currentInterface->shuffled() ); - + emit numTracksChanged( currentPlaylistInterface()->unfilteredTrackCount() ); + emit numShownChanged( currentPlaylistInterface()->trackCount() ); + emit repeatModeChanged( currentPlaylistInterface()->repeatMode() ); + emit shuffleModeChanged( currentPlaylistInterface()->shuffled() ); + emit modeChanged( currentPlaylistInterface()->viewMode() ); } - emit statsAvailable( m_statsAvailable ); - emit modesAvailable( m_modesAvailable ); + if ( currentPage()->queueVisible() ) + m_queueView->show(); + else + m_queueView->hide(); + + emit statsAvailable( currentPage()->showStatsBar() ); + emit modesAvailable( currentPage()->showModes() ); + + if ( !currentPage()->showStatsBar() && !currentPage()->showModes() ) + m_topbar->setVisible( false ); + else + m_topbar->setVisible( true ); + + m_infobar->setCaption( currentPage()->title() ); + m_infobar->setDescription( currentPage()->description() ); + m_infobar->setPixmap( currentPage()->pixmap() ); } @@ -646,17 +618,20 @@ PlaylistManager::onWidgetDestroyed( QWidget* widget ) bool resetWidget = ( m_stack->currentWidget() == widget ); m_stack->removeWidget( widget ); - if ( resetWidget && m_interfaceHistory.count() ) + for ( int i = 0; i < m_pageHistory.count(); i++ ) { - unlinkPlaylist(); + ViewPage* page = m_pageHistory.at( i ); + if ( page->widget() == widget ) + { + m_pageHistory.removeAt( i ); + break; + } + } - m_currentInterface = m_interfaceHistory.last(); - qDebug() << "Last interface:" << m_currentInterface << m_currentInterface->widget(); - - if ( m_currentInterface->widget() ) - m_stack->setCurrentWidget( m_currentInterface->widget() ); - - linkPlaylist(); + if ( resetWidget ) + { + if ( m_pageHistory.count() ) + showHistory( m_pageHistory.count() - 1 ); } } @@ -664,16 +639,16 @@ PlaylistManager::onWidgetDestroyed( QWidget* widget ) void PlaylistManager::setRepeatMode( PlaylistInterface::RepeatMode mode ) { - if ( m_currentInterface ) - m_currentInterface->setRepeatMode( mode ); + if ( currentPlaylistInterface() ) + currentPlaylistInterface()->setRepeatMode( mode ); } void PlaylistManager::setShuffled( bool enabled ) { - if ( m_currentInterface ) - m_currentInterface->setShuffled( enabled ); + if ( currentPlaylistInterface() ) + currentPlaylistInterface()->setShuffled( enabled ); } @@ -697,20 +672,121 @@ PlaylistManager::createDynamicPlaylist( const Tomahawk::source_ptr& src, } +ViewPage* +PlaylistManager::pageForInterface( PlaylistInterface* interface ) const +{ + for ( int i = 0; i < m_pageHistory.count(); i++ ) + { + ViewPage* page = m_pageHistory.at( i ); + if ( page->playlistInterface() == interface ) + return page; + } + + return 0; +} + + +int +PlaylistManager::positionInHistory( ViewPage* page ) const +{ + for ( int i = 0; i < m_pageHistory.count(); i++ ) + { + if ( page == m_pageHistory.at( i ) ) + return i; + } + + return -1; +} + + +PlaylistInterface* +PlaylistManager::currentPlaylistInterface() const +{ + if ( currentPage() ) + return currentPage()->playlistInterface(); + else + return 0; +} + + +Tomahawk::ViewPage* +PlaylistManager::currentPage() const +{ + if ( m_historyPosition >= 0 ) + return m_pageHistory.at( m_historyPosition ); + else + return 0; +} + + +void +PlaylistManager::setHistoryPosition( int position ) +{ + m_historyPosition = position; + + emit historyBackAvailable( m_historyPosition > 0 ); + emit historyForwardAvailable( m_historyPosition < m_pageHistory.count() - 1 ); +} + + +Tomahawk::playlist_ptr +PlaylistManager::playlistForInterface( PlaylistInterface* interface ) const +{ + foreach ( PlaylistView* view, m_playlistViews.values() ) + { + if ( view->playlistInterface() == interface ) + { + return m_playlistViews.key( view ); + } + } + + return playlist_ptr(); +} + + +Tomahawk::dynplaylist_ptr +PlaylistManager::dynamicPlaylistForInterface( PlaylistInterface* interface ) const +{ + foreach ( DynamicWidget* view, m_dynamicWidgets.values() ) + { + if ( view->playlistInterface() == interface ) + { + return m_dynamicWidgets.key( view ); + } + } + + return dynplaylist_ptr(); +} + + +Tomahawk::collection_ptr +PlaylistManager::collectionForInterface( PlaylistInterface* interface ) const +{ + foreach ( CollectionView* view, m_collectionViews.values() ) + { + if ( view->playlistInterface() == interface ) + { + return m_collectionViews.key( view ); + } + } + foreach ( AlbumView* view, m_collectionAlbumViews.values() ) + { + if ( view->playlistInterface() == interface ) + { + return m_collectionAlbumViews.key( view ); + } + } + + return collection_ptr(); +} + + void PlaylistManager::showCurrentTrack() { - unlinkPlaylist(); - - m_currentInterface = AudioEngine::instance()->currentTrackPlaylist(); - - if ( m_currentInterface->widget() ) - m_stack->setCurrentWidget( m_currentInterface->widget() ); - - linkPlaylist(); - -/* if ( m_currentView && m_currentProxyModel ) - m_currentView->scrollTo( m_currentProxyModel->currentItem(), QAbstractItemView::PositionAtCenter );*/ + ViewPage* page = pageForInterface( AudioEngine::instance()->currentTrackPlaylist() ); + setPage( page ); + page->jumpToCurrentTrack(); } @@ -725,4 +801,4 @@ void PlaylistManager::onPauseClicked() { emit pauseClicked(); -} \ No newline at end of file +} diff --git a/src/libtomahawk/playlist/playlistmanager.h b/src/libtomahawk/playlist/playlistmanager.h index 0c327e494..722f7286e 100644 --- a/src/libtomahawk/playlist/playlistmanager.h +++ b/src/libtomahawk/playlist/playlistmanager.h @@ -7,6 +7,7 @@ #include "collection.h" #include "playlistinterface.h" +#include "viewpage.h" #include "dllmacro.h" @@ -25,8 +26,10 @@ class TrackView; class SourceInfoWidget; class InfoBar; class TopBar; +class WelcomeWidget; -namespace Tomahawk { +namespace Tomahawk +{ class DynamicWidget; } @@ -45,7 +48,10 @@ public: bool isSuperCollectionVisible() const { return true; } - PlaylistInterface* currentPlaylistInterface() const { return m_currentInterface; } + PlaylistInterface* currentPlaylistInterface() const; + Tomahawk::ViewPage* currentPage() const; + Tomahawk::ViewPage* pageForInterface( PlaylistInterface* interface ) const; + int positionInHistory( Tomahawk::ViewPage* page ) const; bool show( const Tomahawk::playlist_ptr& playlist ); bool show( const Tomahawk::dynplaylist_ptr& playlist ); @@ -54,10 +60,7 @@ public: bool show( const Tomahawk::collection_ptr& collection ); bool show( const Tomahawk::source_ptr& source ); - bool show( QWidget* widget, const QString& title = QString(), const QString& desc = QString(), const QPixmap& pixmap = QPixmap() ); - - bool showSuperCollection(); - void showCurrentTrack(); + bool show( Tomahawk::ViewPage* page ); signals: void numSourcesChanged( unsigned int sources ); @@ -70,10 +73,29 @@ signals: void statsAvailable( bool b ); void modesAvailable( bool b ); + void modeChanged( PlaylistInterface::ViewMode mode ); void playClicked(); void pauseClicked(); + + void historyBackAvailable( bool avail ); + void historyForwardAvailable( bool avail ); + + void tempPageActivated(); + void superCollectionActivated(); + void collectionActivated( const Tomahawk::collection_ptr& collection ); + void playlistActivated( const Tomahawk::playlist_ptr& playlist ); + void dynamicPlaylistActivated( const Tomahawk::dynplaylist_ptr& playlist ); + public slots: + bool showSuperCollection(); + void showWelcomePage(); + void showCurrentTrack(); + + void historyBack(); + void historyForward(); + void showHistory( int historyPosition ); + void setTreeMode(); void setTableMode(); void setAlbumMode(); @@ -100,9 +122,15 @@ private slots: void onWidgetDestroyed( QWidget* widget ); private: + void setHistoryPosition( int position ); + void setPage( Tomahawk::ViewPage* page, bool trackHistory = true ); + void updateView(); void unlinkPlaylist(); - void linkPlaylist(); + Tomahawk::playlist_ptr playlistForInterface( PlaylistInterface* interface ) const; + Tomahawk::dynplaylist_ptr dynamicPlaylistForInterface( PlaylistInterface* interface ) const; + Tomahawk::collection_ptr collectionForInterface( PlaylistInterface* interface ) const; + QWidget* m_widget; InfoBar* m_infobar; TopBar* m_topbar; @@ -115,7 +143,8 @@ private: AlbumModel* m_superAlbumModel; AlbumView* m_superAlbumView; CollectionFlatModel* m_superCollectionFlatModel; - CollectionView* m_superCollectionView; + CollectionView* m_superCollectionView; + WelcomeWidget* m_welcomeWidget; QList< Tomahawk::collection_ptr > m_superCollections; @@ -126,19 +155,15 @@ private: QHash< Tomahawk::album_ptr, PlaylistView* > m_albumViews; QHash< Tomahawk::playlist_ptr, PlaylistView* > m_playlistViews; QHash< Tomahawk::source_ptr, SourceInfoWidget* > m_sourceViews; - - PlaylistInterface* m_currentInterface; - QList m_interfaceHistory; - - QWidget* m_currentInfoWidget; + + QList m_pageHistory; + int m_historyPosition; Tomahawk::collection_ptr m_currentCollection; int m_currentMode; bool m_superCollectionVisible; - bool m_statsAvailable; - bool m_modesAvailable; - + QTimer m_filterTimer; QString m_filter; diff --git a/src/libtomahawk/playlist/playlistmodel.cpp b/src/libtomahawk/playlist/playlistmodel.cpp index 620cc240b..660e9a1a7 100644 --- a/src/libtomahawk/playlist/playlistmodel.cpp +++ b/src/libtomahawk/playlist/playlistmodel.cpp @@ -67,8 +67,10 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn connect( playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), SLOT( onRevisionLoaded( Tomahawk::PlaylistRevision ) ) ); setReadOnly( !m_playlist->author()->isLocal() ); + setTitle( playlist->title() ); + setDescription( tr( "A playlist by %1" ).arg( playlist->author()->isLocal() ? tr( "you" ) : playlist->author()->friendlyName() ) ); - if( !loadEntries ) + if ( !loadEntries ) return; PlItem* plitem; diff --git a/src/libtomahawk/playlist/playlistview.cpp b/src/libtomahawk/playlist/playlistview.cpp index b2a367dfc..18abb0d01 100644 --- a/src/libtomahawk/playlist/playlistview.cpp +++ b/src/libtomahawk/playlist/playlistview.cpp @@ -4,7 +4,6 @@ #include #include -#include "playlist/playlistmodel.h" #include "playlist/playlistproxymodel.h" #include "widgets/overlaywidget.h" @@ -129,3 +128,10 @@ PlaylistView::onTrackCountChanged( unsigned int tracks ) else overlay()->hide(); } + + +bool +PlaylistView::jumpToCurrentTrack() +{ + scrollTo( proxyModel()->currentItem(), QAbstractItemView::PositionAtCenter ); +} diff --git a/src/libtomahawk/playlist/playlistview.h b/src/libtomahawk/playlist/playlistview.h index 1e7c80c70..26a543316 100644 --- a/src/libtomahawk/playlist/playlistview.h +++ b/src/libtomahawk/playlist/playlistview.h @@ -3,13 +3,16 @@ #include +#include "playlist/trackproxymodel.h" +#include "playlist/playlistmodel.h" #include "trackview.h" +#include "viewpage.h" #include "dllmacro.h" class PlaylistModel; -class DLLEXPORT PlaylistView : public TrackView +class DLLEXPORT PlaylistView : public TrackView, public Tomahawk::ViewPage { Q_OBJECT @@ -20,6 +23,14 @@ public: PlaylistModel* playlistModel() const { return m_model; } virtual void setModel( PlaylistModel* model ); + virtual QWidget* widget() { return this; } + virtual PlaylistInterface* playlistInterface() const { return proxyModel(); } + + virtual QString title() const { return playlistModel()->title(); } + virtual QString description() const { return m_model->description(); } + + virtual bool jumpToCurrentTrack(); + protected: void keyPressEvent( QKeyEvent* event ); diff --git a/src/libtomahawk/playlist/topbar/topbar.cpp b/src/libtomahawk/playlist/topbar/topbar.cpp index dd6705bfd..3aa584bf5 100644 --- a/src/libtomahawk/playlist/topbar/topbar.cpp +++ b/src/libtomahawk/playlist/topbar/topbar.cpp @@ -65,7 +65,28 @@ TopBar::TopBar( QWidget* parent ) setNumArtists( 0 ); setNumShown( 0 ); - ui->radioNormal->setChecked( true ); + onFlatMode(); + + connect( PlaylistManager::instance(), SIGNAL( numSourcesChanged( unsigned int ) ), + SLOT( setNumSources( unsigned int ) ) ); + + connect( PlaylistManager::instance(), SIGNAL( numTracksChanged( unsigned int ) ), + SLOT( setNumTracks( unsigned int ) ) ); + + connect( PlaylistManager::instance(), SIGNAL( numArtistsChanged( unsigned int ) ), + SLOT( setNumArtists( unsigned int ) ) ); + + connect( PlaylistManager::instance(), SIGNAL( numShownChanged( unsigned int ) ), + SLOT( setNumShown( unsigned int ) ) ); + + connect( PlaylistManager::instance(), SIGNAL( statsAvailable( bool ) ), + SLOT( setStatsVisible( bool ) ) ); + + connect( PlaylistManager::instance(), SIGNAL( modesAvailable( bool ) ), + SLOT( setModesVisible( bool ) ) ); + + connect( PlaylistManager::instance(), SIGNAL( modeChanged( PlaylistInterface::ViewMode ) ), + SLOT( onModeChanged( PlaylistInterface::ViewMode ) ) ); } @@ -238,3 +259,48 @@ TopBar::setFilter( const QString& filter ) { ui->filterEdit->setText( filter ); } + + +void +TopBar::onModeChanged( PlaylistInterface::ViewMode mode ) +{ + qDebug() << Q_FUNC_INFO << mode; + switch ( mode ) + { + case PlaylistInterface::Flat: + onFlatMode(); + break; + + case PlaylistInterface::Tree: + onArtistMode(); + break; + + case PlaylistInterface::Album: + onAlbumMode(); + break; + + default: + break; + } +} + + +void +TopBar::onFlatMode() +{ + ui->radioNormal->setChecked( true ); +} + + +void +TopBar::onArtistMode() +{ + ui->radioDetailed->setChecked( true ); +} + + +void +TopBar::onAlbumMode() +{ + ui->radioCloud->setChecked( true ); +} diff --git a/src/libtomahawk/playlist/topbar/topbar.h b/src/libtomahawk/playlist/topbar/topbar.h index f51b27e30..439768029 100644 --- a/src/libtomahawk/playlist/topbar/topbar.h +++ b/src/libtomahawk/playlist/topbar/topbar.h @@ -5,6 +5,7 @@ #include #include +#include "playlist/playlistmanager.h" #include "sourcelist.h" #include "dllmacro.h" @@ -42,6 +43,12 @@ public slots: void setFilter( const QString& filter ); +private slots: + void onModeChanged( PlaylistInterface::ViewMode mode ); + void onFlatMode(); + void onArtistMode(); + void onAlbumMode(); + protected: void changeEvent( QEvent* e ); void resizeEvent( QResizeEvent* e ); diff --git a/src/libtomahawk/playlist/trackmodel.h b/src/libtomahawk/playlist/trackmodel.h index ad43006be..f67b6631a 100644 --- a/src/libtomahawk/playlist/trackmodel.h +++ b/src/libtomahawk/playlist/trackmodel.h @@ -35,6 +35,11 @@ public: virtual bool isReadOnly() const { return m_readOnly; } + virtual QString title() const { return m_title; } + virtual void setTitle( const QString& title ) { m_title = title; } + virtual QString description() const { return m_description; } + virtual void setDescription( const QString& description ) { m_description = description; } + virtual int trackCount() const { return rowCount( QModelIndex() ); } virtual int rowCount( const QModelIndex& parent ) const; @@ -84,6 +89,9 @@ private slots: private: QPersistentModelIndex m_currentIndex; bool m_readOnly; + + QString m_title; + QString m_description; }; #endif // TRACKMODEL_H diff --git a/src/libtomahawk/playlist/trackview.cpp b/src/libtomahawk/playlist/trackview.cpp index c2a972ed1..bdc139773 100644 --- a/src/libtomahawk/playlist/trackview.cpp +++ b/src/libtomahawk/playlist/trackview.cpp @@ -73,7 +73,6 @@ void TrackView::setProxyModel( TrackProxyModel* model ) { m_proxyModel = model; - m_proxyModel->setWidget( this ); m_delegate = new PlaylistItemDelegate( this, m_proxyModel ); setItemDelegate( m_delegate ); diff --git a/src/libtomahawk/playlistinterface.h b/src/libtomahawk/playlistinterface.h index 7ef4fefd1..f8a56fa32 100644 --- a/src/libtomahawk/playlistinterface.h +++ b/src/libtomahawk/playlistinterface.h @@ -13,8 +13,9 @@ class DLLEXPORT PlaylistInterface { public: enum RepeatMode { NoRepeat, RepeatOne, RepeatAll }; - - PlaylistInterface( QObject* parent = 0 ) : m_widget( 0 ), m_object( parent ) {} + enum ViewMode { Unknown, Flat, Tree, Album }; + + PlaylistInterface( QObject* parent = 0 ) : m_object( parent ) {} virtual ~PlaylistInterface() {} virtual QList< Tomahawk::query_ptr > tracks() = 0; @@ -28,13 +29,11 @@ public: virtual PlaylistInterface::RepeatMode repeatMode() const = 0; virtual bool shuffled() const = 0; + virtual PlaylistInterface::ViewMode viewMode() const { return Unknown; } virtual QString filter() const { return m_filter; } virtual void setFilter( const QString& pattern ) { m_filter = pattern; } - QWidget* widget() const { return m_widget; } - void setWidget( QWidget* widget ) { m_widget = widget; } - QObject* object() const { return m_object; } public slots: @@ -48,7 +47,6 @@ signals: virtual void sourceTrackCountChanged( unsigned int tracks ) = 0; private: - QWidget* m_widget; QObject* m_object; QString m_filter; diff --git a/src/libtomahawk/source.cpp b/src/libtomahawk/source.cpp index e6400344f..0c24deb26 100644 --- a/src/libtomahawk/source.cpp +++ b/src/libtomahawk/source.cpp @@ -159,7 +159,7 @@ Source::scanningProgress( unsigned int files ) void Source::scanningFinished( unsigned int files ) { - m_textStatus = tr( "Online" ); + m_textStatus = QString(); emit stateChanged(); } @@ -183,14 +183,14 @@ Source::onStateChanged( DBSyncConnection::State newstate, DBSyncConnection::Stat msg = tr( "Saving" ); break; case DBSyncConnection::SYNCED: - msg = tr( "Online" ); + msg = QString(); break; case DBSyncConnection::SCANNING: msg = tr( "Scanning (%L1 tracks)" ).arg( info ); break; default: - msg = "???"; + msg = QString(); } m_textStatus = msg; diff --git a/src/libtomahawk/source.h b/src/libtomahawk/source.h index 3e598c4aa..f1719cfce 100644 --- a/src/libtomahawk/source.h +++ b/src/libtomahawk/source.h @@ -42,7 +42,7 @@ public: void addCollection( const Tomahawk::collection_ptr& c ); void removeCollection( const Tomahawk::collection_ptr& c ); - unsigned int id() const { return m_id; } + int id() const { return m_id; } ControlConnection* controlConnection() const { return m_cc; } void setControlConnection( ControlConnection* cc ); @@ -90,7 +90,7 @@ private: bool m_isLocal; bool m_online; QString m_username, m_friendlyname; - unsigned int m_id; + int m_id; QList< QSharedPointer > m_collections; QVariantMap m_stats; QString m_lastOpGuid; diff --git a/src/libtomahawk/sourcelist.cpp b/src/libtomahawk/sourcelist.cpp index 20be81298..45a2c74ce 100644 --- a/src/libtomahawk/sourcelist.cpp +++ b/src/libtomahawk/sourcelist.cpp @@ -86,10 +86,11 @@ SourceList::setLocal( const Tomahawk::source_ptr& localSrc ) void SourceList::add( const source_ptr& source ) { - Q_ASSERT( source->id() ); - + qDebug() << "Adding to sources:" << source->userName() << source->id(); m_sources.insert( source->userName(), source ); - m_sources_id2name.insert( source->id(), source->userName() ); + + if ( source->id() > 0 ) + m_sources_id2name.insert( source->id(), source->userName() ); connect( source.data(), SIGNAL( syncedWithDatabase() ), SLOT( sourceSynced() ) ); collection_ptr coll( new RemoteCollection( source ) ); @@ -102,14 +103,11 @@ SourceList::add( const source_ptr& source ) void SourceList::removeAllRemote() { - foreach( source_ptr s, m_sources ) + foreach( const source_ptr& s, m_sources ) { - if( s != m_local ) + if ( !s->isLocal() && s->controlConnection() ) { - if ( s->controlConnection() ) - { - s->controlConnection()->shutdown( true ); - } + s->controlConnection()->shutdown( true ); } } } @@ -132,7 +130,7 @@ SourceList::sources( bool onlyOnline ) const source_ptr -SourceList::get( unsigned int id ) const +SourceList::get( int id ) const { QMutexLocker lock( &m_mut ); return m_sources.value( m_sources_id2name.value( id ) ); @@ -163,8 +161,6 @@ SourceList::sourceSynced() { Source* src = qobject_cast< Source* >( sender() ); - Q_ASSERT( m_sources_id2name.values().contains( src->userName() ) ); - m_sources_id2name.remove( m_sources_id2name.key( src->userName() ) ); m_sources_id2name.insert( src->id(), src->userName() ); } diff --git a/src/libtomahawk/sourcelist.h b/src/libtomahawk/sourcelist.h index aeabad234..8b1861476 100644 --- a/src/libtomahawk/sourcelist.h +++ b/src/libtomahawk/sourcelist.h @@ -28,7 +28,7 @@ public: unsigned int count() const; Tomahawk::source_ptr get( const QString& username, const QString& friendlyName = QString() ); - Tomahawk::source_ptr get( unsigned int id ) const; + Tomahawk::source_ptr get( int id ) const; signals: void ready(); @@ -45,7 +45,7 @@ private: void add( const Tomahawk::source_ptr& source ); QMap< QString, Tomahawk::source_ptr > m_sources; - QMap< unsigned int, QString > m_sources_id2name; + QMap< int, QString > m_sources_id2name; Tomahawk::source_ptr m_local; mutable QMutex m_mut; // mutable so const methods can use a lock diff --git a/src/libtomahawk/utils/tomahawkutils.cpp b/src/libtomahawk/utils/tomahawkutils.cpp index 45238a542..1b5db86fe 100644 --- a/src/libtomahawk/utils/tomahawkutils.cpp +++ b/src/libtomahawk/utils/tomahawkutils.cpp @@ -205,7 +205,7 @@ filesizeToString( unsigned int size ) if ( mb ) { - return QString( "%1.%2 Mb" ).arg( mb ).arg( int( ( kb % 1024 ) / 100 ) ); + return QString( "%1.%2 Mb" ).arg( mb ).arg( int( ( kb % 1024 ) / 102.4 ) ); } else if ( kb ) { diff --git a/src/libtomahawk/viewpage.cpp b/src/libtomahawk/viewpage.cpp new file mode 100644 index 000000000..321bbbdf8 --- /dev/null +++ b/src/libtomahawk/viewpage.cpp @@ -0,0 +1,6 @@ +#include "viewpage.h" + +#include + +using namespace Tomahawk; + diff --git a/src/libtomahawk/viewpage.h b/src/libtomahawk/viewpage.h new file mode 100644 index 000000000..af087c669 --- /dev/null +++ b/src/libtomahawk/viewpage.h @@ -0,0 +1,38 @@ +#ifndef VIEWPAGE_H +#define VIEWPAGE_H + +#include + +#include "typedefs.h" +#include "playlistinterface.h" +#include "utils/tomahawkutils.h" + +#include "dllmacro.h" + +namespace Tomahawk +{ + +class DLLEXPORT ViewPage +{ +public: + ViewPage() {} + + virtual QWidget* widget() = 0; + virtual PlaylistInterface* playlistInterface() const = 0; + + virtual QString title() const = 0; + virtual QString description() const = 0; + virtual QPixmap pixmap() const { return QPixmap( RESPATH "icons/tomahawk-icon-128x128.png" ); } + + virtual bool showStatsBar() const { return true; } + virtual bool showModes() const { return false; } + virtual bool queueVisible() const { return true; } + + virtual bool jumpToCurrentTrack() = 0; + +private: +}; + +}; // ns + +#endif //VIEWPAGE_H diff --git a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.cpp b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.cpp index ad57103d2..80469499e 100644 --- a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.cpp @@ -43,6 +43,8 @@ SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* m_recentAlbumModel = new AlbumModel( ui->recentAlbumView ); ui->recentAlbumView->setModel( m_recentAlbumModel ); m_recentAlbumModel->addFilteredCollection( source->collection(), 20, DatabaseCommand_AllAlbums::ModificationTime ); + + m_title = tr( "Info about %1" ).arg( source->isLocal() ? tr( "Your Collection" ) : source->friendlyName() ); } diff --git a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.h b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.h index 8d369a97e..f12fd942d 100644 --- a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.h +++ b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.h @@ -6,6 +6,7 @@ #include "album.h" #include "result.h" #include "playlistinterface.h" +#include "viewpage.h" #include "dllmacro.h" @@ -18,7 +19,7 @@ namespace Ui class SourceInfoWidget; } -class DLLEXPORT SourceInfoWidget : public QWidget +class DLLEXPORT SourceInfoWidget : public QWidget, public Tomahawk::ViewPage { Q_OBJECT @@ -26,6 +27,16 @@ public: SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* parent = 0 ); ~SourceInfoWidget(); + virtual QWidget* widget() { return this; } + virtual PlaylistInterface* playlistInterface() const { return 0; } + + virtual QString title() const { return m_title; } + virtual QString description() const { return m_description; } + + virtual bool showStatsBar() const { return false; } + + virtual bool jumpToCurrentTrack() { return false; } + protected: void changeEvent( QEvent* e ); @@ -38,6 +49,9 @@ private: CollectionFlatModel* m_recentCollectionModel; PlaylistModel* m_historyModel; AlbumModel* m_recentAlbumModel; + + QString m_title; + QString m_description; }; #endif // SOURCEINFOWIDGET_H diff --git a/src/libtomahawk/widgets/newplaylistwidget.h b/src/libtomahawk/widgets/newplaylistwidget.h index f19590aa7..dfe54a988 100644 --- a/src/libtomahawk/widgets/newplaylistwidget.h +++ b/src/libtomahawk/widgets/newplaylistwidget.h @@ -7,6 +7,7 @@ #include "album.h" #include "result.h" #include "playlistinterface.h" +#include "viewpage.h" #include "dllmacro.h" @@ -18,7 +19,7 @@ namespace Ui class NewPlaylistWidget; } -class DLLEXPORT NewPlaylistWidget : public QWidget +class DLLEXPORT NewPlaylistWidget : public QWidget, public Tomahawk::ViewPage { Q_OBJECT @@ -26,6 +27,16 @@ public: NewPlaylistWidget( QWidget* parent = 0 ); ~NewPlaylistWidget(); + virtual QWidget* widget() { return this; } + virtual PlaylistInterface* playlistInterface() const { return 0; } + + virtual QString title() const { return tr( "Create a new playlist" ); } + virtual QString description() const { return QString(); } + + virtual bool showStatsBar() const { return false; } + + virtual bool jumpToCurrentTrack() { return false; } + protected: void changeEvent( QEvent* e ); diff --git a/src/libtomahawk/widgets/newplaylistwidget.ui b/src/libtomahawk/widgets/newplaylistwidget.ui index 8b30f4780..6a2701ee8 100644 --- a/src/libtomahawk/widgets/newplaylistwidget.ui +++ b/src/libtomahawk/widgets/newplaylistwidget.ui @@ -11,28 +11,11 @@ - - - - - 20 - 75 - true - - - - Create A New Playlist - - - false - - - - 14 + 13 @@ -54,7 +37,7 @@ - 14 + 13 @@ -69,7 +52,7 @@ - 14 + 13 diff --git a/src/libtomahawk/widgets/welcomewidget.h b/src/libtomahawk/widgets/welcomewidget.h index 79f700448..9d14859e8 100644 --- a/src/libtomahawk/widgets/welcomewidget.h +++ b/src/libtomahawk/widgets/welcomewidget.h @@ -9,6 +9,7 @@ #include "playlist.h" #include "result.h" +#include "viewpage.h" #include "utils/tomahawkutils.h" @@ -73,7 +74,7 @@ private: }; -class DLLEXPORT WelcomeWidget : public QWidget +class DLLEXPORT WelcomeWidget : public QWidget, public Tomahawk::ViewPage { Q_OBJECT @@ -81,6 +82,16 @@ public: WelcomeWidget( QWidget* parent = 0 ); ~WelcomeWidget(); + virtual QWidget* widget() { return this; } + virtual PlaylistInterface* playlistInterface() const { return 0; } + + virtual QString title() const { return tr( "Welcome to Tomahawk" ); } + virtual QString description() const { return QString(); } + + virtual bool showStatsBar() const { return false; } + + virtual bool jumpToCurrentTrack() { return false; } + protected: void changeEvent( QEvent* e ); diff --git a/src/sip/jabber/jabber_p.cpp b/src/sip/jabber/jabber_p.cpp index a891973a9..cf090c107 100644 --- a/src/sip/jabber/jabber_p.cpp +++ b/src/sip/jabber/jabber_p.cpp @@ -526,7 +526,7 @@ Jabber_p::handleRosterPresence( const RosterItem& item, const std::string& resou // convert to QString to get proper regex support QString res( jid.resource().c_str() ); QRegExp regex( "tomahawk\\d+" ); - if( res != "tomahawk-tomahawk" && !res.contains( regex ) ) + if( res != "tomahawk-tomahawk" && !res.startsWith( "tomahawk" ) ) { //qDebug() << "not considering resource of" << res; // Disco them to check if they are tomahawk-capable diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp index 3a8cf60ce..e2a95de0c 100644 --- a/src/sourcetree/sourcesmodel.cpp +++ b/src/sourcetree/sourcesmodel.cpp @@ -58,7 +58,8 @@ SourcesModel::flags( const QModelIndex& index ) const playlist_ptr playlist = indexToPlaylist( index ); if ( !playlist.isNull() && playlist->author()->isLocal() ) defaultFlags |= Qt::ItemIsEditable; - } else if ( indexType( index ) == DynamicPlaylistSource ) + } + else if ( indexType( index ) == DynamicPlaylistSource ) { dynplaylist_ptr playlist = indexToDynamicPlaylist( index ); if ( !playlist.isNull() && playlist->author()->isLocal() ) @@ -124,13 +125,15 @@ SourcesModel::appendItem( const source_ptr& source ) // qDebug() << "Appending source item:" << item->source()->username(); invisibleRootItem()->appendRow( item->columns() ); -// m_parent->setIndexWidget( m_parent->model()->index( rowCount() - 1, 0 ), item->widget() ); - connect( source.data(), SIGNAL( offline() ), SLOT( onSourceChanged() ) ); - connect( source.data(), SIGNAL( online() ), SLOT( onSourceChanged() ) ); - connect( source.data(), SIGNAL( stats( QVariantMap ) ), SLOT( onSourceChanged() ) ); - connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), SLOT( onSourceChanged() ) ); - connect( source.data(), SIGNAL( stateChanged() ), SLOT( onSourceChanged() ) ); + if ( !source.isNull() ) + { + connect( source.data(), SIGNAL( offline() ), SLOT( onSourceChanged() ) ); + connect( source.data(), SIGNAL( online() ), SLOT( onSourceChanged() ) ); + connect( source.data(), SIGNAL( stats( QVariantMap ) ), SLOT( onSourceChanged() ) ); + connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), SLOT( onSourceChanged() ) ); + connect( source.data(), SIGNAL( stateChanged() ), SLOT( onSourceChanged() ) ); + } return true; // FIXME } @@ -259,6 +262,75 @@ SourcesModel::indexToTreeItem( const QModelIndex& index ) } +QModelIndex +SourcesModel::playlistToIndex( const Tomahawk::playlist_ptr& playlist ) +{ + for ( int i = 0; i < rowCount(); i++ ) + { + QModelIndex pidx = index( i, 0 ); + + for ( int j = 0; j < rowCount( pidx ); j++ ) + { + QModelIndex idx = index( j, 0, pidx ); + SourcesModel::SourceType type = SourcesModel::indexType( idx ); + + if ( type == SourcesModel::PlaylistSource ) + { + playlist_ptr p = SourcesModel::indexToPlaylist( idx ); + if ( playlist.data() == p.data() ) + return idx; + } + } + } + + return QModelIndex(); +} + + +QModelIndex +SourcesModel::dynamicPlaylistToIndex( const Tomahawk::dynplaylist_ptr& playlist ) +{ + for ( int i = 0; i < rowCount(); i++ ) + { + QModelIndex pidx = index( i, 0 ); + + for ( int j = 0; j < rowCount( pidx ); j++ ) + { + QModelIndex idx = index( j, 0, pidx ); + SourcesModel::SourceType type = SourcesModel::indexType( idx ); + + if ( type == SourcesModel::DynamicPlaylistSource ) + { + playlist_ptr p = SourcesModel::indexToDynamicPlaylist( idx ); + if ( playlist.data() == p.data() ) + return idx; + } + } + } + + return QModelIndex(); +} + + +QModelIndex +SourcesModel::collectionToIndex( const Tomahawk::collection_ptr& collection ) +{ + for ( int i = 0; i < rowCount(); i++ ) + { + QModelIndex idx = index( i, 0 ); + SourcesModel::SourceType type = SourcesModel::indexType( idx ); + if ( type == SourcesModel::CollectionSource ) + { + SourceTreeItem* sti = SourcesModel::indexToTreeItem( idx ); + if ( sti && !sti->source().isNull() && sti->source()->collection().data() == collection.data() ) + return idx; + } + } + + return QModelIndex(); +} + + bool SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role ) { diff --git a/src/sourcetree/sourcesmodel.h b/src/sourcetree/sourcesmodel.h index 2b761637b..e258e73ff 100644 --- a/src/sourcetree/sourcesmodel.h +++ b/src/sourcetree/sourcesmodel.h @@ -37,6 +37,10 @@ public: static Tomahawk::dynplaylist_ptr indexToDynamicPlaylist( const QModelIndex& index ); static SourceTreeItem* indexToTreeItem( const QModelIndex& index ); + QModelIndex playlistToIndex( const Tomahawk::playlist_ptr& playlist ); + QModelIndex dynamicPlaylistToIndex( const Tomahawk::dynplaylist_ptr& playlist ); + QModelIndex collectionToIndex( const Tomahawk::collection_ptr& collection ); + signals: void clicked( const QModelIndex& ); diff --git a/src/sourcetree/sourcetreeitem.cpp b/src/sourcetree/sourcetreeitem.cpp index 0e4ec8748..96fa06a8d 100644 --- a/src/sourcetree/sourcetreeitem.cpp +++ b/src/sourcetree/sourcetreeitem.cpp @@ -237,8 +237,8 @@ void SourceTreeItem::playlistAddedInternal( qlonglong ptr, const Tomahawk::playl subitem->setData( (qlonglong)this, SourceItemPointer ); m_columns.at( 0 )->appendRow( subitem ); - Q_ASSERT( qobject_cast((parent()->parent()) ) ); - qobject_cast((parent()->parent()))->expandAll(); +// Q_ASSERT( qobject_cast((parent()->parent()) ) ); +// qobject_cast((parent()->parent()))->expandAll(); p->loadRevision(); } diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index dbee09d92..177482a61 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -67,7 +67,7 @@ SourceTreeView::SourceTreeView( QWidget* parent ) setItemDelegate( new SourceDelegate( this ) ); setContextMenuPolicy( Qt::CustomContextMenu ); - connect( this, SIGNAL( customContextMenuRequested( const QPoint& ) ), SLOT( onCustomContextMenu( const QPoint& ) ) ); + connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) ); m_model = new SourcesModel( this ); m_proxyModel = new SourcesProxyModel( m_model, this ); @@ -77,14 +77,25 @@ SourceTreeView::SourceTreeView( QWidget* parent ) header()->setResizeMode( 0, QHeaderView::Stretch ); connect( m_model, SIGNAL( clicked( QModelIndex ) ), SIGNAL( clicked( QModelIndex ) ) ); - connect( this, SIGNAL( clicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); + connect( this, SIGNAL( clicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); - connect( selectionModel(), SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), SLOT( onSelectionChanged() ) ); + connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), SLOT( onSelectionChanged() ) ); connect( SourceList::instance(), SIGNAL( sourceRemoved( Tomahawk::source_ptr ) ), SLOT( onSourceOffline( Tomahawk::source_ptr ) ) ); m_model->appendItem( source_ptr() ); hideOfflineSources(); + + connect( PlaylistManager::instance(), SIGNAL( playlistActivated( Tomahawk::playlist_ptr ) ), + SLOT( onPlaylistActivated( Tomahawk::playlist_ptr ) ) ); + connect( PlaylistManager::instance(), SIGNAL( dynamicPlaylistActivated( Tomahawk::dynplaylist_ptr ) ), + SLOT( onDynamicPlaylistActivated( Tomahawk::dynplaylist_ptr ) ) ); + connect( PlaylistManager::instance(), SIGNAL( collectionActivated( Tomahawk::collection_ptr ) ), + SLOT( onCollectionActivated( Tomahawk::collection_ptr ) ) ); + connect( PlaylistManager::instance(), SIGNAL( superCollectionActivated() ), + SLOT( onSuperCollectionActivated() ) ); + connect( PlaylistManager::instance(), SIGNAL( tempPageActivated() ), + SLOT( onTempPageActivated() ) ); } @@ -143,6 +154,57 @@ SourceTreeView::onSourceOffline( Tomahawk::source_ptr src ) } +void +SourceTreeView::onPlaylistActivated( const Tomahawk::playlist_ptr& playlist ) +{ + QModelIndex idx = m_proxyModel->mapFromSource( m_model->playlistToIndex( playlist ) ); + if ( idx.isValid() ) + { + setCurrentIndex( idx ); + } +} + + +void +SourceTreeView::onDynamicPlaylistActivated( const Tomahawk::dynplaylist_ptr& playlist ) +{ + QModelIndex idx = m_proxyModel->mapFromSource( m_model->dynamicPlaylistToIndex( playlist ) ); + if ( idx.isValid() ) + { + setCurrentIndex( idx ); + } +} + + +void +SourceTreeView::onCollectionActivated( const Tomahawk::collection_ptr& collection ) +{ + QModelIndex idx = m_proxyModel->mapFromSource( m_model->collectionToIndex( collection ) ); + if ( idx.isValid() ) + { + setCurrentIndex( idx ); + } +} + + +void +SourceTreeView::onSuperCollectionActivated() +{ + QModelIndex idx = m_proxyModel->index( 0, 0 ); + if ( idx.isValid() ) + { + setCurrentIndex( idx ); + } +} + + +void +SourceTreeView::onTempPageActivated() +{ + clearSelection(); +} + + void SourceTreeView::onItemActivated( const QModelIndex& index ) { @@ -469,7 +531,7 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co QString desc = status ? sti->source()->textStatus() : tr( "Offline" ); if ( sti->source().isNull() ) desc = tr( "All available tracks" ); - if ( status && !sti->source()->currentTrack().isNull() ) + if ( status && desc.isEmpty() && !sti->source()->currentTrack().isNull() ) desc = sti->source()->currentTrack()->artist() + " - " + sti->source()->currentTrack()->track(); if ( desc.isEmpty() ) desc = tr( "Online" ); @@ -479,41 +541,39 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() ); painter->drawText( textRect, text ); - if ( !status ) + if ( status ) { - painter->restore(); - return; + painter->setRenderHint( QPainter::Antialiasing ); + + QRect figRect = o.rect.adjusted( o.rect.width() - figWidth - 18, 0, -10, -o.rect.height() + 16 ); + int hd = ( option.rect.height() - figRect.height() ) / 2; + figRect.adjust( 0, hd, 0, hd ); + + QColor figColor( 167, 183, 211 ); + painter->setPen( figColor ); + painter->setBrush( figColor ); + + QPen origpen = painter->pen(); + QPen pen = origpen; + pen.setWidth( 1.0 ); + painter->setPen( pen ); + painter->drawRect( figRect ); + + QPainterPath ppath; + ppath.moveTo( QPoint( figRect.x(), figRect.y() ) ); + ppath.quadTo( QPoint( figRect.x() - 8, figRect.y() + figRect.height() / 2 ), QPoint( figRect.x(), figRect.y() + figRect.height() ) ); + painter->drawPath( ppath ); + ppath.moveTo( QPoint( figRect.x() + figRect.width(), figRect.y() ) ); + ppath.quadTo( QPoint( figRect.x() + figRect.width() + 8, figRect.y() + figRect.height() / 2 ), QPoint( figRect.x() + figRect.width(), figRect.y() + figRect.height() ) ); + painter->drawPath( ppath ); + + painter->setPen( origpen ); + + QTextOption to( Qt::AlignCenter ); + painter->setFont( bold ); + painter->setPen( Qt::white ); + painter->drawText( figRect, tracks, to ); } - painter->setRenderHint( QPainter::Antialiasing ); - - QRect figRect = o.rect.adjusted( o.rect.width() - figWidth - 18, 0, -10, -o.rect.height() + 16 ); - int hd = ( option.rect.height() - figRect.height() ) / 2; - figRect.adjust( 0, hd, 0, hd ); - - QColor figColor( 167, 183, 211 ); - painter->setPen( figColor ); - painter->setBrush( figColor ); - - QPen origpen = painter->pen(); - QPen pen = origpen; - pen.setWidth( 1.0 ); - painter->setPen( pen ); - painter->drawRect( figRect ); - - QPainterPath ppath; - ppath.moveTo( QPoint( figRect.x(), figRect.y() ) ); - ppath.quadTo( QPoint( figRect.x() - 8, figRect.y() + figRect.height() / 2 ), QPoint( figRect.x(), figRect.y() + figRect.height() ) ); - painter->drawPath( ppath ); - ppath.moveTo( QPoint( figRect.x() + figRect.width(), figRect.y() ) ); - ppath.quadTo( QPoint( figRect.x() + figRect.width() + 8, figRect.y() + figRect.height() / 2 ), QPoint( figRect.x() + figRect.width(), figRect.y() + figRect.height() ) ); - painter->drawPath( ppath ); - - painter->setPen( origpen ); - - QTextOption to( Qt::AlignCenter ); - painter->setFont( bold ); - painter->setPen( Qt::white ); - painter->drawText( figRect, tracks, to ); painter->restore(); } diff --git a/src/sourcetree/sourcetreeview.h b/src/sourcetree/sourcetreeview.h index 10df5d54d..077fb2937 100644 --- a/src/sourcetree/sourcetreeview.h +++ b/src/sourcetree/sourcetreeview.h @@ -27,6 +27,12 @@ signals: void onOffline( const QModelIndex& index ); private slots: + void onPlaylistActivated( const Tomahawk::playlist_ptr& playlist ); + void onDynamicPlaylistActivated( const Tomahawk::dynplaylist_ptr& playlist ); + void onCollectionActivated( const Tomahawk::collection_ptr& collection ); + void onSuperCollectionActivated(); + void onTempPageActivated(); + void onItemActivated( const QModelIndex& index ); void onSelectionChanged(); diff --git a/src/tomahawk.protocol b/src/tomahawk.protocol new file mode 100644 index 000000000..3a393aa61 --- /dev/null +++ b/src/tomahawk.protocol @@ -0,0 +1,12 @@ +[Protocol] +exec=/home/leo/kde/tomahawk/build/tomahawk "%u" +protocol=tomahawk +input=none +output=none +helper=true +listing= +reading=false +writing=false +makedir=false +deleting=false + diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 45b4053c8..4d68b8aa7 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -175,6 +175,10 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) Tomahawk::setShortcutHandler( static_cast( m_shortcutHandler) ); Tomahawk::setApplicationHandler( this ); + + QFont f( QApplication::font() ); + f.setPointSize( f.pointSize() - 2 ); + QApplication::setFont( f ); #endif // Connect up shortcuts diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index 0767af108..0fb8fd67d 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -29,7 +29,6 @@ #include "utils/widgetdragfilter.h" #include "utils/xspfloader.h" #include "widgets/newplaylistwidget.h" -#include "widgets/welcomewidget.h" #include "audiocontrols.h" #include "settingsdialog.h" @@ -57,6 +56,8 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) #endif PlaylistManager* pm = new PlaylistManager( this ); + connect( pm, SIGNAL( historyBackAvailable( bool ) ), SLOT( onHistoryBackAvailable( bool ) ) ); + connect( pm, SIGNAL( historyForwardAvailable( bool ) ), SLOT( onHistoryForwardAvailable( bool ) ) ); connect( m_audioControls, SIGNAL( playPressed() ), pm, SLOT( onPlayClicked() ) ); connect( m_audioControls, SIGNAL( pausePressed() ), pm, SLOT( onPauseClicked() ) ); @@ -115,12 +116,17 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) ui->splitter->setCollapsible( 1, false ); ui->splitter->setHandleWidth( 1 ); -/* QToolBar* toolbar = addToolBar( "TomahawkToolbar" ); + QToolBar* toolbar = addToolBar( "TomahawkToolbar" ); toolbar->setObjectName( "TomahawkToolbar" ); - toolbar->addWidget( m_topbar ); toolbar->setMovable( false ); toolbar->setFloatable( false ); - toolbar->installEventFilter( new WidgetDragFilter( toolbar ) );*/ + toolbar->setIconSize( QSize( 32, 32 ) ); + toolbar->setToolButtonStyle( Qt::ToolButtonFollowStyle ); + toolbar->installEventFilter( new WidgetDragFilter( toolbar ) ); + + m_backAvailable = toolbar->addAction( QIcon( RESPATH "images/back.png" ), tr( "Back" ), PlaylistManager::instance(), SLOT( historyBack() ) ); + m_forwardAvailable = toolbar->addAction( QIcon( RESPATH "images/forward.png" ), tr( "Forward" ), PlaylistManager::instance(), SLOT( historyForward() ) ); + toolbar->addAction( QIcon( RESPATH "images/home.png" ), tr( "Home" ), PlaylistManager::instance(), SLOT( showWelcomePage() ) ); statusBar()->addPermanentWidget( m_audioControls, 1 ); @@ -135,8 +141,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) loadSettings(); setupSignals(); - - PlaylistManager::instance()->show( new WelcomeWidget(), tr( "Welcome to Tomahawk!" ), QString(), QPixmap( RESPATH "icons/tomahawk-icon-128x128.png" ) ); + PlaylistManager::instance()->showWelcomePage(); } @@ -354,6 +359,20 @@ TomahawkWindow::onPlaybackLoading( const Tomahawk::result_ptr& result ) } +void +TomahawkWindow::onHistoryBackAvailable( bool avail ) +{ + m_backAvailable->setEnabled( avail ); +} + + +void +TomahawkWindow::onHistoryForwardAvailable( bool avail ) +{ + m_forwardAvailable->setEnabled( avail ); +} + + void TomahawkWindow::onSipConnected() { diff --git a/src/tomahawkwindow.h b/src/tomahawkwindow.h index 5e6a24472..766066cd8 100644 --- a/src/tomahawkwindow.h +++ b/src/tomahawkwindow.h @@ -54,7 +54,9 @@ private slots: void addPeerManually(); void onPlaybackLoading( const Tomahawk::result_ptr& result ); - + void onHistoryBackAvailable( bool avail ); + void onHistoryForwardAvailable( bool avail ); + void showAboutTomahawk(); private: @@ -68,6 +70,9 @@ private: QNetworkAccessManager m_nam; QPushButton* m_statusButton; + QAction* m_backAvailable; + QAction* m_forwardAvailable; + Tomahawk::result_ptr m_currentTrack; QString m_windowTitle; }; diff --git a/src/web/api_v1.h b/src/web/api_v1.h index 6d89beddd..daaacc4fb 100644 --- a/src/web/api_v1.h +++ b/src/web/api_v1.h @@ -17,8 +17,15 @@ #include #include +#include #include "network/servent.h" +#include "tomahawkutils.h" +#include "tomahawk/tomahawkapp.h" +#include +#include +#include +#include class Api_v1 : public QxtWebSlotService { @@ -32,7 +39,81 @@ public: } public slots: + + // authenticating uses /auth_1 + // we redirect to /auth_2 for the callback + void auth_1( QxtWebRequestEvent* event ) { + qDebug() << "AUTH_1 HTTP" << event->url.toString(); + + if( !event->url.hasQueryItem( "website" ) || !event->url.hasQueryItem( "name" ) ) { + qDebug() << "Malformed HTTP resolve request"; + send404( event ); + } + + QString formToken = uuid(); + + if( event->url.hasQueryItem( "json" ) ) { // JSON response + QVariantMap m; + m[ "formtoken" ] = formToken; + sendJSON( m, event ); + } else { // webpage request + QString authPage = RESPATH "www/auth.html"; + QHash< QString, QString > args; + if( event->url.hasQueryItem( "receiverurl" ) ) + args[ "url" ] = QUrl::fromPercentEncoding( event->url.queryItemValue( "receiverurl" ).toUtf8() ); + args[ "formtoken" ] = formToken; + args[ "website" ] = QUrl::fromPercentEncoding( event->url.queryItemValue( "website" ).toUtf8() ); + args[ "name" ] = QUrl::fromPercentEncoding( event->url.queryItemValue( "name" ).toUtf8() ); + sendWebpageWithArgs( event, authPage, args ); + } + } + + void auth_2( QxtWebRequestEvent* event ) { + + qDebug() << "AUTH_2 HTTP" << event->url.toString(); + QUrl url = event->url; + url.setEncodedQuery( event->content->readAll() ); + if( !url.hasQueryItem( "website" ) || !url.hasQueryItem( "name" ) || !url.hasQueryItem( "formtoken" ) ) { + qDebug() << "Malformed HTTP resolve request"; + qDebug() << url.hasQueryItem( "website" ) << url.hasQueryItem( "name" ) << url.hasQueryItem( "formtoken" ); + send404( event ); + return; + } + + QString website = QUrl::fromPercentEncoding( url.queryItemValue( "website" ).toUtf8() ); + QString name = QUrl::fromPercentEncoding( url.queryItemValue( "name" ).toUtf8() ); + QByteArray authtoken = uuid().toLatin1(); + qDebug() << "HEADERS:" << event->headers; + if( !url.hasQueryItem( "receiverurl" ) && url.queryItemValue( "receiverurl" ).isEmpty() ) { //no receiver url, so do it ourselves + QString receiverUrl = QUrl::fromPercentEncoding( url.queryItemValue( "receiverurl" ).toUtf8() ); + if( url.hasQueryItem( "json" ) ) { + QVariantMap m; + m[ "authtoken" ] = authtoken; + + sendJSON( m, event ); + } else { + QString authPage = RESPATH "www/auth.na.html"; + QHash< QString, QString > args; + args[ "authcode" ] = authPage; + args[ "website" ] = QUrl::fromPercentEncoding( url.queryItemValue( "website" ).toUtf8() ); + args[ "name" ] = QUrl::fromPercentEncoding( url.queryItemValue( "name" ).toUtf8() ); + sendWebpageWithArgs( event, authPage, args ); + } + } else { // do what the client wants + QUrl receiverurl = QUrl( url.queryItemValue( "receiverurl" ).toUtf8(), QUrl::TolerantMode ); + receiverurl.addEncodedQueryItem( "authtoken", "#" + authtoken ); + qDebug() << "Got receiver url:" << receiverurl.toString(); + + QxtWebRedirectEvent* e = new QxtWebRedirectEvent( event->sessionID, event->requestID, receiverurl.toString() ); + postEvent( e ); + // TODO validation of receiverurl? + } + + DatabaseCommand_AddClientAuth* dbcmd = new DatabaseCommand_AddClientAuth( authtoken, website, name, event->headers.key( "ua" ) ); + Database::instance()->enqueue( QSharedPointer(dbcmd) ); + } + // all v1 api calls go to /api/ void api(QxtWebRequestEvent* event) { @@ -80,18 +161,35 @@ public slots: qDebug() << "404" << event->url.toString(); QxtWebPageEvent* wpe = new QxtWebPageEvent(event->sessionID, event->requestID, "

Not Found

"); wpe->status = 404; - wpe->statusMessage = "not found"; + wpe->statusMessage = "not feventound"; postEvent( wpe ); } void stat( QxtWebRequestEvent* event ) { + qDebug() << "Got Stat request:" << event->url.toString(); + m_storedEvent = event; + if( !event->content.isNull() ) + qDebug() << "BODY:" << event->content->readAll(); + if( event->url.hasQueryItem( "auth" ) ) { // check for auth status + DatabaseCommand_ClientAuthValid* dbcmd = new DatabaseCommand_ClientAuthValid( event->url.queryItemValue( "auth" ), this ); + connect( dbcmd, SIGNAL( authValid( QString, QString, bool ) ), this, SLOT( statResult( QString, QString, bool ) ) ); + Database::instance()->enqueue( QSharedPointer(dbcmd) ); + + } else { + statResult( QString(), QString(), false ); + } + } + + void statResult( const QString& clientToken, const QString& name, bool valid ) { QVariantMap m; m.insert( "name", "playdar" ); m.insert( "version", "0.1.1" ); // TODO (needs to be >=0.1.1 for JS to work) - m.insert( "authenticated", true ); // TODO + m.insert( "authenticated", valid ); // TODO m.insert( "capabilities", QVariantList() ); - sendJSON( m, event ); + sendJSON( m, m_storedEvent ); + + m_storedEvent = 0; } void resolve( QxtWebRequestEvent* event ) @@ -119,6 +217,12 @@ public slots: sendJSON( r, event ); } + void staticdata( QxtWebRequestEvent* event ) { + if( event->url.path().contains( "playdar_auth_logo.gif" ) ) { + // TODO handle + } + } + void get_results( QxtWebRequestEvent* event ) { if( !event->url.hasQueryItem("qid") ) @@ -174,6 +278,23 @@ public slots: qDebug() << "JSON response" << event->url.toString() << body; } + // load an html template from a file, replace args from map + // then serve + void sendWebpageWithArgs( QxtWebRequestEvent* event, const QString& filenameSource, const QHash< QString, QString >& args ) { + if( !QFile::exists( filenameSource ) ) + qWarning() << "Passed invalid file for html source:" << filenameSource; + + QFile f( filenameSource ); + f.open( QIODevice::ReadOnly ); + QByteArray html = f.readAll(); + + foreach( const QString& param, args.keys() ) { + html.replace( QString( "<%%1%>" ).arg( param.toUpper() ), args.value( param ).toUtf8() ); + } + + QxtWebPageEvent* e = new QxtWebPageEvent( event->sessionID, event->requestID, html ); + postEvent( e ); + } void index(QxtWebRequestEvent* event) { @@ -182,6 +303,8 @@ public slots: } +private: + QxtWebRequestEvent* m_storedEvent; }; #endif