From 0742e1d681d02d482a2827be6caf4405c1f5bb21 Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 5 Aug 2015 00:05:10 +0200 Subject: [PATCH] [UI] Added some stats on the track view --- src/database/Track.cpp | 14 +++++++ src/database/Track.hpp | 11 ++++-- src/ui/audio/desktop/DesktopAudio.cpp | 11 +++++- src/ui/audio/desktop/Filter.hpp | 8 ---- src/ui/audio/desktop/PlayQueue.cpp | 2 +- src/ui/audio/desktop/TableFilter.cpp | 6 +-- src/ui/audio/desktop/TrackView.cpp | 55 +++++++++++++++++++++------ src/ui/audio/desktop/TrackView.hpp | 5 +++ 8 files changed, 83 insertions(+), 29 deletions(-) diff --git a/src/database/Track.cpp b/src/database/Track.cpp index 062ea370..7ad69914 100644 --- a/src/database/Track.cpp +++ b/src/database/Track.cpp @@ -113,6 +113,20 @@ Track::getUIQuery(Wt::Dbo::Session& session, SearchFilter filter) return query; } +Track::StatsQueryResult +Track::getStats(Wt::Dbo::Session& session, SearchFilter filter) +{ + SqlQuery sqlQuery = generatePartialQuery(filter); + + Wt::Dbo::Query query = session.query( "SELECT COUNT(DISTINCT t.id), SUM(t.duration) FROM track t INNER JOIN artist a ON t.artist_id = a.id INNER JOIN genre g ON g.id = t_g.genre_id INNER JOIN track_genre t_g ON t_g.track_id = t.id INNER JOIN release r ON r.id = t.release_id " + sqlQuery.where().get()); + + for (const std::string& bindArg : sqlQuery.where().getBindArgs()) + query.bind(bindArg); + + return query; +} + + std::vector Track::getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size) { diff --git a/src/database/Track.hpp b/src/database/Track.hpp index cad39c44..14099ce7 100644 --- a/src/database/Track.hpp +++ b/src/database/Track.hpp @@ -105,10 +105,8 @@ class Track static pointer getByPath(Wt::Dbo::Session& session, const boost::filesystem::path& p); static pointer getById(Wt::Dbo::Session& session, id_type id); static pointer getByMBID(Wt::Dbo::Session& session, const std::string& MBID); - static Wt::Dbo::collection< pointer > getAll(Wt::Dbo::Session& session); - - // Used for remote static std::vector getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1); + static Wt::Dbo::collection< pointer > getAll(Wt::Dbo::Session& session); // Utility fonctions // MVC models for the user interface @@ -127,6 +125,13 @@ class Track static Wt::Dbo::Query< UIQueryResult > getUIQuery(Wt::Dbo::Session& session, SearchFilter filter); static void updateUIQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel< UIQueryResult >& model, SearchFilter filter, const std::vector& columnNames = std::vector()); + // Stats for a given search filter + typedef boost::tuple< + int, // Total tracks + boost::posix_time::time_duration // Total duration + > StatsQueryResult; + static StatsQueryResult getStats(Wt::Dbo::Session& session, SearchFilter filter); + // Create utility static pointer create(Wt::Dbo::Session& session, const boost::filesystem::path& p); diff --git a/src/ui/audio/desktop/DesktopAudio.cpp b/src/ui/audio/desktop/DesktopAudio.cpp index 7f5bc9a9..3aa25975 100644 --- a/src/ui/audio/desktop/DesktopAudio.cpp +++ b/src/ui/audio/desktop/DesktopAudio.cpp @@ -102,8 +102,13 @@ _playQueue(nullptr) Wt::WPushButton* addBtn = new Wt::WPushButton("Add"); addBtn->setStyleClass("btn-sm"); trackControls->addWidget(addBtn); - trackControls->addWidget(new Wt::WText("Total duration: "), 1); + Wt::WText *statsText = new Wt::WText(); + statsText->setStyleClass("vertical-align"); + trackControls->addWidget(statsText, 1); + _trackView->statsUpdated().connect(std::bind([=] (Wt::WString stats) { + statsText->setText(stats); + }, std::placeholders::_1)); trackLayout->addLayout(trackControls); @@ -111,6 +116,7 @@ _playQueue(nullptr) _filterChain.addFilter(_trackView); + _playQueue = new PlayQueue(); // Playlist/PlayQueue @@ -216,6 +222,9 @@ _playQueue(nullptr) playlistRefreshMenus(); + + // Initially, search for everything + _filterChain.searchKeyword(""); } void diff --git a/src/ui/audio/desktop/Filter.hpp b/src/ui/audio/desktop/Filter.hpp index 194f2867..5feb120a 100644 --- a/src/ui/audio/desktop/Filter.hpp +++ b/src/ui/audio/desktop/Filter.hpp @@ -30,14 +30,6 @@ namespace Desktop { class Filter { public: - - struct Constraint { - std::vector search; - - typedef std::map > ColumnValues; - ColumnValues columnValues; - }; - Filter() {} virtual ~Filter() {} diff --git a/src/ui/audio/desktop/PlayQueue.cpp b/src/ui/audio/desktop/PlayQueue.cpp index 3f1e6fc8..ab1299fe 100644 --- a/src/ui/audio/desktop/PlayQueue.cpp +++ b/src/ui/audio/desktop/PlayQueue.cpp @@ -501,7 +501,7 @@ PlayQueue::delSelected(void) int minId = _model->rowCount(); Wt::WModelIndexSet indexSet = this->selectedIndexes(); - BOOST_REVERSE_FOREACH(Wt::WModelIndex index, indexSet) + for (Wt::WModelIndex index : indexSet) { _model->removeRow(index.row()); if (index.row() < minId) diff --git a/src/ui/audio/desktop/TableFilter.cpp b/src/ui/audio/desktop/TableFilter.cpp index 2e410870..87ed9079 100644 --- a/src/ui/audio/desktop/TableFilter.cpp +++ b/src/ui/audio/desktop/TableFilter.cpp @@ -17,8 +17,6 @@ * along with LMS. If not, see . */ -#include - #include #include "database/Types.hpp" @@ -163,8 +161,8 @@ TableFilterArtist::getConstraint(SearchFilter& filter) { Wt::WModelIndexSet indexSet = this->selectedIndexes(); - BOOST_FOREACH(Wt::WModelIndex index, indexSet) { - + for (Wt::WModelIndex index : indexSet) + { if (!index.isValid()) continue; diff --git a/src/ui/audio/desktop/TrackView.cpp b/src/ui/audio/desktop/TrackView.cpp index b98a0198..0b8cbb6b 100644 --- a/src/ui/audio/desktop/TrackView.cpp +++ b/src/ui/audio/desktop/TrackView.cpp @@ -17,9 +17,6 @@ * along with LMS. If not, see . */ - -#include - #include #include @@ -31,6 +28,8 @@ namespace UserInterface { namespace Desktop { +using namespace Database; + TrackView::TrackView(Wt::WContainerWidget* parent) : Wt::WTableView( parent ) { @@ -48,9 +47,9 @@ TrackView::TrackView(Wt::WContainerWidget* parent) "Genres", }; - Database::SearchFilter filter; + SearchFilter filter; - Database::Track::updateUIQueryModel(DboSession(), _queryModel, filter, columnNames); + Track::updateUIQueryModel(DboSession(), _queryModel, filter, columnNames); _queryModel.setBatchSize(300); @@ -107,15 +106,47 @@ TrackView::TrackView(Wt::WContainerWidget* parent) } +void +TrackView::emitStats(const SearchFilter& filter) +{ + Wt::Dbo::Transaction transaction (DboSession()); + + // Update stats on the view + Track::StatsQueryResult stats = Track::getStats(DboSession(), filter); + + transaction.commit(); + + int nbTracks = stats.get<0>(); + boost::posix_time::time_duration totalDuration = stats.get<1>(); + + std::ostringstream oss; + + oss << nbTracks << " track" << (nbTracks > 1 ? "s" : "") << ", "; + + if (totalDuration.hours() >= 24) + { + auto days = totalDuration.hours() / 24; + oss << days << " day" << (days > 1 ? "s " : " "); + } + + oss << std::setw(2) << std::setfill('0') << totalDuration.hours() % 24 + << ":" << std::setw(2) << std::setfill('0') << totalDuration.minutes() + << ":" << std::setw(2) << std::setfill('0') << totalDuration.seconds(); + + _sigStatsUpdated.emit(Wt::WString(oss.str())); +} + // Set constraints created by parent filters void -TrackView::refresh(Database::SearchFilter& filter) +TrackView::refresh(SearchFilter& filter) { - Database::Track::updateUIQueryModel(DboSession(), _queryModel, filter); + Track::updateUIQueryModel(DboSession(), _queryModel, filter); + + emitStats(filter); } void -TrackView::getSelectedTracks(std::vector& track_ids) +TrackView::getSelectedTracks(std::vector& track_ids) { LMS_LOG(MOD_UI, SEV_DEBUG) << "Getting selected tracks..."; @@ -126,7 +157,7 @@ TrackView::getSelectedTracks(std::vector& track_ids) if (!index.isValid()) continue; - Database::Track::id_type id = _queryModel.resultRow( index.row() ).get<0>(); + Track::id_type id = _queryModel.resultRow( index.row() ).get<0>(); track_ids.push_back(id); } @@ -157,16 +188,16 @@ TrackView::getFirstSelectedTrackPosition(void) } void -TrackView::getTracks(std::vector& trackIds) +TrackView::getTracks(std::vector& trackIds) { LMS_LOG(MOD_UI, SEV_DEBUG) << "Getting all tracks..."; Wt::Dbo::Transaction transaction(DboSession()); - Wt::Dbo::collection results = _queryModel.query(); + Wt::Dbo::collection results = _queryModel.query(); for (auto it = results.begin(); it != results.end(); ++it) { - Database::Track::id_type id = it->get<0>(); + Track::id_type id = it->get<0>(); trackIds.push_back(id); } diff --git a/src/ui/audio/desktop/TrackView.hpp b/src/ui/audio/desktop/TrackView.hpp index f922589e..2fef0556 100644 --- a/src/ui/audio/desktop/TrackView.hpp +++ b/src/ui/audio/desktop/TrackView.hpp @@ -55,12 +55,17 @@ class TrackView : public Wt::WTableView, public Filter void getTracks(std::vector& track_ids); typedef Wt::Signal SigTrackDoubleClicked; + typedef Wt::Signal SigStatsUpdated; SigTrackDoubleClicked& trackDoubleClicked() { return _sigTrackDoubleClicked; } + SigStatsUpdated& statsUpdated() { return _sigStatsUpdated; } private: SigTrackDoubleClicked _sigTrackDoubleClicked; + SigStatsUpdated _sigStatsUpdated; + + void emitStats(const Database::SearchFilter& filter); typedef Database::Track::UIQueryResult ResultType; Wt::Dbo::QueryModel< ResultType > _queryModel;