parent
d15fffc802
commit
85d5e398da
@ -690,6 +690,7 @@ void MainWindow::SetCurrentPlaylist(PlaylistView* pCurrent){
|
|||||||
current_playlist_ = qobject_cast< Playlist* >( pCurrent->model() );
|
current_playlist_ = qobject_cast< Playlist* >( pCurrent->model() );
|
||||||
player_->SetCurrentPlaylist(current_playlist_);
|
player_->SetCurrentPlaylist(current_playlist_);
|
||||||
|
|
||||||
|
current_playlist_->set_shuffle_repeat_widget(shuffle_repeat_widget_);
|
||||||
|
|
||||||
// connects !! :)
|
// connects !! :)
|
||||||
|
|
||||||
@ -709,6 +710,9 @@ void MainWindow::SetCurrentPlaylist(PlaylistView* pCurrent){
|
|||||||
connect(player_, SIGNAL(Stopped()), current_playlist_view_, SLOT(StopGlowing()));
|
connect(player_, SIGNAL(Stopped()), current_playlist_view_, SLOT(StopGlowing()));
|
||||||
|
|
||||||
connect(radio_model_, SIGNAL(StreamMetadataFound(QUrl,Song)), current_playlist_, SLOT(SetStreamMetadata(QUrl,Song)));
|
connect(radio_model_, SIGNAL(StreamMetadataFound(QUrl,Song)), current_playlist_, SLOT(SetStreamMetadata(QUrl,Song)));
|
||||||
|
|
||||||
|
connect(shuffle_repeat_widget_, SIGNAL(ShuffleModeChanged(ShuffleRepeatWidget::ShuffleMode)),
|
||||||
|
current_playlist_, SLOT(ShuffleModeChanged(ShuffleRepeatWidget::ShuffleMode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::CurrentTabChanged(int index ){
|
void MainWindow::CurrentTabChanged(int index ){
|
||||||
|
124
src/playlist.cpp
124
src/playlist.cpp
@ -14,6 +14,7 @@
|
|||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <lastfm/ScrobblePoint>
|
#include <lastfm/ScrobblePoint>
|
||||||
|
|
||||||
@ -23,11 +24,14 @@ const char* Playlist::kSettingsGroup = "Playlist";
|
|||||||
Playlist::Playlist(QObject *parent) :
|
Playlist::Playlist(QObject *parent) :
|
||||||
QAbstractListModel(parent),
|
QAbstractListModel(parent),
|
||||||
current_is_paused_(false),
|
current_is_paused_(false),
|
||||||
|
current_virtual_index_(-1),
|
||||||
|
is_shuffled_(false),
|
||||||
scrobble_point_(-1),
|
scrobble_point_(-1),
|
||||||
has_scrobbled_(false),
|
has_scrobbled_(false),
|
||||||
ignore_sorting_(false),
|
ignore_sorting_(false),
|
||||||
title_(""),
|
title_(""),
|
||||||
index_(-1)
|
index_(-1),
|
||||||
|
shuffle_repeat_widget_(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,14 +115,68 @@ int Playlist::current_index() const {
|
|||||||
return current_item_.isValid() ? current_item_.row() : -1;
|
return current_item_.isValid() ? current_item_.row() : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Playlist::ShuffleModeChanged(ShuffleRepeatWidget::ShuffleMode mode) {
|
||||||
|
is_shuffled_ = (mode != ShuffleRepeatWidget::Shuffle_Off);
|
||||||
|
ReshuffleIndices();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Playlist::NextVirtualIndex(int i) const {
|
||||||
|
ShuffleRepeatWidget::RepeatMode repeat_mode = shuffle_repeat_widget_->repeat_mode();
|
||||||
|
ShuffleRepeatWidget::ShuffleMode shuffle_mode = shuffle_repeat_widget_->shuffle_mode();
|
||||||
|
bool album_only = repeat_mode == ShuffleRepeatWidget::Repeat_Album ||
|
||||||
|
shuffle_mode == ShuffleRepeatWidget::Shuffle_Album;
|
||||||
|
|
||||||
|
// This one's easy - if we have to repeat the current track then just return i
|
||||||
|
if (repeat_mode == ShuffleRepeatWidget::Repeat_Track)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
// If we're not bothered about whether a song is on the same album then
|
||||||
|
// return the next virtual index, whatever it is.
|
||||||
|
if (!album_only)
|
||||||
|
return i+1;
|
||||||
|
|
||||||
|
// We need to advance i until we get something else on the same album
|
||||||
|
Song last_song = current_item_metadata();
|
||||||
|
for (int j=i+1 ; j<virtual_items_.count(); ++j) {
|
||||||
|
Song this_song = item_at(virtual_items_[j])->Metadata();
|
||||||
|
if ((last_song.is_compilation() && this_song.is_compilation() ||
|
||||||
|
last_song.artist() == this_song.artist()) &&
|
||||||
|
last_song.album() == this_song.album()) {
|
||||||
|
return j; // Found one
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couldn't find one - return past the end of the list
|
||||||
|
return virtual_items_.count();
|
||||||
|
}
|
||||||
|
|
||||||
int Playlist::next_index() const {
|
int Playlist::next_index() const {
|
||||||
int i = current_index() + 1;
|
// Did we want to stop after this track?
|
||||||
if (i >= items_.count())
|
|
||||||
return -1;
|
|
||||||
if (stop_after_.isValid() && current_index() == stop_after_.row())
|
if (stop_after_.isValid() && current_index() == stop_after_.row())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return i;
|
int next_virtual_index = NextVirtualIndex(current_virtual_index_);
|
||||||
|
if (next_virtual_index >= virtual_items_.count()) {
|
||||||
|
// We've gone off the end of the playlist.
|
||||||
|
|
||||||
|
switch (shuffle_repeat_widget_->repeat_mode()) {
|
||||||
|
case ShuffleRepeatWidget::Repeat_Off:
|
||||||
|
return -1;
|
||||||
|
case ShuffleRepeatWidget::Repeat_Track:
|
||||||
|
next_virtual_index = current_virtual_index_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
next_virtual_index = NextVirtualIndex(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Still off the end? Then just give up
|
||||||
|
if (next_virtual_index >= virtual_items_.count())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return virtual_items_[next_virtual_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
int Playlist::previous_index() const {
|
int Playlist::previous_index() const {
|
||||||
@ -142,6 +200,23 @@ void Playlist::set_current_index(int i) {
|
|||||||
emit CurrentSongChanged(current_item_metadata());
|
emit CurrentSongChanged(current_item_metadata());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the virtual index
|
||||||
|
if (i == -1)
|
||||||
|
current_virtual_index_ = -1;
|
||||||
|
else if (is_shuffled_ && current_virtual_index_ == -1) {
|
||||||
|
// This is the first thing we're playing so we want to make sure the array
|
||||||
|
// is shuffled
|
||||||
|
ReshuffleIndices();
|
||||||
|
|
||||||
|
// Bring the one we've been asked to play to the start of the list
|
||||||
|
virtual_items_.takeAt(virtual_items_.indexOf(i));
|
||||||
|
virtual_items_.prepend(i);
|
||||||
|
current_virtual_index_ = 0;
|
||||||
|
} else if (is_shuffled_)
|
||||||
|
current_virtual_index_ = virtual_items_.indexOf(i);
|
||||||
|
else
|
||||||
|
current_virtual_index_ = i;
|
||||||
|
|
||||||
UpdateScrobblePoint();
|
UpdateScrobblePoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,14 +350,14 @@ QModelIndex Playlist::InsertItems(const QList<PlaylistItem*>& items, int after)
|
|||||||
const int end = start + items.count() - 1;
|
const int end = start + items.count() - 1;
|
||||||
|
|
||||||
beginInsertRows(QModelIndex(), start, end);
|
beginInsertRows(QModelIndex(), start, end);
|
||||||
|
|
||||||
for (int i=start ; i<=end ; ++i) {
|
for (int i=start ; i<=end ; ++i) {
|
||||||
items_.insert(i, items[i - start]);
|
items_.insert(i, items[i - start]);
|
||||||
|
virtual_items_ << virtual_items_.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
|
||||||
// Save();
|
// Save();
|
||||||
|
ReshuffleIndices();
|
||||||
|
|
||||||
return index(start, 0);
|
return index(start, 0);
|
||||||
}
|
}
|
||||||
@ -428,6 +503,7 @@ void Playlist::SaveR() const {
|
|||||||
void Playlist::RestoreR() {
|
void Playlist::RestoreR() {
|
||||||
qDeleteAll(items_);
|
qDeleteAll(items_);
|
||||||
items_.clear();
|
items_.clear();
|
||||||
|
virtual_items_.clear();
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
@ -444,6 +520,7 @@ void Playlist::RestoreR() {
|
|||||||
|
|
||||||
item->Restore(s);
|
item->Restore(s);
|
||||||
items_ << item;
|
items_ << item;
|
||||||
|
virtual_items_ << virtual_items_.count();
|
||||||
}
|
}
|
||||||
s.endArray();
|
s.endArray();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
@ -460,6 +537,20 @@ bool Playlist::removeRows(int row, int count, const QModelIndex& parent) {
|
|||||||
|
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
|
|
||||||
|
QList<int>::iterator it = virtual_items_.begin();
|
||||||
|
int i = 0;
|
||||||
|
while (it != virtual_items_.end()) {
|
||||||
|
if (*it >= items_.count()) {
|
||||||
|
if (i >= current_virtual_index_)
|
||||||
|
current_virtual_index_ --;
|
||||||
|
|
||||||
|
it = virtual_items_.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
// Save();
|
// Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -582,3 +673,22 @@ void Playlist::Shuffle() {
|
|||||||
|
|
||||||
// Save();
|
// Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Playlist::ReshuffleIndices() {
|
||||||
|
if (!is_shuffled_) {
|
||||||
|
std::sort(virtual_items_.begin(), virtual_items_.end());
|
||||||
|
if (current_index() != -1)
|
||||||
|
current_virtual_index_ = virtual_items_.indexOf(current_index());
|
||||||
|
} else {
|
||||||
|
QList<int>::iterator begin = virtual_items_.begin();
|
||||||
|
if (current_virtual_index_ != -1)
|
||||||
|
std::advance(begin, current_virtual_index_ + 1);
|
||||||
|
|
||||||
|
std::random_shuffle(begin, virtual_items_.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Playlist::set_shuffle_repeat_widget(ShuffleRepeatWidget* w) {
|
||||||
|
shuffle_repeat_widget_ = w;
|
||||||
|
ShuffleModeChanged(w->shuffle_mode());
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "playlistitem.h"
|
#include "playlistitem.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
#include "radioitem.h"
|
#include "radioitem.h"
|
||||||
|
#include "shufflerepeatwidget.h"
|
||||||
|
|
||||||
class RadioService;
|
class RadioService;
|
||||||
|
|
||||||
@ -74,6 +75,9 @@ class Playlist : public QAbstractListModel {
|
|||||||
void SetPlaylistIndex( int ipos ) { index_ = ipos ; }
|
void SetPlaylistIndex( int ipos ) { index_ = ipos ; }
|
||||||
int GetPlaylistIndex() const { return index_ ; }
|
int GetPlaylistIndex() const { return index_ ; }
|
||||||
|
|
||||||
|
void set_shuffle_repeat_widget(ShuffleRepeatWidget* w);
|
||||||
|
ShuffleRepeatWidget* shuffle_repeat_widget() const { return shuffle_repeat_widget_; }
|
||||||
|
|
||||||
// Scrobbling
|
// Scrobbling
|
||||||
int scrobble_point() const { return scrobble_point_; }
|
int scrobble_point() const { return scrobble_point_; }
|
||||||
bool has_scrobbled() const { return has_scrobbled_; }
|
bool has_scrobbled() const { return has_scrobbled_; }
|
||||||
@ -114,12 +118,16 @@ class Playlist : public QAbstractListModel {
|
|||||||
void Clear();
|
void Clear();
|
||||||
void Shuffle();
|
void Shuffle();
|
||||||
|
|
||||||
|
void ShuffleModeChanged(ShuffleRepeatWidget::ShuffleMode mode);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void CurrentSongChanged(const Song& metadata);
|
void CurrentSongChanged(const Song& metadata);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetCurrentIsPaused(bool paused);
|
void SetCurrentIsPaused(bool paused);
|
||||||
void UpdateScrobblePoint();
|
void UpdateScrobblePoint();
|
||||||
|
void ReshuffleIndices();
|
||||||
|
int NextVirtualIndex(int i) const;
|
||||||
|
|
||||||
// Persistence
|
// Persistence
|
||||||
void SaveR() const;
|
void SaveR() const;
|
||||||
@ -127,10 +135,14 @@ class Playlist : public QAbstractListModel {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QList<PlaylistItem*> items_;
|
QList<PlaylistItem*> items_;
|
||||||
|
QList<int> virtual_items_; // Contains the indices into items_ in the order
|
||||||
|
// that they will be played.
|
||||||
|
bool is_shuffled_;
|
||||||
|
|
||||||
QPersistentModelIndex current_item_;
|
QPersistentModelIndex current_item_;
|
||||||
QPersistentModelIndex stop_after_;
|
QPersistentModelIndex stop_after_;
|
||||||
bool current_is_paused_;
|
bool current_is_paused_;
|
||||||
|
int current_virtual_index_;
|
||||||
|
|
||||||
int scrobble_point_;
|
int scrobble_point_;
|
||||||
bool has_scrobbled_;
|
bool has_scrobbled_;
|
||||||
@ -139,6 +151,8 @@ class Playlist : public QAbstractListModel {
|
|||||||
bool ignore_sorting_;
|
bool ignore_sorting_;
|
||||||
QString title_;
|
QString title_;
|
||||||
int index_ ;
|
int index_ ;
|
||||||
|
|
||||||
|
ShuffleRepeatWidget* shuffle_repeat_widget_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PLAYLIST_H
|
#endif // PLAYLIST_H
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class QMenu;
|
|
||||||
|
|
||||||
#include "ui_shufflerepeatwidget.h"
|
#include "ui_shufflerepeatwidget.h"
|
||||||
|
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
class ShuffleRepeatWidget : public QWidget {
|
class ShuffleRepeatWidget : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -27,21 +27,25 @@ class ShuffleRepeatWidget : public QWidget {
|
|||||||
|
|
||||||
static const char* kSettingsGroup;
|
static const char* kSettingsGroup;
|
||||||
|
|
||||||
void Load();
|
RepeatMode repeat_mode() const { return repeat_mode_; }
|
||||||
void Save();
|
ShuffleMode shuffle_mode() const { return shuffle_mode_; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void SetRepeatMode(RepeatMode mode);
|
void SetRepeatMode(ShuffleRepeatWidget::RepeatMode mode);
|
||||||
void SetShuffleMode(ShuffleMode mode);
|
void SetShuffleMode(ShuffleRepeatWidget::ShuffleMode mode);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void RepeatModeChanged(RepeatMode mode);
|
void RepeatModeChanged(ShuffleRepeatWidget::RepeatMode mode);
|
||||||
void ShuffleModeChanged(ShuffleMode mode);
|
void ShuffleModeChanged(ShuffleRepeatWidget::ShuffleMode mode);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void RepeatActionTriggered(QAction*);
|
void RepeatActionTriggered(QAction*);
|
||||||
void ShuffleActionTriggered(QAction*);
|
void ShuffleActionTriggered(QAction*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Load();
|
||||||
|
void Save();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::ShuffleRepeatWidget ui_;
|
Ui::ShuffleRepeatWidget ui_;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user