From dd00ef6be1a5989020c9ae2c1fa6c17910b260d1 Mon Sep 17 00:00:00 2001 From: Nikolay Tischenko Date: Wed, 15 Sep 2010 15:34:26 +0700 Subject: [PATCH] Implemented playback. play/pause/stop/next/prev showing progress and seeking --- someplayer.pro | 9 +- src/busywidget.cpp | 18 +++ src/busywidget.h | 23 +++ src/filestorage.cpp | 16 +- src/library.cpp | 7 +- src/library.h | 9 +- src/libraryform.cpp | 34 +++++ src/libraryform.h | 3 + src/mainwindow.cpp | 38 +++-- src/mainwindow.h | 11 +- src/mediascanner.cpp | 24 +-- src/mediascanner.h | 4 +- src/player/player.cpp | 116 ++++++++++---- src/player/player.h | 31 +++- src/playerform.cpp | 85 ++++++++++- src/playerform.h | 21 +++ src/playlist.cpp | 22 +-- src/playlist.h | 10 +- src/tagresolver.cpp | 9 +- src/tagresolver.h | 1 + src/track.cpp | 4 + src/track.h | 1 + src/trackmetainformation.cpp | 6 +- src/ui/busywidget.ui | 31 ++++ src/ui/libraryform.ui | 35 +++++ src/ui/playerform.ui | 348 +++++++++++++++++++++++++++++++++++++++++- 26 files changed, 824 insertions(+), 92 deletions(-) create mode 100644 src/busywidget.cpp create mode 100644 src/busywidget.h create mode 100644 src/ui/busywidget.ui diff --git a/someplayer.pro b/someplayer.pro index ef76e94..5c081bb 100644 --- a/someplayer.pro +++ b/someplayer.pro @@ -22,7 +22,8 @@ SOURCES += src/main.cpp\ src/mediascanner.cpp \ src/tagresolver.cpp \ src/playerform.cpp \ - src/libraryform.cpp + src/libraryform.cpp \ + src/busywidget.cpp HEADERS += src/mainwindow.h \ src/player/player.h \ @@ -37,11 +38,13 @@ HEADERS += src/mainwindow.h \ src/mediascanner.h \ src/tagresolver.h \ src/playerform.h \ - src/libraryform.h + src/libraryform.h \ + src/busywidget.h FORMS += src/ui/mainwindow.ui \ src/ui/playerform.ui \ - src/ui/libraryform.ui + src/ui/libraryform.ui \ + src/ui/busywidget.ui CONFIG += mobility MOBILITY = diff --git a/src/busywidget.cpp b/src/busywidget.cpp new file mode 100644 index 0000000..5584790 --- /dev/null +++ b/src/busywidget.cpp @@ -0,0 +1,18 @@ +#include "busywidget.h" +#include "ui_busywidget.h" + +BusyWidget::BusyWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::BusyWidget) +{ + ui->setupUi(this); +} + +BusyWidget::~BusyWidget() +{ + delete ui; +} + +void BusyWidget::setText(QString text) { + ui->label->setText(text); +} diff --git a/src/busywidget.h b/src/busywidget.h new file mode 100644 index 0000000..c8ce7b4 --- /dev/null +++ b/src/busywidget.h @@ -0,0 +1,23 @@ +#ifndef BUSYWIDGET_H +#define BUSYWIDGET_H + +#include + +namespace Ui { + class BusyWidget; +} + +class BusyWidget : public QWidget +{ + Q_OBJECT + +public: + explicit BusyWidget(QWidget *parent = 0); + ~BusyWidget(); + void setText(QString text); + +private: + Ui::BusyWidget *ui; +}; + +#endif // BUSYWIDGET_H diff --git a/src/filestorage.cpp b/src/filestorage.cpp index f32f47d..f1e5222 100644 --- a/src/filestorage.cpp +++ b/src/filestorage.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using namespace SomePlayer::Storage; using namespace SomePlayer::DataObjects; @@ -12,6 +13,12 @@ FileStorage::FileStorage(QString path) { _path_prefix = path; _meta_regexp.setPattern("#META \\[(\\d+)\\].*::(.+)::,::(.+)::,::(.+)::"); _path_regexp.setPattern("#PATH (.+)"); + + Playlist current = getCurrentPlaylist(); + if (current.name() == PLAYLIST_BAD_NAME) { + current.setName(_CURRENT_PLAYLIST_NAME_); + saveCurrentPlaylist(current); + } } QList FileStorage::getPlaylists() { @@ -22,7 +29,7 @@ QList FileStorage::getPlaylists() { Playlist FileStorage::getPlaylist(QString name) { QFile playlistFile (_path_prefix+"/"+name+"."+_PLAYLIST_FILE_EXTENSION_); Playlist playlist; - playlist.setName("Bad playlist"); + playlist.setName(PLAYLIST_BAD_NAME); if (playlistFile.exists()) { playlist.setName(name); playlistFile.open(QFile::ReadOnly); @@ -60,19 +67,20 @@ QStringList FileStorage::getPlaylistsNames() { QFileInfo info(entry); QString suffix = info.suffix().toLower(); if (suffix == _PLAYLIST_FILE_EXTENSION_) { - playlistNames.append(info.fileName() - .replace(QString(".%1").arg(_PLAYLIST_FILE_EXTENSION_), "", Qt::CaseInsensitive)); + QString name = info.fileName().replace(QString(".%1").arg(_PLAYLIST_FILE_EXTENSION_), "", Qt::CaseInsensitive); + playlistNames.append(name); } } return playlistNames; } void FileStorage::savePlaylist(Playlist playlist) { - QString filename = _path_prefix+playlist.name()+_PLAYLIST_FILE_EXTENSION_; + QString filename = _path_prefix + "/" +playlist.name()+"."_PLAYLIST_FILE_EXTENSION_; QFile playlistFile(filename); if (playlistFile.exists()) { playlistFile.remove(); } + playlistFile.open(QFile::WriteOnly); QTextStream stream(&playlistFile); stream << _PLAYLIST_SIGNATURE_ << endl; const QList &tracks = playlist.tracks(); diff --git a/src/library.cpp b/src/library.cpp index 9a530e8..1a34860 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -12,6 +12,7 @@ Library::Library(QString databasePath, QString playlistsPath) : QObject(0) { _scanner = new MediaScanner(); _resolver = new TagResolver(this); connect(_scanner, SIGNAL(scanFinish(QStringList)), _resolver, SLOT(decode(QStringList))); + connect(_resolver, SIGNAL(done()), this, SIGNAL(addingDone())); connect(_resolver, SIGNAL(decoded(Track)), this, SLOT(addTrack(Track))); } @@ -93,11 +94,11 @@ Playlist Library::getPlaylist(QString name) { return _playlist_storage->getPlaylist(name); } -void Library::savePlaylist(Playlist playlist) { +void Library::savePlaylist(const Playlist &playlist) { _playlist_storage->savePlaylist(playlist); } -void Library::removePlaylist(Playlist playlist) { +void Library::removePlaylist(const Playlist &playlist) { _playlist_storage->removePlaylist(playlist); } @@ -109,6 +110,6 @@ Playlist Library::getCurrentPlaylist() { return _playlist_storage->getCurrentPlaylist(); } -void Library::saveCurrentPlaylist(Playlist playlist) { +void Library::saveCurrentPlaylist(const Playlist &playlist) { _playlist_storage->saveCurrentPlaylist(playlist); } diff --git a/src/library.h b/src/library.h index c9e460a..742c03e 100644 --- a/src/library.h +++ b/src/library.h @@ -46,12 +46,15 @@ namespace SomePlayer { QList getPlaylists(); QStringList getPlaylistsNames(); Playlist getPlaylist(QString name); - void savePlaylist(Playlist playlist); - void removePlaylist(Playlist playlist); + void savePlaylist(const Playlist &playlist); + void removePlaylist(const Playlist &playlist); void removePlaylist(QString name); Playlist getCurrentPlaylist(); - void saveCurrentPlaylist(Playlist playlist); + void saveCurrentPlaylist(const Playlist &playlist); + + signals: + void addingDone(); private: DbStorage *_library_storage; diff --git a/src/libraryform.cpp b/src/libraryform.cpp index cc9e1a0..463b939 100644 --- a/src/libraryform.cpp +++ b/src/libraryform.cpp @@ -9,6 +9,7 @@ #include "playlist.h" #include #include +#include using namespace SomePlayer::DataObjects; @@ -52,11 +53,13 @@ LibraryForm::LibraryForm(Library *lib, QWidget *parent) : connect(ui->listView, SIGNAL(clicked(QModelIndex)), this, SLOT(_process_list_click(QModelIndex))); connect(ui->addButton, SIGNAL(clicked()), this, SLOT(_add_button())); connect(ui->backButton, SIGNAL(clicked()), this, SLOT(_back_button())); + connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(_delete_button())); _view_button(); } LibraryForm::~LibraryForm() { + _lib->saveCurrentPlaylist(_lib->getCurrentPlaylist()); delete ui; } @@ -71,6 +74,8 @@ void LibraryForm::_view_button() { _state = STATE_ARTIST; ui->backButton->setEnabled(false); ui->listLabel->setText("Artists"); + ui->addButton->setEnabled(true); + ui->deleteButton->setEnabled(false); } void LibraryForm::_dynamic_button() { @@ -102,6 +107,7 @@ void LibraryForm::_process_list_click(QModelIndex index) { __fill_model_tracks(_model, _current_tracks); _state = STATE_PLAYLIST_TRACK; ui->backButton->setEnabled(true); + ui->deleteButton->setEnabled(true); ui->listLabel->setText(QString("Tracks in playlist \"%1\"").arg(data)); } break; @@ -164,6 +170,9 @@ void LibraryForm::_add_album(QString artist, QString album) { void LibraryForm::_add_track(Track track) { qDebug() << "adding TRACK " << track.metadata().title() << " from " << track.metadata().album() << " by " << track.metadata().artist(); + Playlist current = _lib->getCurrentPlaylist(); + current.addTrack(track); + _lib->saveCurrentPlaylist(current); } void LibraryForm::_add_playlist(QString name) { @@ -199,4 +208,29 @@ void LibraryForm::_playlists_button() { _state = STATE_PLAYLIST; ui->backButton->setEnabled(false); ui->listLabel->setText("Playlists"); + ui->addButton->setEnabled(false); +} + +void LibraryForm::_delete_button() { + if (_state == STATE_PLAYLIST_TRACK) { + QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes(); + ui->listView->selectionModel()->clearSelection(); + QQueue to_delete; + foreach (QModelIndex id, selected) { + _delete_track(_current_tracks.at(id.row())); + to_delete.append(id.row()); + } + qSort(to_delete); + int count = to_delete.count(); + for (int i = count-1; i >= 0; i--) { + _current_tracks.removeAt(to_delete.at(i)); + } + __fill_model_tracks(_model, _current_tracks); + } +} + +void LibraryForm::_delete_track(Track track) { + Playlist current = _lib->getCurrentPlaylist(); + current.removeTrack(track); + _lib->saveCurrentPlaylist(current); } diff --git a/src/libraryform.h b/src/libraryform.h index 009b692..b842778 100644 --- a/src/libraryform.h +++ b/src/libraryform.h @@ -14,6 +14,7 @@ namespace Ui { using SomePlayer::DataObjects::Library; using SomePlayer::DataObjects::Track; +using SomePlayer::DataObjects::Playlist; enum LibraryFormListState {STATE_NONE, STATE_ARTIST, STATE_ALBUM, STATE_TRACK, STATE_PLAYLIST, STATE_PLAYLIST_TRACK}; @@ -32,6 +33,7 @@ private slots: void _dynamic_button(); void _playlists_button(); void _add_button(); + void _delete_button(); void _back_button(); void _process_list_click(QModelIndex); @@ -48,6 +50,7 @@ private: void _add_album(QString artist, QString album); void _add_track(Track track); void _add_playlist(QString name); + void _delete_track(Track track); }; #endif // LIBRARYFORM_H diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f14edf9..32421f3 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -22,19 +22,26 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionPlayer, SIGNAL(triggered()), this, SLOT(player())); connect(ui->actionLibrary, SIGNAL(triggered()), this, SLOT(library())); setAnimated(true); - _playerForm = new PlayerForm(_library, ui->stackedWidget); - _libraryForm = new LibraryForm(_library, ui->stackedWidget); - ui->stackedWidget->insertWidget(0, _playerForm); - ui->stackedWidget->insertWidget(1, _libraryForm); - connect(_playerForm, SIGNAL(library()), this, SLOT(library())); - connect(_libraryForm, SIGNAL(player()), this, SLOT(player())); + _player_form = new PlayerForm(_library, ui->stackedWidget); + _library_form = new LibraryForm(_library, ui->stackedWidget); + _busy_widget = new BusyWidget(ui->stackedWidget); + ui->stackedWidget->insertWidget(0, _player_form); + ui->stackedWidget->insertWidget(1, _library_form); + ui->stackedWidget->insertWidget(2, _busy_widget); + _library_menu = new QMenu("Lirary"); + QAction *add_directory = _library_menu->addAction("Add directory"); + _player_menu = new QMenu("Player"); + connect(_player_form, SIGNAL(library()), this, SLOT(library())); + connect(_library_form, SIGNAL(player()), this, SLOT(player())); + connect(add_directory, SIGNAL(triggered()), this, SLOT(_add_directory())); + connect(_library, SIGNAL(addingDone()), this, SLOT(library())); library(); } MainWindow::~MainWindow() { - delete _playerForm; - delete _libraryForm; + delete _player_form; + delete _library_form; delete ui; } @@ -55,13 +62,24 @@ void MainWindow::about() { } void MainWindow::player() { - _playerForm->show(); ui->stackedWidget->setCurrentIndex(0); + _player_form->reload(); setWindowTitle("SomePlayer"); } void MainWindow::library() { - _libraryForm->show(); + ui->menuBar->setEnabled(true); ui->stackedWidget->setCurrentIndex(1); setWindowTitle("SomePlayer Library"); + ui->menuBar->addMenu(_library_menu); +} + +void MainWindow::_add_directory() { + QString directory = QFileDialog::getExistingDirectory (this, "Select directory", "/home/user/MyDocs", QFileDialog::ShowDirsOnly ); + if (!directory.isEmpty()) { + _busy_widget->setText("

Scanning... Please wait

"); + ui->menuBar->setEnabled(false); + ui->stackedWidget->setCurrentIndex(2); + _library->addDirectory(directory); + } } diff --git a/src/mainwindow.h b/src/mainwindow.h index 033630d..24f8eff 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -3,8 +3,10 @@ #include #include +#include #include "playerform.h" #include "libraryform.h" +#include "busywidget.h" #include "library.h" namespace Ui { @@ -30,9 +32,14 @@ public slots: void about(); void player(); void library(); +private slots: + void _add_directory(); private: - PlayerForm *_playerForm; - LibraryForm *_libraryForm; + PlayerForm *_player_form; + LibraryForm *_library_form; + BusyWidget *_busy_widget; + QMenu *_library_menu; + QMenu *_player_menu; Library *_library; }; diff --git a/src/mediascanner.cpp b/src/mediascanner.cpp index 1f9adf0..e46c57a 100644 --- a/src/mediascanner.cpp +++ b/src/mediascanner.cpp @@ -3,22 +3,30 @@ using namespace SomePlayer::Storage; #include +#include MediaScanner::MediaScanner(QObject *parent) : QThread(parent), _stopped(false), _initialized(false) { REGISTERED_FILE_EXTENSIONS << "mp3" << "flac" << "wma" << "acc"; - _iterator = NULL; } void MediaScanner::run() { if (!_initialized) return; _foundMedia.clear(); - while(!_stopped && _iterator->hasNext()) { - QString entry(_iterator->next()); - QFileInfo info(entry); - if (info.isReadable()) { + _scan_directory(_dir); + emit scanFinish(_foundMedia); + _stopped = true; +} + +void MediaScanner::_scan_directory(QDir dir) { + QFileInfoList items = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + foreach (QFileInfo info, items) { + if (info.isDir()) { + QDir ndir(info.absoluteFilePath()); + _scan_directory(ndir); + } else { QString suffix = info.suffix().toLower(); if (REGISTERED_FILE_EXTENSIONS.contains(suffix)) { if (!_foundMedia.contains(info.absoluteFilePath())) @@ -26,8 +34,6 @@ void MediaScanner::run() { } } } - emit scanFinish(_foundMedia); - _stopped = true; } void MediaScanner::stop() { @@ -38,7 +44,5 @@ void MediaScanner::stop() { void MediaScanner::init(QString dir) { _stopped = false; _initialized = true; - if (!_iterator) - delete _iterator; - _iterator = new QDirIterator(QDir(dir), QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); + _dir = dir; } diff --git a/src/mediascanner.h b/src/mediascanner.h index c350f3a..cd952cf 100644 --- a/src/mediascanner.h +++ b/src/mediascanner.h @@ -24,11 +24,13 @@ namespace SomePlayer { void stop(); void init(QString); private: - QDirIterator *_iterator; + QDir _dir; bool _stopped; bool _initialized; QStringList REGISTERED_FILE_EXTENSIONS; QStringList _foundMedia; + + void _scan_directory(QDir); }; }; diff --git a/src/player/player.cpp b/src/player/player.cpp index 4670db3..ee42116 100644 --- a/src/player/player.cpp +++ b/src/player/player.cpp @@ -7,51 +7,113 @@ using namespace SomePlayer::DataObjects; Player::Player(QObject *parent) : QObject(parent) { - _player = NULL; + _player = new Phonon::MediaObject(this); + _output = new Phonon::AudioOutput(Phonon::MusicCategory, this); + _player->setTickInterval(1000); + connect(_player, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(_stateChanged(Phonon::State,Phonon::State))); + connect(_player, SIGNAL(tick(qint64)), this, SLOT(_tick(qint64))); + Phonon::createPath(_player, _output); + int seed = reinterpret_cast (_player); + srand(seed); + _random = false; + _repeat = false; } -void Player::setTrack(Track &track) { - _current_track = track; - _create_player(); - emit stateChanged(PLAYER_LOADING); +void Player::setTrackId(int id) { + _current = id; + _history.push(_current); + _set_source(); + _state = PLAYER_LOADING; + emit stateChanged(_state); } void Player::play() { - if (_player) { - _player->play(); - emit stateChanged(PLAYER_PLAYING); - } + _player->play(); + _state = PLAYER_PLAYING; + emit stateChanged(_state); } void Player::stop() { - if (_player) { - _player->stop(); - emit stateChanged(PLAYER_STOPPED); - } + _player->stop(); + _state = PLAYER_STOPPED; + emit stateChanged(_state); } void Player::pause() { - if (_player) { - _player->pause(); - emit stateChanged(PLAYER_PAUSED); - } + _player->pause(); + _state = PLAYER_PAUSED; + emit stateChanged(_state); } -void Player::_create_player() { - if (_player) { - disconnect(_player, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(_stateChanged(Phonon::State,Phonon::State))); - delete _player; +void Player::next() { + _history.push(_current); + if (_random) { + _current = rand() % _playlist.tracks().count(); + } else { + _current = (_current + 1) % _playlist.tracks().count(); + } + if (_history.count()-1 == _playlist.tracks().count() && !_repeat) { + _history.clear(); + stop(); + } else { + _set_source(); + play(); } - _player = Phonon::createPlayer(Phonon::MusicCategory, Phonon::MediaSource(_current_track.source())); - _player->setTickInterval(1000); - connect(_player, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(_stateChanged(Phonon::State,Phonon::State))); - connect(_player, SIGNAL(tick(qint64)), this, SLOT(_tick(qint64))); - emit stateChanged(PLAYER_STOPPED); +} + +void Player::_set_source() { + qDebug() << "id: " << _current << " all: " << _playlist.tracks().count(); + Track track = _playlist.tracks().at(_current); + _player->setCurrentSource(Phonon::MediaSource(track.source())); + emit trackChanged(track); +} + +void Player::prev() { + if (_history.count() > 0) + _current = _history.pop(); + _set_source(); + play(); } void Player::_stateChanged(Phonon::State newState, Phonon::State oldState) { + qDebug() << "state changed: " << oldState << "->" << newState; + switch (newState) { + case Phonon::PlayingState: + if (_state == PLAYER_LOADING) { + _state = PLAYER_PLAYING; + emit stateChanged(_state); + } + break; + case Phonon::StoppedState: + break; + case Phonon::LoadingState: + break; + case Phonon::PausedState: + if (_state == PLAYER_PLAYING) { + next(); + } else if (_state == PLAYER_ERROR) { + play(); + } + break; + case Phonon::BufferingState: + break; + case Phonon::ErrorState: + _state = PLAYER_ERROR; + qDebug() << _player->errorString(); + break; + } } void Player::_tick(qint64 ticks) { - emit tick(ticks/1000, _current_track.metadata().length()); + emit tick(ticks/1000, _playlist.tracks().at(_current).metadata().length()); +} + +void Player::setPlaylist(Playlist playlist) { + _playlist = playlist; + _history.clear(); +} + +void Player::seek(int s) { + qDebug() << "seeking " << s; + _player->seek(s*1000); } diff --git a/src/player/player.h b/src/player/player.h index 201b458..ec3d82d 100644 --- a/src/player/player.h +++ b/src/player/player.h @@ -4,17 +4,22 @@ #include #include "../someplayer.h" #include "../track.h" +#include "../trackmetainformation.h" +#include "../playlist.h" #include #include +#include // represents player using SomePlayer::DataObjects::Track; +using SomePlayer::DataObjects::TrackMetadata; +using SomePlayer::DataObjects::Playlist; namespace SomePlayer { namespace Playback { - enum PlayerState { PLAYER_STOPPED, PLAYER_PLAYING, PLAYER_PAUSED, PLAYER_LOADING, PLAYER_DONE }; + enum PlayerState { PLAYER_STOPPED, PLAYER_PLAYING, PLAYER_PAUSED, PLAYER_LOADING, PLAYER_DONE, PLAYER_ERROR }; class Player : public QObject { @@ -22,22 +27,40 @@ namespace SomePlayer { public: explicit Player(QObject *parent = 0); + bool random() {return _random;} + bool repeat() {return _repeat;} + Phonon::MediaObject* mediaObject() {return _player;} + signals: void stateChanged (PlayerState); + void trackChanged (Track); void tick (int, int); // played | all (seconds) public slots: - void setTrack(Track&); + void setTrackId(int id); void play(); void pause(); void stop(); + void next(); + void prev(); + void setPlaylist(Playlist); + void toggleRandom() {_random = !_random;} + void toggleRepeat() {_repeat = !_repeat;} + void seek(int); private slots: void _stateChanged(Phonon::State, Phonon::State); void _tick(qint64); private: - Track _current_track; + int _current; + bool _random; + bool _repeat; + QStack _history; + Playlist _playlist; Phonon::MediaObject *_player; - void _create_player(); + Phonon::AudioOutput *_output; + PlayerState _state; + + void _set_source(); }; }; }; diff --git a/src/playerform.cpp b/src/playerform.cpp index d6e5929..a1af42f 100644 --- a/src/playerform.cpp +++ b/src/playerform.cpp @@ -1,15 +1,48 @@ #include "playerform.h" #include "ui_playerform.h" +#include "library.h" +#include +#include +#include using namespace SomePlayer::DataObjects; +using namespace SomePlayer::Playback; + +inline void __fill_list(QStandardItemModel *_model, Playlist playlist) { + _model->clear(); + QList tracks = playlist.tracks(); + int count = tracks.count(); + _model->setRowCount(count); + for (int i = 0; i < count; i++) { + TrackMetadata meta = tracks.at(i).metadata(); + _model->setItem(i, 0, new QStandardItem(meta.title())); + _model->setItem(i, 1, new QStandardItem(meta.artist())); + } +} PlayerForm::PlayerForm(Library* lib, QWidget *parent) : - _lib(lib), QWidget(parent), ui(new Ui::PlayerForm) { + _lib = lib; + _player = new Player(this); ui->setupUi(this); connect(ui->libraryButton, SIGNAL(clicked()), this, SLOT(_library())); + connect(ui->viewButton, SIGNAL(clicked()), this, SLOT(_toggle_view())); + connect(ui->playlistView, SIGNAL(clicked(QModelIndex)), this, SLOT(_process_click(QModelIndex))); + connect(ui->playButton, SIGNAL(clicked()), _player, SLOT(play())); + connect(ui->pauseButton, SIGNAL(clicked()), _player, SLOT(pause())); + connect(ui->stopButton, SIGNAL(clicked()), _player, SLOT(stop())); + connect(ui->nextButton, SIGNAL(clicked()), _player, SLOT(next())); + connect(ui->prevButton, SIGNAL(clicked()), _player, SLOT(prev())); + connect(_player, SIGNAL(trackChanged(Track)), this, SLOT(_track_changed(Track))); + connect(_player, SIGNAL(tick(int,int)), this, SLOT(_tick(int,int))); + _seek_slider = new QSlider(Qt::Horizontal); + ui->progressLayout->insertWidget(1, _seek_slider); + _seek_slider->setTracking(false); + connect(_seek_slider, SIGNAL(sliderMoved(int)), _player, SLOT(seek(int))); + _model = new QStandardItemModel(0, 2, this); + ui->playlistView->setModel(_model); } PlayerForm::~PlayerForm() @@ -20,3 +53,53 @@ PlayerForm::~PlayerForm() void PlayerForm::_library() { emit library(); } + +void PlayerForm::reload() { + _current_playlist = _lib->getCurrentPlaylist(); + _player->setPlaylist(_current_playlist); + __fill_list(_model, _current_playlist); +} + +void PlayerForm::_toggle_view() { + int index = ui->stackedWidget->currentIndex(); + index = (!index % 2); + ui->stackedWidget->setCurrentIndex(index); +} + +void PlayerForm::_process_click(QModelIndex index) { + int id = index.row(); + _player->stop(); + _player->setTrackId(id); + _player->play(); +} + +void PlayerForm::_track_changed(Track track) { + int id = _current_playlist.tracks().indexOf(track); + QModelIndex index = _model->index(id, 0); + ui->playlistView->setCurrentIndex(index); + _display_track(track); +} + +void PlayerForm::_display_track(Track track) { + ui->countLabel->setText(QString("%1/%2"). + arg(_current_playlist.tracks().indexOf(track)+1). + arg(_current_playlist.tracks().count())); + ui->titleLabel->setText(QString("

%1

").arg(track.metadata().title())); + ui->artistAlbumLabel->setText(QString("

%1


%2"). + arg(track.metadata().artist()). + arg(track.metadata().album())); + _seek_slider->setMinimum(0); + _seek_slider->setMaximum(track.metadata().length()); +} + +void PlayerForm::_tick(int done, int all) { + QTime time1(0, all/60, all%60); + QTime time2(0, done/60, done%60); + ui->allTimeLabel->setText(time1.toString("mm:ss")); + ui->doneTimeLabel->setText(time2.toString("mm:ss")); + _seek_slider->setValue(done); +} + +void PlayerForm::_slider_released() { + _player->seek(_seek_slider->value()); +} diff --git a/src/playerform.h b/src/playerform.h index ea57a27..91c1e3f 100644 --- a/src/playerform.h +++ b/src/playerform.h @@ -3,12 +3,19 @@ #include #include "someplayer.h" +#include "playlist.h" +#include +#include "player/player.h" +#include namespace Ui { class PlayerForm; } using SomePlayer::DataObjects::Library; +using SomePlayer::DataObjects::Playlist; +using SomePlayer::DataObjects::Track; +using SomePlayer::Playback::Player; class PlayerForm : public QWidget { @@ -20,12 +27,26 @@ public: signals: void library(); +public slots: + void reload(); + private slots: void _library(); + void _toggle_view(); + void _process_click(QModelIndex); + void _track_changed(Track); + void _tick(int, int); + void _slider_released(); private: Ui::PlayerForm *ui; Library *_lib; + Playlist _current_playlist; + QStandardItemModel *_model; + Player *_player; + QSlider *_seek_slider; + + void _display_track(Track); }; #endif // PLAYERFORM_H diff --git a/src/playlist.cpp b/src/playlist.cpp index d036714..417ac26 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -1,4 +1,5 @@ #include "playlist.h" +#include using namespace SomePlayer::DataObjects; @@ -8,21 +9,15 @@ Playlist::Playlist() } Playlist::Playlist(const Playlist &playlist) { - _name = playlist.name(); - _tracks = playlist.tracks(); + _name = playlist._name; + _tracks = playlist._tracks; } -Playlist& Playlist::operator =(const Playlist &playlist) { - _name = playlist.name(); - _tracks = playlist.tracks(); - return *this; -} - -QString Playlist::name() const { +QString Playlist::name() { return _name; } -const QList &Playlist::tracks() const { +QList Playlist::tracks() { return _tracks; } @@ -31,6 +26,11 @@ void Playlist::setName(QString name) { } void Playlist::addTrack(Track track) { - _tracks.append(track); + if (!_tracks.contains(track)) + _tracks.append(track); +} + +void Playlist::removeTrack(Track track) { + _tracks.removeOne(track); } diff --git a/src/playlist.h b/src/playlist.h index 5c3ecde..21ba765 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -4,6 +4,9 @@ #include "track.h" #include "someplayer.h" +#define PLAYLIST_BAD_NAME "Bad playlist" +#define PLAYLIST_CURRENT_NAME "Current" + // represents playlist: list of tracks, name namespace SomePlayer { @@ -13,13 +16,12 @@ namespace SomePlayer { Playlist(); Playlist(const Playlist &playlist); - Playlist &operator=(const Playlist &playlist); - - QString name() const; - const QList &tracks() const; + QString name(); + QList tracks(); void setName(QString name); void addTrack(Track track); + void removeTrack(Track track); private: QString _name; diff --git a/src/tagresolver.cpp b/src/tagresolver.cpp index ef579cd..841de0c 100644 --- a/src/tagresolver.cpp +++ b/src/tagresolver.cpp @@ -27,11 +27,18 @@ void TagResolver::metaStateChanged(Phonon::State newState, Phonon::State /*oldSt QMap meta = _metaObject->metaData(); TrackMetadata metadata(meta.value("TITLE"), meta.value("ARTIST"), meta.value("ALBUM"), time/1000); Track track(0, metadata, source.fileName()); - emit decoded(track); int index = _sources.indexOf(source)+1; + emit decoded(track); if (index != _sources.size()) { Phonon::MediaSource newSource = _sources.at(index); + _metaObject->clear(); _metaObject->setCurrentSource(newSource); + } else { + emit done(); } + } else if (newState == Phonon::ErrorState) { + Phonon::MediaSource s = _metaObject->currentSource(); + _metaObject->clear(); + _metaObject->setCurrentSource(s); } } diff --git a/src/tagresolver.h b/src/tagresolver.h index 993711e..123072b 100644 --- a/src/tagresolver.h +++ b/src/tagresolver.h @@ -23,6 +23,7 @@ namespace SomePlayer { signals: void decoded(Track); + void done(); private slots: void metaStateChanged(Phonon::State newState, Phonon::State /*oldState*/); diff --git a/src/track.cpp b/src/track.cpp index b5634e6..c61a07a 100644 --- a/src/track.cpp +++ b/src/track.cpp @@ -64,3 +64,7 @@ Track &Track::operator =(const Track &track) { } Track::~Track() {} + +bool Track::operator ==(const Track &track) { + return _source == track._source; +} diff --git a/src/track.h b/src/track.h index 4288823..7539f21 100644 --- a/src/track.h +++ b/src/track.h @@ -27,6 +27,7 @@ namespace SomePlayer { void setSource (QString source); int count() const; //count of plays void setCount(int count); //for restoring from database and counting from player + bool operator == (const Track &track); private: TrackMetadata _metadata; diff --git a/src/trackmetainformation.cpp b/src/trackmetainformation.cpp index 087493c..d72b280 100644 --- a/src/trackmetainformation.cpp +++ b/src/trackmetainformation.cpp @@ -6,9 +6,9 @@ TrackMetadata::TrackMetadata() { } TrackMetadata::TrackMetadata(QString title = "", QString artist = "", QString album = "", int length = 0) { - _metadata["TITLE"] = title == "" ? "Unknown title" : title; - _metadata["ARTIST"] = artist == "" ? "Unknown artist" : artist; - _metadata["ALBUM"] = album == "" ? "Unknown album" : album; + _metadata["TITLE"] = title == "" ? "Unknown title" : title.trimmed(); + _metadata["ARTIST"] = artist == "" ? "Unknown artist" : artist.trimmed(); + _metadata["ALBUM"] = album == "" ? "Unknown album" : album.trimmed(); _length = length; } diff --git a/src/ui/busywidget.ui b/src/ui/busywidget.ui new file mode 100644 index 0000000..9fbae8b --- /dev/null +++ b/src/ui/busywidget.ui @@ -0,0 +1,31 @@ + + + BusyWidget + + + + 0 + 0 + 800 + 480 + + + + Form + + + + + + BUSY + + + Qt::AlignCenter + + + + + + + + diff --git a/src/ui/libraryform.ui b/src/ui/libraryform.ui index cdc3ddd..7d9f819 100644 --- a/src/ui/libraryform.ui +++ b/src/ui/libraryform.ui @@ -51,6 +51,12 @@ Form + + 0 + + + 0 + @@ -113,6 +119,9 @@ + + 0 + @@ -162,6 +171,29 @@ + + + Delete + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + Player @@ -175,6 +207,9 @@ + + 0 + diff --git a/src/ui/playerform.ui b/src/ui/playerform.ui index 8a8acba..c552cb1 100644 --- a/src/ui/playerform.ui +++ b/src/ui/playerform.ui @@ -13,14 +13,352 @@ Form - - - - - Library + + + 0 + + + 0 + + + + + 1 + + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + Qt::ElideLeft + + + true + + + true + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0/0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + <h3>Title</h3> + + + Qt::AlignCenter + + + + + + + + + 00:00 + + + + + + + 00:00 + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Droid Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:large; font-weight:600;">Artist</span></p> +<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:large;">album</span></p></body></html> + + + Qt::AlignCenter + + + + + + + + + + + + 0 + + + + + + 0 + 70 + + + + + 16777215 + 70 + + + + Library + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 70 + 70 + + + + + 70 + 70 + + + + ^ + + + true + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 70 + 70 + + + + + 70 + 70 + + + + <| + + + true + + + + + + + + 0 + 0 + + + + + 70 + 70 + + + + + 70 + 70 + + + + > + + + true + + + + + + + + 0 + 0 + + + + + 70 + 70 + + + + + 70 + 70 + + + + || + + + true + + + + + + + + 0 + 0 + + + + + 70 + 70 + + + + + 70 + 70 + + + + [] + + + true + + + + + + + + 0 + 0 + + + + + 70 + 70 + + + + + 70 + 70 + + + + |> + + + true + + + + + -- 1.7.9.5