Implemented playback.
authorNikolay Tischenko <niktischenko@gmail.com>
Wed, 15 Sep 2010 08:34:26 +0000 (15:34 +0700)
committerNikolay Tischenko <niktischenko@gmail.com>
Wed, 15 Sep 2010 08:34:26 +0000 (15:34 +0700)
play/pause/stop/next/prev
showing progress and seeking

26 files changed:
someplayer.pro
src/busywidget.cpp [new file with mode: 0644]
src/busywidget.h [new file with mode: 0644]
src/filestorage.cpp
src/library.cpp
src/library.h
src/libraryform.cpp
src/libraryform.h
src/mainwindow.cpp
src/mainwindow.h
src/mediascanner.cpp
src/mediascanner.h
src/player/player.cpp
src/player/player.h
src/playerform.cpp
src/playerform.h
src/playlist.cpp
src/playlist.h
src/tagresolver.cpp
src/tagresolver.h
src/track.cpp
src/track.h
src/trackmetainformation.cpp
src/ui/busywidget.ui [new file with mode: 0644]
src/ui/libraryform.ui
src/ui/playerform.ui

index ef76e94..5c081bb 100644 (file)
@@ -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 (file)
index 0000000..5584790
--- /dev/null
@@ -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 (file)
index 0000000..c8ce7b4
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef BUSYWIDGET_H
+#define BUSYWIDGET_H
+
+#include <QWidget>
+
+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
index f32f47d..f1e5222 100644 (file)
@@ -4,6 +4,7 @@
 #include <QFileInfo>
 #include <QTextStream>
 #include <QRegExp>
+#include <QDebug>
 
 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<Playlist> FileStorage::getPlaylists() {
@@ -22,7 +29,7 @@ QList<Playlist> 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<Track> &tracks = playlist.tracks();
index 9a530e8..1a34860 100644 (file)
@@ -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);
 }
index c9e460a..742c03e 100644 (file)
@@ -46,12 +46,15 @@ namespace SomePlayer {
                        QList<Playlist> 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;
index cc9e1a0..463b939 100644 (file)
@@ -9,6 +9,7 @@
 #include "playlist.h"
 #include <QDebug>
 #include <QTime>
+#include <QQueue>
 
 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<int> 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);
 }
index 009b692..b842778 100644 (file)
@@ -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
index f14edf9..32421f3 100644 (file)
@@ -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("<H1>Scanning... Please wait</H1>");
+               ui->menuBar->setEnabled(false);
+               ui->stackedWidget->setCurrentIndex(2);
+               _library->addDirectory(directory);
+       }
 }
index 033630d..24f8eff 100644 (file)
@@ -3,8 +3,10 @@
 
 #include <QMainWindow>
 #include <QMessageBox>
+#include <QMenu>
 #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;
 };
 
index 1f9adf0..e46c57a 100644 (file)
@@ -3,22 +3,30 @@
 using namespace SomePlayer::Storage;
 
 #include <QMap>
+#include <QDir>
 
 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;
 }
index c350f3a..cd952cf 100644 (file)
@@ -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);
                };
 
        };
index 4670db3..ee42116 100644 (file)
@@ -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<int> (_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);
 }
index 201b458..ec3d82d 100644 (file)
@@ -4,17 +4,22 @@
 #include <QObject>
 #include "../someplayer.h"
 #include "../track.h"
+#include "../trackmetainformation.h"
+#include "../playlist.h"
 #include <phonon/MediaObject>
 #include <phonon/AudioOutput>
+#include <QStack>
 
 // 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<int> _history;
+                       Playlist _playlist;
                        Phonon::MediaObject *_player;
-                       void _create_player();
+                       Phonon::AudioOutput *_output;
+                       PlayerState _state;
+
+                       void _set_source();
                };
        };
 };
index d6e5929..a1af42f 100644 (file)
@@ -1,15 +1,48 @@
 #include "playerform.h"
 #include "ui_playerform.h"
+#include "library.h"
+#include <QDebug>
+#include <QTime>
+#include <QSlider>
 
 using namespace SomePlayer::DataObjects;
+using namespace SomePlayer::Playback;
+
+inline void __fill_list(QStandardItemModel *_model, Playlist playlist) {
+       _model->clear();
+       QList<Track> 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("<h3>%1</h3>").arg(track.metadata().title()));
+       ui->artistAlbumLabel->setText(QString("<h3>%1</h3><br/>%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());
+}
index ea57a27..91c1e3f 100644 (file)
@@ -3,12 +3,19 @@
 
 #include <QWidget>
 #include "someplayer.h"
+#include "playlist.h"
+#include <QStandardItemModel>
+#include "player/player.h"
+#include <QSlider>
 
 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
index d036714..417ac26 100644 (file)
@@ -1,4 +1,5 @@
 #include "playlist.h"
+#include <QDebug>
 
 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<Track> &Playlist::tracks() const {
+QList<Track> 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);
 }
 
index 5c3ecde..21ba765 100644 (file)
@@ -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<Track> &tracks() const;
+                       QString name();
+                       QList<Track> tracks();
 
                        void setName(QString name);
                        void addTrack(Track track);
+                       void removeTrack(Track track);
 
                private:
                        QString _name;
index ef579cd..841de0c 100644 (file)
@@ -27,11 +27,18 @@ void TagResolver::metaStateChanged(Phonon::State newState, Phonon::State /*oldSt
                QMap<QString, QString> 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);
        }
 }
index 993711e..123072b 100644 (file)
@@ -23,6 +23,7 @@ namespace SomePlayer {
 
                signals:
                        void decoded(Track);
+                       void done();
 
                private slots:
                        void metaStateChanged(Phonon::State newState, Phonon::State /*oldState*/);
index b5634e6..c61a07a 100644 (file)
@@ -64,3 +64,7 @@ Track &Track::operator =(const Track &track) {
 }
 
 Track::~Track() {}
+
+bool Track::operator ==(const Track &track) {
+       return _source == track._source;
+}
index 4288823..7539f21 100644 (file)
@@ -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;
index 087493c..d72b280 100644 (file)
@@ -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 (file)
index 0000000..9fbae8b
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BusyWidget</class>
+ <widget class="QWidget" name="BusyWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>800</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>BUSY</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
index cdc3ddd..7d9f819 100644 (file)
    <string>Form</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_2">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
    </item>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <property name="spacing">
+      <number>0</number>
+     </property>
      <item>
       <layout class="QVBoxLayout" name="verticalLayout">
        <item>
         </spacer>
        </item>
        <item>
+        <widget class="QPushButton" name="deleteButton">
+         <property name="text">
+          <string>Delete</string>
+         </property>
+         <property name="flat">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_3">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
         <widget class="QPushButton" name="playerButton">
          <property name="text">
           <string>Player</string>
      </item>
      <item>
       <layout class="QVBoxLayout" name="verticalLayout_3">
+       <property name="spacing">
+        <number>0</number>
+       </property>
        <item>
         <widget class="QLabel" name="listLabel">
          <property name="enabled">
index 8a8acba..c552cb1 100644 (file)
   <property name="windowTitle">
    <string>Form</string>
   </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0">
-    <widget class="QPushButton" name="libraryButton">
-     <property name="text">
-      <string>Library</string>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QStackedWidget" name="stackedWidget">
+     <property name="currentIndex">
+      <number>1</number>
      </property>
+     <widget class="QWidget" name="page">
+      <layout class="QVBoxLayout" name="verticalLayout_4">
+       <property name="spacing">
+        <number>0</number>
+       </property>
+       <property name="margin">
+        <number>0</number>
+       </property>
+       <item>
+        <widget class="QListView" name="playlistView">
+         <property name="editTriggers">
+          <set>QAbstractItemView::NoEditTriggers</set>
+         </property>
+         <property name="textElideMode">
+          <enum>Qt::ElideLeft</enum>
+         </property>
+         <property name="uniformItemSizes">
+          <bool>true</bool>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="page_2">
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="0" column="0">
+        <widget class="QWidget" name="widget" native="true">
+         <layout class="QVBoxLayout" name="verticalLayout_2">
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_5">
+            <item>
+             <spacer name="horizontalSpacer_2">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QLabel" name="countLabel">
+              <property name="text">
+               <string>0/0</string>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <widget class="QLabel" name="titleLabel">
+            <property name="text">
+             <string>&lt;h3&gt;Title&lt;/h3&gt;</string>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignCenter</set>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="progressLayout">
+            <item>
+             <widget class="QLabel" name="doneTimeLabel">
+              <property name="text">
+               <string>00:00</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLabel" name="allTimeLabel">
+              <property name="text">
+               <string>00:00</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <widget class="QLabel" name="artistAlbumLabel">
+            <property name="text">
+             <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Droid Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:large; font-weight:600;&quot;&gt;Artist&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:large;&quot;&gt;album&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignCenter</set>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+      </layout>
+     </widget>
     </widget>
    </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="spacing">
+      <number>0</number>
+     </property>
+     <item>
+      <widget class="QPushButton" name="libraryButton">
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>16777215</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Library</string>
+       </property>
+       <property name="flat">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="viewButton">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>^</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <property name="flat">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_3">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="prevButton">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>&lt;|</string>
+       </property>
+       <property name="flat">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="playButton">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>&gt;</string>
+       </property>
+       <property name="flat">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pauseButton">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>||</string>
+       </property>
+       <property name="flat">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="stopButton">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>[]</string>
+       </property>
+       <property name="flat">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="nextButton">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>70</width>
+         <height>70</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>|&gt;</string>
+       </property>
+       <property name="flat">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
   </layout>
  </widget>
  <resources/>