diff --git a/src/libtomahawk-widgets/NetworkActivityWidget.cpp b/src/libtomahawk-widgets/NetworkActivityWidget.cpp index c97ea8f81..53cdf0675 100644 --- a/src/libtomahawk-widgets/NetworkActivityWidget.cpp +++ b/src/libtomahawk-widgets/NetworkActivityWidget.cpp @@ -23,6 +23,7 @@ #include "database/DatabaseCommand_NetworkCharts.h" #include "database/DatabaseCommand_TrendingTracks.h" #include "playlist/AlbumItemDelegate.h" +#include "playlist/TreeProxyModel.h" #include "playlist/ViewHeader.h" #include "utils/AnimatedSpinner.h" #include "utils/ImageRegistry.h" @@ -185,6 +186,34 @@ NetworkActivityWidget::NetworkActivityWidget( QWidget* parent ) // connect( model, SIGNAL( emptinessChanged( bool ) ), this, SLOT( updatePlaylists() ) ); } + // Trending artists + { + d->artistsModel = new PlayableModel( d->ui->trendingArtistsView ); + d->ui->trendingArtistsView->setPlayableModel( d->artistsModel ); + } + { + d->ui->trendingArtistsView->setFrameShape( QFrame::NoFrame ); + d->ui->trendingArtistsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + d->ui->trendingArtistsView->proxyModel()->sort( -1 ); + d->ui->trendingArtistsView->proxyModel()->setHideDupeItems( true ); + + d->ui->trendingArtistsView->setAutoResize( true ); + d->ui->trendingArtistsView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + d->ui->trendingArtistsView->setStyleSheet( "QListView { background-color: transparent; }" ); + TomahawkStyle::stylePageFrame( d->ui->trendingArtistsFrame ); + } + { + QFont f = d->ui->trendingArtistsLabel->font(); + f.setFamily( "Pathway Gothic One" ); + + QPalette p = d->ui->trendingArtistsLabel->palette(); + p.setColor( QPalette::Foreground, TomahawkStyle::PAGE_CAPTION ); + + d->ui->trendingArtistsLabel->setFont( f ); + d->ui->trendingArtistsLabel->setPalette( p ); + } + + { QScrollArea* area = new QScrollArea(); area->setWidgetResizable( true ); @@ -214,6 +243,9 @@ NetworkActivityWidget::NetworkActivityWidget( QWidget* parent ) connect( d->worker, SIGNAL( hotPlaylists(QList) ), SLOT(hotPlaylists(QList)), Qt::QueuedConnection); + connect( d->worker, SIGNAL( trendingArtists( QList< Tomahawk::artist_ptr > ) ), + SLOT( trendingArtists( QList< Tomahawk::artist_ptr > ) ), + Qt::QueuedConnection ); connect( d->worker, SIGNAL( finished() ), d->workerThread, SLOT( quit() ), Qt::QueuedConnection ); @@ -343,6 +375,17 @@ NetworkActivityWidget::hotPlaylists( const QList& playlists ) } +void +NetworkActivityWidget::trendingArtists( const QList& artists ) +{ + Q_D( NetworkActivityWidget ); + + d->artistsModel->startLoading(); + d->artistsModel->appendArtists( artists ); + d->artistsModel->finishLoading(); +} + + void NetworkActivityWidget::trendingTracks( const QList& tracks ) { diff --git a/src/libtomahawk-widgets/NetworkActivityWidget.h b/src/libtomahawk-widgets/NetworkActivityWidget.h index 8462b7282..b076c4936 100644 --- a/src/libtomahawk-widgets/NetworkActivityWidget.h +++ b/src/libtomahawk-widgets/NetworkActivityWidget.h @@ -61,6 +61,7 @@ public: virtual bool jumpToCurrentTrack(); static const uint numberOfHotPlaylists = 3; + static const uint numberOfTrendingArtists = 3; static const uint numberOfTrendingTracks = 6; static const uint numberOfNetworkChartEntries = 20; @@ -74,6 +75,7 @@ private slots: void overallCharts( const QList& ); void hotPlaylists( const QList& playlists ); + void trendingArtists( const QList< Tomahawk::artist_ptr >& artists ); void trendingTracks( const QList< Tomahawk::track_ptr >& tracks ); void leftCrumbIndexChanged( const QModelIndex& ); diff --git a/src/libtomahawk-widgets/NetworkActivityWidget.ui b/src/libtomahawk-widgets/NetworkActivityWidget.ui index 986186550..8fd0dcdd2 100644 --- a/src/libtomahawk-widgets/NetworkActivityWidget.ui +++ b/src/libtomahawk-widgets/NetworkActivityWidget.ui @@ -99,6 +99,34 @@ + + + + + + + + 20 + + + + Trending Artists + + + + + + + + 320 + 0 + + + + + + + @@ -149,16 +177,21 @@ + + PlaylistView + QTreeView +
playlist/PlaylistView.h
+
+ + GridView + QListView +
playlist/GridView.h
+
Tomahawk::Widgets::PlaylistWidget QListWidget
PlaylistWidget.h
- - PlaylistView - QTreeView -
playlist/PlaylistView.h
-
Tomahawk::Breadcrumb QWidget diff --git a/src/libtomahawk-widgets/NetworkActivityWidget_p.h b/src/libtomahawk-widgets/NetworkActivityWidget_p.h index 808b5f2a3..7cde02be9 100644 --- a/src/libtomahawk-widgets/NetworkActivityWidget_p.h +++ b/src/libtomahawk-widgets/NetworkActivityWidget_p.h @@ -49,6 +49,7 @@ private: Tomahawk::playlistinterface_ptr playlistInterface; QStandardItemModel* crumbModelLeft; QSortFilterProxyModel* sortedProxy; + QPointer artistsModel; QPointer weeklyChartsModel; QPointer monthlyChartsModel; diff --git a/src/libtomahawk-widgets/NetworkActivityWorker.cpp b/src/libtomahawk-widgets/NetworkActivityWorker.cpp index 7ec76149c..2580c2290 100644 --- a/src/libtomahawk-widgets/NetworkActivityWorker.cpp +++ b/src/libtomahawk-widgets/NetworkActivityWorker.cpp @@ -22,6 +22,7 @@ #include "database/DatabaseCommand_CalculatePlaytime.h" #include "database/DatabaseCommand_LoadAllPlaylists.h" #include "database/DatabaseCommand_LoadAllSources.h" +#include "database/DatabaseCommand_TrendingArtists.h" #include "database/DatabaseCommand_TrendingTracks.h" #include "database/DatabaseImpl.h" #include "NetworkActivityWidget.h" @@ -62,6 +63,15 @@ NetworkActivityWorker::run() Qt::QueuedConnection ); Database::instance()->enqueue( dbcmd_ptr( dbcmd ) ); } + { + qRegisterMetaType< QList< QPair< double, Tomahawk::artist_ptr > > >("QList< QPair< double, Tomahawk::artist_ptr > >"); + DatabaseCommand_TrendingArtists* dbcmd = new DatabaseCommand_TrendingArtists(); + dbcmd->setLimit( Tomahawk::Widgets::NetworkActivityWidget::numberOfTrendingArtists ); + connect( dbcmd, SIGNAL( done( QList< QPair< double, Tomahawk::artist_ptr > > ) ), + SLOT( trendingArtistsReceived( QList< QPair< double, Tomahawk::artist_ptr > >) ), + Qt::QueuedConnection ); + Database::instance()->enqueue( dbcmd_ptr( dbcmd ) ); + } { /* DatabaseCommand_LoadAllSources* dbcmd = new DatabaseCommand_LoadAllSources(); connect( dbcmd, SIGNAL( done( QList ) ), @@ -141,6 +151,25 @@ NetworkActivityWorker::playtime( const Tomahawk::playlist_ptr& playlist, uint pl } +void +NetworkActivityWorker::trendingArtistsReceived( const QList >& _artists ) +{ + Q_D( NetworkActivityWorker ); + d->trendingArtistsDone = true; + + QList< artist_ptr > artists; + QList< QPair< double, artist_ptr > >::const_iterator iter = _artists.constBegin(); + const QList< QPair< double, artist_ptr > >::const_iterator end = _artists.constEnd(); + for(; iter != end; ++iter) + { + artists << iter->second; + } + emit trendingArtists( artists ); + + checkDone(); +} + + void NetworkActivityWorker::trendingTracksReceived( const QList >& _tracks) { @@ -163,7 +192,7 @@ void NetworkActivityWorker::checkDone() { Q_D( NetworkActivityWorker ); - if ( d->trendingTracksDone /* && d->hotPlaylistsDone */ ) + if ( d->trendingTracksDone && d->trendingArtistsDone /* && d->hotPlaylistsDone */ ) { emit finished(); } diff --git a/src/libtomahawk-widgets/NetworkActivityWorker.h b/src/libtomahawk-widgets/NetworkActivityWorker.h index a68154c35..89989c5bb 100644 --- a/src/libtomahawk-widgets/NetworkActivityWorker.h +++ b/src/libtomahawk-widgets/NetworkActivityWorker.h @@ -44,6 +44,7 @@ public slots: void run(); signals: + void trendingArtists( const QList< Tomahawk::artist_ptr >& artists ); void trendingTracks( const QList& tracks ); void hotPlaylists( const QList& playlists ); void finished(); @@ -55,6 +56,7 @@ private slots: void allPlaylistsReceived( const QHash< Tomahawk::playlist_ptr, QStringList >& playlists ); void allSourcesReceived( const QList< Tomahawk::source_ptr >& sources ); void playtime( const Tomahawk::playlist_ptr& playlist , uint playtime ); + void trendingArtistsReceived( const QList< QPair< double,Tomahawk::artist_ptr > >& tracks ); void trendingTracksReceived( const QList< QPair< double,Tomahawk::track_ptr > >& tracks ); private: diff --git a/src/libtomahawk-widgets/NetworkActivityWorker_p.h b/src/libtomahawk-widgets/NetworkActivityWorker_p.h index de0a20114..416f88434 100644 --- a/src/libtomahawk-widgets/NetworkActivityWorker_p.h +++ b/src/libtomahawk-widgets/NetworkActivityWorker_p.h @@ -35,6 +35,7 @@ class NetworkActivityWorkerPrivate public: NetworkActivityWorkerPrivate( NetworkActivityWorker* q ) : q_ptr( q ) + , trendingArtistsDone( false ) , trendingTracksDone( false ) , hotPlaylistsDone( false ) , playtimesToLoad( 0 ) @@ -45,6 +46,7 @@ public: NetworkActivityWorker* q_ptr; Q_DECLARE_PUBLIC( NetworkActivityWorker ) private: + bool trendingArtistsDone; bool trendingTracksDone; bool hotPlaylistsDone; diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index df552d953..7f9351163 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -290,6 +290,7 @@ list(APPEND libSources database/DatabaseCommand_SourceOffline.cpp database/DatabaseCommand_TrackAttributes.cpp database/DatabaseCommand_TrackStats.cpp + database/DatabaseCommand_TrendingArtists.cpp database/DatabaseCommand_TrendingTracks.cpp database/DatabaseCommand_UpdateSearchIndex.cpp database/DatabaseCommandLoggable.cpp diff --git a/src/libtomahawk/database/DatabaseCommand_TrendingArtists.cpp b/src/libtomahawk/database/DatabaseCommand_TrendingArtists.cpp new file mode 100644 index 000000000..99df79be3 --- /dev/null +++ b/src/libtomahawk/database/DatabaseCommand_TrendingArtists.cpp @@ -0,0 +1,127 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2013, Uwe L. Korn + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "DatabaseCommand_TrendingArtists_p.h" + +#include "database/DatabaseImpl.h" +#include "Artist.h" + +#include + +namespace Tomahawk { + + +DatabaseCommand_TrendingArtists::DatabaseCommand_TrendingArtists( QObject* parent ) + : DatabaseCommand( parent, new DatabaseCommand_TrendingArtistsPrivate( this ) ) +{ +} + + +DatabaseCommand_TrendingArtists::~DatabaseCommand_TrendingArtists() +{ +} + + +void +DatabaseCommand_TrendingArtists::exec( DatabaseImpl* dbi ) +{ + Q_D( DatabaseCommand_TrendingArtists ); + + QString limit; + if ( d->amount > 0 ) + { + limit = QString( "LIMIT 0, %1" ).arg( d->amount ); + } + + QDateTime now = QDateTime::currentDateTime(); + QDateTime _1WeekAgo = now.addDays( -7 ); + QDateTime _2WeeksAgo = now.addDays( -14 ); + + uint peersLastWeek = 1; // Use a default of 1 to be able to do certain mathematical computations without Div-by-0 Errors. + { + // Get the number of active peers in the last week. + // We could just use the number of peers instead but that would include old peers that may have been inactive for a long while. + + QString peersLastWeekSql = QString( + " SELECT COUNT(DISTINCT source ) " + " FROM playback_log " + " WHERE playback_log.source IS NOT NULL " // exclude self + " AND playback_log.playtime >= %1 " + ).arg( _1WeekAgo.toTime_t() ); + TomahawkSqlQuery query = dbi->newquery(); + query.prepare( peersLastWeekSql ); + query.exec(); + while ( query.next() ) + { + peersLastWeek = std::max( 1u, query.value( 0 ).toUInt() ); + } + } + + + QString timespanSql = QString( + " SELECT COUNT(*) as counter, track.artist as artistid " + " FROM playback_log " + " JOIN track ON track.id = playback_log.track " + " WHERE playback_log.source IS NOT NULL " // exclude self + " AND playback_log.playtime >= %1 AND playback_log.playtime <= %2 " + " GROUP BY track.artist " + ); + QString lastWeekSql = timespanSql.arg( _1WeekAgo.toTime_t() ).arg( now.toTime_t() ); + QString _1BeforeLastWeekSql = timespanSql.arg( _2WeeksAgo.toTime_t() ).arg( _1WeekAgo.toTime_t() ); + QString formula = QString( + " ( lastweek.counter / weekbefore.counter ) " + " * " + " max(0, 1 - (%1 / (4*min(lastweek.counter, weekbefore.counter )) ) )" + ).arg( peersLastWeek ); + QString sql = QString( + " SELECT artist.name, ( %4 ) as trending " + " FROM ( %1 ) lastweek, ( %2 ) weekbefore, artist " + " WHERE lastweek.artistid = weekbefore.artistid " + " AND artist.id = lastweek.artistid " + " AND ( lastweek.counter - weekbefore.counter ) > 0" + " ORDER BY trending DESC %3 " + ).arg( lastWeekSql ).arg( _1BeforeLastWeekSql ).arg( limit ).arg( formula ); + TomahawkSqlQuery query = dbi->newquery(); + query.prepare( sql ); + query.exec(); + + + + QList< QPair< double, Tomahawk::artist_ptr > > artists; + while ( query.next() ) + { + Tomahawk::artist_ptr artist = Artist::get( query.value( 0 ).toString() ); + if ( !artist ) + continue; + + artists << QPair< double, artist_ptr >( query.value( 1 ).toDouble(), artist ); + } + + emit done( artists ); +} + + +void +DatabaseCommand_TrendingArtists::setLimit( unsigned int amount ) +{ + Q_D( DatabaseCommand_TrendingArtists ); + d->amount = amount; +} + + +} // namespace Tomahawk diff --git a/src/libtomahawk/database/DatabaseCommand_TrendingArtists.h b/src/libtomahawk/database/DatabaseCommand_TrendingArtists.h new file mode 100644 index 000000000..2bc7607cf --- /dev/null +++ b/src/libtomahawk/database/DatabaseCommand_TrendingArtists.h @@ -0,0 +1,53 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2013, Uwe L. Korn + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#pragma once +#ifndef TOMAHAWK_DATABASECOMMAND_TRENDINGARTISTS_H +#define TOMAHAWK_DATABASECOMMAND_TRENDINGARTISTS_H + +#include "DatabaseCommand.h" + +namespace Tomahawk { + +class DatabaseCommand_TrendingArtistsPrivate; + +class DLLEXPORT DatabaseCommand_TrendingArtists : public Tomahawk::DatabaseCommand +{ + Q_OBJECT +public: + explicit DatabaseCommand_TrendingArtists( QObject *parent = 0 ); + virtual ~DatabaseCommand_TrendingArtists(); + + virtual void exec( DatabaseImpl* ); + + virtual bool doesMutates() const { return false; } + virtual QString commandname() const { return "trendingartists"; } + + void setLimit( unsigned int amount ); + +signals: + void done( const QList >& artists ); + +private: + Q_DECLARE_PRIVATE( DatabaseCommand_TrendingArtists ) + +}; + +} // namespace Tomahawk + +#endif // TOMAHAWK_DATABASECOMMAND_TRENDINGARTISTS_H diff --git a/src/libtomahawk/database/DatabaseCommand_TrendingArtists_p.h b/src/libtomahawk/database/DatabaseCommand_TrendingArtists_p.h new file mode 100644 index 000000000..fa055c75d --- /dev/null +++ b/src/libtomahawk/database/DatabaseCommand_TrendingArtists_p.h @@ -0,0 +1,46 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2013, Uwe L. Korn + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#pragma once +#ifndef DATABASECOMMAND_TRENDINGARTISTS_P_H +#define DATABASECOMMAND_TRENDINGARTISTS_P_H + +#include "database/DatabaseCommand_p.h" +#include "database/DatabaseCommand_TrendingArtists.h" + +namespace Tomahawk +{ + +class DatabaseCommand_TrendingArtistsPrivate: DatabaseCommandPrivate +{ +public: + DatabaseCommand_TrendingArtistsPrivate( DatabaseCommand_TrendingArtists* q ) + : DatabaseCommandPrivate( q ) + , amount( 0 ) + { + } + + Q_DECLARE_PUBLIC( DatabaseCommand_TrendingArtists ) + +private: + uint amount; +}; + +} // Tomahawk + +#endif // DATABASECOMMAND_TRENDINGARTISTS_P_H diff --git a/src/libtomahawk/widgets/WhatsHotWidget.cpp b/src/libtomahawk/widgets/WhatsHotWidget.cpp index 3c012c60f..89dd1bb9d 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.cpp +++ b/src/libtomahawk/widgets/WhatsHotWidget.cpp @@ -552,7 +552,7 @@ WhatsHotWidget::setLeftViewAlbums( PlayableModel* model ) void WhatsHotWidget::setLeftViewArtists( TreeModel* model ) { - ui->artistsViewLeft->proxyModel()->setStyle( PlayableProxyModel::Collection ); + ui->artistsViewLeft->proxyModel()->setStyle( PlayableProxyModel::Large ); ui->artistsViewLeft->setTreeModel( model ); ui->artistsViewLeft->proxyModel()->sort( -1 ); // disable sorting, must be called after artistsViewLeft->setTreeModel ui->stackLeft->setCurrentIndex( 1 ); diff --git a/src/libtomahawk/widgets/WhatsHotWidget.ui b/src/libtomahawk/widgets/WhatsHotWidget.ui index dba284e79..ad0c00bf8 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.ui +++ b/src/libtomahawk/widgets/WhatsHotWidget.ui @@ -63,27 +63,27 @@ + + PlaylistView + QTreeView +
playlist/PlaylistView.h
+
GridView QListView
playlist/GridView.h
- - TreeView - QTreeView -
playlist/TreeView.h
-
- - PlaylistView - QTreeView -
playlist/PlaylistView.h
-
Tomahawk::Breadcrumb QWidget
widgets/Breadcrumb.h
1
+ + TreeView + QTreeView +
playlist/TreeView.h
+