Reworked the project layout

This commit is contained in:
emeric
2014-10-10 20:41:34 +02:00
parent 92a176c899
commit 49ff050539
146 changed files with 156 additions and 162 deletions
+126
View File
@@ -0,0 +1,126 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <boost/foreach.hpp>
#include <Wt/WTable> // TODO
#include <Wt/WBreak> // TODO
#include "AudioDatabaseWidget.hpp"
#include "TableFilterWidget.hpp"
#include "SearchFilterWidget.hpp"
#include "TrackWidget.hpp"
namespace UserInterface {
AudioDatabaseWidget::AudioDatabaseWidget( Database::Handler& db, Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent),
_refreshingFilters(false)
{
std::size_t idFilter (0);
{
SearchFilterWidget* search = new SearchFilterWidget(this);
_filters.push_back( search );
search->update().connect( boost::bind(&AudioDatabaseWidget::handleFilterUpdated, this, idFilter++) );
}
Wt::WTable* table = new Wt::WTable(this);
{
TableFilterWidget* filterTable = new TableFilterWidget(db, "genre", "name", table->elementAt(0,0));
_filters.push_back( filterTable );
filterTable->update().connect( boost::bind(&AudioDatabaseWidget::handleFilterUpdated, this, idFilter++) );
}
{
TableFilterWidget* filterTable = new TableFilterWidget(db, "artist", "name", table->elementAt(0,1));
_filters.push_back( filterTable );
filterTable->update().connect( boost::bind(&AudioDatabaseWidget::handleFilterUpdated, this, idFilter++) );
}
{
TableFilterWidget* filterTable = new TableFilterWidget(db, "release", "name", table->elementAt(0,2));
_filters.push_back( filterTable );
filterTable->update().connect( boost::bind(&AudioDatabaseWidget::handleFilterUpdated, this, idFilter++) );
}
{
TrackWidget* track = new TrackWidget(db, this);
_filters.push_back( track );
track->trackSelected().connect(this, &AudioDatabaseWidget::handleTrackSelected);
}
}
void
AudioDatabaseWidget::search(const std::string& text)
{
SearchFilterWidget* searchWidget ( dynamic_cast<SearchFilterWidget*>(_filters.front() ) );
searchWidget->setText(text);
}
void
AudioDatabaseWidget::handleTrackSelected(boost::filesystem::path p)
{
_trackSelected.emit(p);
}
void
AudioDatabaseWidget::handleFilterUpdated(std::size_t idFilterUpdated)
{
// TODO disconnect from event!
if (_refreshingFilters)
return;
_refreshingFilters = true;
FilterWidget::Constraint currentConstraint;
currentConstraint.where.And( WhereClause( "track.artist_id = artist.id and track.release_id = release.id and track_genre.track_id = track.id and genre.id = track_genre.genre_id"));
for (std::size_t idFilter = 0; idFilter < _filters.size(); ++idFilter)
{
FilterWidget* filter = _filters.at(idFilter);
// Apply contraints created by previous filters
if (idFilter > idFilterUpdated) {
filter->refresh(currentConstraint);
}
// Get constraints generated by this filter
// (Note: adding accross successive calls)
filter->getConstraint(currentConstraint);
}
_refreshingFilters = false;
}
void
AudioDatabaseWidget::selectNextTrack(void)
{
TrackWidget* trackWidget ( dynamic_cast<TrackWidget*>(_filters.back() ) );
trackWidget->selectNextTrack();
}
} // namespace UserInterface
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AUDIO_DB_WIDGET_HPP
#define AUDIO_DB_WIDGET_HPP
#include <boost/filesystem/path.hpp>
#include <Wt/WContainerWidget>
#include <Wt/WSignal>
#include "common/SessionData.hpp"
#include "FilterWidget.hpp"
namespace UserInterface {
class AudioDatabaseWidget : public Wt::WContainerWidget
{
public:
AudioDatabaseWidget( Database::Handler& db, Wt::WContainerWidget *parent = 0);
void search(const std::string& text);
void selectNextTrack(void); // Will later emit the next selected track
// Signals
Wt::Signal< boost::filesystem::path >& trackSelected() { return _trackSelected; }
private:
Wt::Signal< boost::filesystem::path > _trackSelected;
void handleTrackSelected(boost::filesystem::path p);
void handleFilterUpdated(std::size_t idFilter);
std::vector<FilterWidget*> _filters; // Free Search, Genre, Artist, Release, etc.
bool _refreshingFilters;
};
} // namespace UserInterface
#endif
+173
View File
@@ -0,0 +1,173 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Wt/WMediaPlayer>
#include <Wt/WProgressBar>
#include "AudioMediaPlayerWidget.hpp"
namespace UserInterface {
AudioMediaPlayerWidget::AudioMediaPlayerWidget( Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent),
_mediaResource(nullptr)
{
_mediaPlayer = new Wt::WMediaPlayer( Wt::WMediaPlayer::Audio, this );
// _mediaPlayer->setAlternativeContent (new Wt::WText("You don't have HTML5 audio support!"));
// _mediaPlayer->setOptions( Wt::WMediaPlayer::Autoplay );
_mediaPlayer->addSource( Wt::WMediaPlayer::OGA, "" );
_mediaPlayer->ended().connect(this, &AudioMediaPlayerWidget::handleTrackEnded);
{
Wt::WContainerWidget *container = new Wt::WContainerWidget(this);
_prevBtn = new Wt::WPushButton("<<", container );
_playBtn = new Wt::WPushButton("Play", container );
_pauseBtn = new Wt::WPushButton("Pause", container );
_nextBtn = new Wt::WPushButton(">>", container );
_curTime = new Wt::WText(container);
_timeSlider = new Wt::WSlider( container );
_duration = new Wt::WText(container);
_volumeSlider = new Wt::WSlider( container );
_volumeSlider->setRange(0,100);
_volumeSlider->setValue(_mediaPlayer->volume() * 100);
_mediaPlayer->setControlsWidget( container );
_mediaPlayer->setButton(Wt::WMediaPlayer::Play, _playBtn);
_mediaPlayer->setButton(Wt::WMediaPlayer::Pause, _pauseBtn);
_mediaPlayer->setText( Wt::WMediaPlayer::CurrentTime, _curTime);
_mediaPlayer->setText( Wt::WMediaPlayer::Duration, _duration);
_mediaPlayer->timeUpdated().connect(this, &AudioMediaPlayerWidget::handleTimeUpdated);
}
_timeSlider->valueChanged().connect(this, &AudioMediaPlayerWidget::handlePlayOffset);
_timeSlider->sliderMoved().connect(this, &AudioMediaPlayerWidget::handleSliderMoved);
_timeSlider->setDisabled(true);
_volumeSlider->sliderMoved().connect(this, &AudioMediaPlayerWidget::handleVolumeSliderMoved);
_nextBtn->clicked().connect(this, &AudioMediaPlayerWidget::handlePlayNext);
_prevBtn->clicked().connect(this, &AudioMediaPlayerWidget::handlePlayPrev);
}
void
AudioMediaPlayerWidget::loadPlayer(void)
{
_mediaPlayer->clearSources();
_mediaInternalLink.setResource( nullptr );
if (_mediaResource)
delete _mediaResource;
assert( _currentParameters );
_mediaResource = new AvConvTranscodeStreamResource( *_currentParameters, this );
_mediaInternalLink.setResource( _mediaResource );
_mediaPlayer->addSource( Wt::WMediaPlayer::OGA, _mediaInternalLink );
}
void
AudioMediaPlayerWidget::load(const Transcode::Parameters& parameters)
{
_timeSlider->setDisabled(false);
_currentParameters = std::make_shared<Transcode::Parameters>( parameters );
loadPlayer();
_timeSlider->setRange(0, parameters.getInputMediaFile().getDuration().total_seconds() );
_timeSlider->setValue(0);
_duration->setText( boost::posix_time::to_simple_string( parameters.getInputMediaFile().getDuration() ));
_mediaPlayer->play();
}
void
AudioMediaPlayerWidget::handlePlayOffset(int offsetSecs)
{
if (!_currentParameters)
return;
_currentParameters->setOffset( boost::posix_time::seconds(offsetSecs) );
loadPlayer();
_mediaPlayer->play();
}
void
AudioMediaPlayerWidget::handlePlayNext(void)
{
// TODO
}
void
AudioMediaPlayerWidget::handlePlayPrev(void)
{
// TODO
}
void
AudioMediaPlayerWidget::handleTrackEnded(void)
{
_playbackEnded.emit();
}
void
AudioMediaPlayerWidget::handleValueChanged(double value)
{
// TODO
}
void
AudioMediaPlayerWidget::handleSliderMoved(int value)
{
;
}
void
AudioMediaPlayerWidget::handleTimeUpdated(void)
{
if (!_currentParameters)
return;
boost::posix_time::time_duration currentTime ( boost::posix_time::seconds( _mediaPlayer->currentTime() + _currentParameters->getOffset().total_seconds()));
_timeSlider->setValue( currentTime.total_seconds() );
_curTime->setText( boost::posix_time::to_simple_string( currentTime) );
}
void
AudioMediaPlayerWidget::handleVolumeSliderMoved(int value)
{
_mediaPlayer->setVolume( value / 100. );
}
} // namespace UserInterface
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MEDIA_PLAYER_WIDGET_HPP
#define __MEDIA_PLAYER_WIDGET_HPP
#include <memory>
#include <Wt/WSlider>
#include <Wt/WPushButton>
#include <Wt/WContainerWidget>
#include <Wt/WMediaPlayer>
#include <Wt/WLink>
#include <Wt/WText>
#include "transcode/Parameters.hpp"
#include "resource/AvConvTranscodeStreamResource.hpp"
namespace UserInterface {
class AudioMediaPlayerWidget : public Wt::WContainerWidget
{
public:
AudioMediaPlayerWidget( Wt::WContainerWidget *parent = 0);
void load(const Transcode::Parameters& parameters);
// Signal slot Next
Wt::Signal<void>& playbackEnded() {return _playbackEnded;}
// Signal Slot Previous
// Signal slot Ended
private:
void handlePlayOffset(int offsetSecs);
void handlePlayNext(void);
void handlePlayPrev(void);
void handleTrackEnded(void);
void handleValueChanged(double);
void handleTimeUpdated(void);
void handleSliderMoved(int value);
void handleVolumeSliderMoved(int value);
void loadPlayer(void);
// Signals
Wt::Signal<void> _playbackEnded;
// Core
Wt::WMediaPlayer* _mediaPlayer;
AvConvTranscodeStreamResource* _mediaResource;
Wt::WLink _mediaInternalLink;
// Controls
std::shared_ptr<Transcode::Parameters> _currentParameters;
Wt::WPushButton* _playBtn;
Wt::WPushButton* _pauseBtn;
Wt::WPushButton* _nextBtn;
Wt::WPushButton* _prevBtn;
Wt::WSlider* _timeSlider;
Wt::WSlider* _volumeSlider;
Wt::WText* _curTime;
Wt::WText* _duration;
};
} // namespace UserInterface
#endif
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Wt/WBreak>
#include "logger/Logger.hpp"
#include "AudioWidget.hpp"
namespace UserInterface {
AudioWidget::AudioWidget(SessionData& sessionData, Wt::WContainerWidget* parent)
: Wt::WContainerWidget(parent),
_db(sessionData.getDatabaseHandler()),
_audioDbWidget(nullptr),
_mediaPlayer(nullptr),
_imgResource(nullptr),
_img(nullptr)
{
_audioDbWidget = new AudioDatabaseWidget(sessionData.getDatabaseHandler(), this);
_audioDbWidget->trackSelected().connect(this, &AudioWidget::playTrack);
_mediaPlayer = new AudioMediaPlayerWidget(this);
_mediaPlayer->playbackEnded().connect(this, &AudioWidget::handleTrackEnded);
this->addWidget(new Wt::WBreak());
// Image
_imgResource = new Wt::WMemoryResource(this);
_imgLink.setResource( _imgResource);
_img = new Wt::WImage(_imgLink, this);
}
void
AudioWidget::search(const std::string& searchText)
{
_audioDbWidget->search(searchText);
}
void
AudioWidget::playTrack(boost::filesystem::path p)
{
LMS_LOG(MOD_UI, SEV_DEBUG) << "play track '" << p << "'";
try {
std::size_t bitrate = 0;
// Get user preferences
{
Wt::Dbo::Transaction transaction(_db.getSession());
Database::User::pointer user = _db.getCurrentUser();
if (user)
bitrate = user->getAudioBitrate();
else
{
LMS_LOG(MOD_UI, SEV_ERROR) << "Can't play video: user does not exists!";
return; // TODO logout?
}
}
Transcode::InputMediaFile inputFile(p);
Transcode::Parameters parameters(inputFile, Transcode::Format::get(Transcode::Format::OGA));
parameters.setBitrate(Transcode::Stream::Audio, bitrate);
_mediaPlayer->load( parameters );
// Refresh cover
{
std::vector<CoverArt::CoverArt> covers = inputFile.getCovers();
if (!covers.empty())
{
LMS_LOG(MOD_UI, SEV_DEBUG) << "Cover found!";
if (!covers.front().scale(256)) // TODO
LMS_LOG(MOD_UI, SEV_ERROR) << "Cannot resize!";
//_imgResource->setMimeType(covers.front().getMimeType());
_imgResource->setData(covers.front().getData());
}
else {
LMS_LOG(MOD_UI, SEV_DEBUG) << "No cover found!";
_imgResource->setData( std::vector<unsigned char>());
}
_imgResource->setChanged();
}
}
catch( std::exception &e)
{
LMS_LOG(MOD_UI, SEV_ERROR) << "Caught exception while loading '" << p << "': " << e.what();
}
}
void
AudioWidget::handleTrackEnded(void)
{
LMS_LOG(MOD_UI, SEV_DEBUG) << "Track playback ended!";
_audioDbWidget->selectNextTrack();
}
} // namespace UserInterface
+68
View File
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AUDIO_WIDGET_HPP
#define AUDIO_WIDGET_HPP
#include <string>
#include <Wt/WLink>
#include <Wt/WImage>
#include <Wt/WContainerWidget>
#include <Wt/WMemoryResource>
#include "audio/AudioMediaPlayerWidget.hpp"
#include "audio/AudioDatabaseWidget.hpp"
namespace UserInterface {
class AudioWidget : public Wt::WContainerWidget
{
public:
AudioWidget(SessionData& sessionData, Wt::WContainerWidget* parent = 0);
void search(const std::string& searchText);
private:
void playTrack(boost::filesystem::path p);
void handleTrackEnded(void);
Database::Handler& _db;
AudioDatabaseWidget* _audioDbWidget;
AudioMediaPlayerWidget* _mediaPlayer;
// Image
Wt::WMemoryResource *_imgResource;
Wt::WLink _imgLink;
Wt::WImage *_img;
};
} // namespace UserInterface
#endif
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FILTER_WIDGET_HPP
#define FILTER_WIDGET_HPP
#include <boost/foreach.hpp>
#include <string>
#include <list>
#include <Wt/WSignal>
#include <Wt/WContainerWidget>
#include "database/SqlQuery.hpp"
namespace UserInterface {
class FilterWidget : public Wt::WContainerWidget {
public:
struct Constraint {
WhereClause where; // WHERE SQL clause
};
FilterWidget(Wt::WContainerWidget* parent = 0) : Wt::WContainerWidget(parent) {}
virtual ~FilterWidget() {}
// Refresh filter Widget using constraints created by parent filters
virtual void refresh(const Constraint& constraint) = 0;
// Update constraints for child filters
virtual void getConstraint(Constraint& constraint) = 0;
// Emitted when a constraint has changed
Wt::Signal<void>& update() { return _update; };
protected:
void emitUpdate() { _update.emit(); }
private:
Wt::Signal<void> _update;
};
} // namespace UserInterface
#endif
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Wt/WLabel>
#include "SearchFilterWidget.hpp"
namespace UserInterface {
SearchFilterWidget::SearchFilterWidget(Wt::WContainerWidget* parent)
: FilterWidget( parent )
{
}
void
SearchFilterWidget::setText(const std::string& text)
{
_lastEmittedText = text;
emitUpdate();
}
// Get constraints created by this filter
void
SearchFilterWidget::getConstraint(Constraint& constraint)
{
// No active search means no constaint!
if (!_lastEmittedText.empty()) {
const std::string bindText ("%%" + _lastEmittedText + "%%");
constraint.where.And( WhereClause("(track.name like ? or release.name like ? or artist.name like ?)").bind(bindText).bind(bindText).bind(bindText));
}
// else no constraint!
}
} // namespace UserInterface
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SEARCH_FILTER_WIDGET_PP
#define SEARCH_FILTER_WIDGET_PP
#include <Wt/WLineEdit>
#include "FilterWidget.hpp"
namespace UserInterface {
class SearchFilterWidget : public FilterWidget {
public:
SearchFilterWidget(Wt::WContainerWidget* parent = 0);
void setText(const std::string& text);
// Set constraint on this filter
void refresh(const Constraint& constraint) {}
// Get constraints created by this filter
void getConstraint(Constraint& constraint);
private:
void handleKeyWentUp(void);
std::string _lastEmittedText;
};
} // namespace UserInterface
#endif
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <boost/foreach.hpp>
#include "logger/Logger.hpp"
#include "TableFilterWidget.hpp"
namespace UserInterface {
TableFilterWidget::TableFilterWidget(Database::Handler& db, std::string table, std::string field, Wt::WContainerWidget* parent)
: FilterWidget( parent ),
_db(db),
_table(table),
_field(field),
_tableView(nullptr)
{
_queryModel.setQuery( _db.getSession().query< ResultType >("select " + _table + "." + _field + ",count(DISTINCT track.id),0 as ORDERBY from track,artist,release,genre,track_genre WHERE track.artist_id = artist.id and track.release_id = release.id and track_genre.track_id = track.id and genre.id = track_genre.genre_id GROUP BY " + _table + "." + _field + " UNION select '<All>',0,1 AS ORDERBY").orderBy("ORDERBY DESC," + _table + "." + _field));
_queryModel.addColumn( _table + "." + _field, table);
_queryModel.addColumn( "count(DISTINCT track.id)", "Tracks");
_tableView = new Wt::WTableView( this );
_tableView->resize(250, 200); // TODO
_tableView->setSelectionMode(Wt::ExtendedSelection);
_tableView->setSortingEnabled(false);
_tableView->setAlternatingRowColors(true);
_tableView->setModel(&_queryModel);
_tableView->selectionChanged().connect(this, &TableFilterWidget::emitUpdate);
_queryModel.setBatchSize(100);
}
// Set constraints on this filter
void
TableFilterWidget::refresh(const Constraint& constraint)
{
SqlQuery sqlQuery;
sqlQuery.select(_table + "." + _field + ",count(DISTINCT track.id),0 as ORDERBY");
sqlQuery.from().And( FromClause("artist,release,track,genre,track_genre")) ;
sqlQuery.where().And(constraint.where); // Add constraint made by other filters
sqlQuery.groupBy().And( _table + "." + _field); // Add constraint made by other filters
SqlQuery AllSqlQuery;
AllSqlQuery.select("'<All>',0,1 AS ORDERBY");
LMS_LOG(MOD_UI, SEV_DEBUG) << _table << ", generated query = '" << sqlQuery.get() + " UNION " + AllSqlQuery.get() << "'";
Wt::Dbo::Query<ResultType> query = _db.getSession().query<ResultType>( sqlQuery.get() + " UNION " + AllSqlQuery.get() );
query.orderBy("ORDERBY DESC," + _table + "." + _field);
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs()) {
LMS_LOG(MOD_UI, SEV_DEBUG) << "Binding value '" << bindArg << "'";
query.bind(bindArg);
}
_queryModel.setQuery( query, true /* Keep columns */);
LMS_LOG(MOD_UI, SEV_DEBUG) << "Finish !";
}
// Get constraint created by this filter
void
TableFilterWidget::getConstraint(Constraint& constraint)
{
Wt::WModelIndexSet indexSet = _tableView->selectedIndexes();
// WHERE statement
WhereClause clause;
BOOST_FOREACH(Wt::WModelIndex index, indexSet) {
if (!index.isValid())
continue;
ResultType result = _queryModel.resultRow( index.row() );
// Get the track part
std::string name( result.get<0>() );
bool isAll( result.get<2>() ) ;
if (isAll) {
// no constraint, just return
return;
}
clause.Or(_table + "." + _field + " = ?").bind(name);
}
// Adding our WHERE clause
constraint.where.And( clause );
}
} // namespace UserInterface
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TABLE_VIEW_FILTER_WIDGET_HPP
#define TABLE_VIEW_FILTER_WIDGET_HPP
#include <Wt/Dbo/QueryModel>
#include <Wt/WTableView>
#include "FilterWidget.hpp"
#include "database/DatabaseHandler.hpp"
namespace UserInterface {
class TableFilterWidget : public FilterWidget
{
public:
TableFilterWidget(Database::Handler& db, std::string table, std::string field, Wt::WContainerWidget* parent = 0);
// Set constraints on this filter
virtual void refresh(const Constraint& constraint);
// Get constraints created by this filter
virtual void getConstraint(Constraint& constraint);
protected:
Database::Handler& _db;
const std::string _table;
const std::string _field;
// Name, track count, special value that means 'all' if set to 1
typedef boost::tuple<std::string, int, int> ResultType;
Wt::Dbo::QueryModel< ResultType > _queryModel;
Wt::WTableView* _tableView;
};
} // namespace UserInterface
#endif
+159
View File
@@ -0,0 +1,159 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <boost/foreach.hpp>
#include <Wt/WItemDelegate>
#include <Wt/WBreak>
#include "logger/Logger.hpp"
#include "TrackWidget.hpp"
namespace UserInterface {
TrackWidget::TrackWidget( Database::Handler& db, Wt::WContainerWidget* parent)
: FilterWidget( parent ),
_db(db),
_tableView(nullptr),
_trackStats(nullptr)
{
// ----- TRACK -----
_queryModel.setQuery(_db.getSession().query<ResultType>("select track,release,artist from track,release,artist where track.release_id = release.id and track.artist_id = artist.id" ).orderBy("artist.name,release.name,track.disc_number,track.track_number"));
_queryModel.addColumn( "artist.name", "Artist" );
_queryModel.addColumn( "release.name", "Album" );
_queryModel.addColumn( "track.disc_number", "Disc #" );
_queryModel.addColumn( "track.track_number", "Track #" );
_queryModel.addColumn( "track.name", "Track" );
_queryModel.addColumn( "track.duration", "Duration" );
_queryModel.addColumn( "track.creation_time", "Date" );
_queryModel.addColumn( "track.genre_list", "Genres" );
_queryModel.setBatchSize(1000);
_tableView = new Wt::WTableView( this );
_tableView->resize(Wt::WLength::Auto, 400);
_tableView->setSortingEnabled(true);
_tableView->setSelectionMode(Wt::SingleSelection);
_tableView->setAlternatingRowColors(true);
_tableView->setModel(&_queryModel);
{
Wt::WItemDelegate *delegate = new Wt::WItemDelegate(this);
delegate->setTextFormat("yyyy");
_tableView->setItemDelegateForColumn(6, delegate);
}
{
// TODO better handle 1 hour+ files!
Wt::WItemDelegate *delegate = new Wt::WItemDelegate(this);
delegate->setTextFormat("mm:ss");
_tableView->setItemDelegateForColumn(5, delegate);
}
// TODO other event!
_tableView->selectionChanged().connect(this, &TrackWidget::handleTrackSelected);
new Wt::WBreak(this);
_trackStats = new Wt::WText(this);
updateStats();
}
void
TrackWidget::updateStats(void)
{
std::ostringstream oss; oss << "Files :" << _tableView->model()->rowCount();
// TODO from UTF-8 ?
_trackStats->setText(oss.str());
}
// Set constraints created by parent filters
void
TrackWidget::refresh(const Constraint& constraint)
{
SqlQuery sqlQuery;
sqlQuery.select( "track,release,artist" );
sqlQuery.from().And( FromClause("artist,release,track,genre,track_genre"));
sqlQuery.where().And(constraint.where);
LMS_LOG(MOD_UI, SEV_DEBUG) << "TRACK REQ = '" << sqlQuery.get() << "'";
Wt::Dbo::Query<ResultType> query = _db.getSession().query<ResultType>( sqlQuery.get() );
query.groupBy("track").orderBy("artist.name,track.creation_time,release.name,track.disc_number,track.track_number");
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs()) {
LMS_LOG(MOD_UI, SEV_DEBUG) << "Binding value '" << bindArg << "'";
query.bind(bindArg);
}
_queryModel.setQuery( query, true );
updateStats();
}
void
TrackWidget::handleTrackSelected(void)
{
Wt::WModelIndexSet indexSet = _tableView->selectedIndexes();
if (!indexSet.empty()) {
Wt::WModelIndex currentIndex( *indexSet.begin() );
// Check there are remainin tracks!
if (currentIndex.isValid())
{
ResultType result = _queryModel.resultRow( currentIndex.row());
// Get the track part
Wt::Dbo::ptr<Database::Track> track ( result.get<0>() );
_trackSelected.emit( track->getPath() );
}
}
}
void
TrackWidget::selectNextTrack(void)
{
Wt::WModelIndexSet indexSet = _tableView->selectedIndexes();
if (!indexSet.empty()) {
Wt::WModelIndex currentIndex( *indexSet.begin() );
// Check there are remainin tracks!
if (currentIndex.isValid() && _tableView->model()->rowCount() > currentIndex.row() + 1)
{
_tableView->select( _tableView->model()->index( currentIndex.row() + 1, currentIndex.column()));
ResultType result = _queryModel.resultRow( currentIndex.row() + 1 );
// Get the track part
Wt::Dbo::ptr<Database::Track> track ( result.get<0>() );
_trackSelected.emit( track->getPath() );
}
}
}
} // namespace UserInterface
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRACK_WIDGET_HPP
#define TRACK_WIDGET_HPP
#include <Wt/WTableView>
#include <Wt/Dbo/QueryModel>
#include "database/DatabaseHandler.hpp"
#include "database/AudioTypes.hpp"
#include "FilterWidget.hpp"
namespace UserInterface {
class TrackWidget : public FilterWidget
{
public:
TrackWidget( Database::Handler& db, Wt::WContainerWidget* parent = 0);
// Set constraints created by parent filters
void refresh(const Constraint& constraint);
// Create constraints for child filters (N/A)
void getConstraint(Constraint& constraint) {}
void selectNextTrack(void); // Emit a trackSelected() if success
// Signals
Wt::Signal< boost::filesystem::path >& trackSelected() { return _trackSelected; }
private:
void handleTrackSelected();
Wt::Signal< boost::filesystem::path > _trackSelected;
Database::Handler& _db;
typedef boost::tuple<Database::Track::pointer, Database::Release::pointer, Database::Artist::pointer> ResultType;
Wt::Dbo::QueryModel< ResultType > _queryModel;
Wt::WTableView* _tableView;
void updateStats(void);
Wt::WText* _trackStats;
};
} // namespace UserInterface
#endif