Commit d8a5c948 authored by Michael Pyne's avatar Michael Pyne
Browse files

playlist: Simplify dynamic playlist tracking of other playlists.

We store pointers to other `Playlist` entries to ensure we can update
their playing item state (which in the old JuK was a 'playback arrow'
icon that would show up in the row for playing items). The idea being
that there would be an entry in the Play Queue showing that an item was
playing but also the same source item in the source playlist would also
indicate that it was playing.

This has been susceptible to all the normal frailties of storing
pointers to objects whose lifetime is unpredictable. By using guarded
pointers we can at least hopefully avoid crashing (especially on
shutdown).
parent 5bd79f38
......@@ -22,12 +22,7 @@
#include <QTimer>
#include <QObject>
PlaylistDirtyObserver::PlaylistDirtyObserver(DynamicPlaylist* parent, Playlist* playlist) :
m_parent(parent)
{
QObject::connect(&(playlist->signaller), &PlaylistInterfaceSignaller::playingItemDataChanged, m_parent, &DynamicPlaylist::slotSetDirty);
}
#include <algorithm>
////////////////////////////////////////////////////////////////////////////////
// public methods
......@@ -38,23 +33,27 @@ DynamicPlaylist::DynamicPlaylist(const PlaylistList &playlists,
const QString &name,
const QString &iconName,
bool setupPlaylist,
bool synchronizePlaying) :
Playlist(collection, true),
m_playlists(playlists),
m_dirty(true),
m_synchronizePlaying(synchronizePlaying)
bool synchronizePlaying)
: Playlist(collection, true)
, m_dirty(true)
, m_synchronizePlaying(synchronizePlaying)
{
if(setupPlaylist)
collection->setupPlaylist(this, iconName);
setName(name);
setAllowDuplicates(false);
setSortingEnabled(false);
for(PlaylistList::ConstIterator it = playlists.constBegin(); it != playlists.constEnd(); ++it)
m_observers.append(new PlaylistDirtyObserver(this, *it));
for(const auto playlist : playlists) {
m_playlists << QPointer<Playlist>(playlist);
connect(&(playlist->signaller), &PlaylistInterfaceSignaller::playingItemDataChanged,
this, &DynamicPlaylist::slotSetDirty);
}
connect(CollectionList::instance(), SIGNAL(signalCollectionChanged()), this, SLOT(slotSetDirty()));
connect(CollectionList::instance(), &CollectionList::signalCollectionChanged,
this, &DynamicPlaylist::slotSetDirty);
}
DynamicPlaylist::~DynamicPlaylist()
......@@ -65,14 +64,16 @@ DynamicPlaylist::~DynamicPlaylist()
checkUpdateItems();
lower();
foreach(PlaylistDirtyObserver *observer, m_observers)
delete observer;
}
void DynamicPlaylist::setPlaylists(const PlaylistList &playlists)
{
m_playlists = playlists;
m_playlists.clear();
for(const auto playlist : playlists) {
m_playlists << QPointer<Playlist>(playlist);
}
updateItems();
}
......@@ -82,8 +83,11 @@ void DynamicPlaylist::setPlaylists(const PlaylistList &playlists)
void DynamicPlaylist::slotReload()
{
for(PlaylistList::Iterator it = m_playlists.begin(); it != m_playlists.end(); ++it)
(*it)->slotReload();
for(const auto playlist : m_playlists) {
if(!playlist)
continue;
playlist->slotReload();
}
checkUpdateItems();
}
......@@ -96,23 +100,23 @@ void DynamicPlaylist::lower(QWidget *top)
if(playing()) {
PlaylistList l;
l.append(this);
for(PlaylistList::Iterator it = m_playlists.begin();
it != m_playlists.end(); ++it)
{
(*it)->synchronizePlayingItems(l, true);
}
}
PlaylistItemList list = PlaylistItem::playingItems();
for(PlaylistItemList::Iterator it = list.begin(); it != list.end(); ++it) {
if((*it)->playlist() == this) {
list.erase(it);
break;
for(const auto playlist : m_playlists) {
if(!playlist)
continue;
playlist->synchronizePlayingItems(l, true);
}
}
if(!list.isEmpty())
TrackSequenceManager::instance()->setCurrentPlaylist(list.front()->playlist());
const auto playlistItems = PlaylistItem::playingItems();
const auto itemIt = std::find_if(
playlistItems.begin(), playlistItems.end(),
[this](const PlaylistItem *item) {
return item->playlist() != this;
});
if(itemIt != playlistItems.end())
TrackSequenceManager::instance()->setCurrentPlaylist((*itemIt)->playlist());
}
////////////////////////////////////////////////////////////////////////////////
......@@ -141,15 +145,20 @@ void DynamicPlaylist::updateItems()
{
PlaylistItemList siblings;
for(PlaylistList::ConstIterator it = m_playlists.constBegin(); it != m_playlists.constEnd(); ++it)
siblings += (*it)->items();
for(const auto playlist : qAsConst(m_playlists)) {
if(!playlist)
continue;
siblings += playlist->items();
}
if(m_siblings != siblings) {
m_siblings = siblings;
this->synchronizeItemsTo(siblings);
if(m_synchronizePlaying) {
synchronizePlayingItems(m_playlists, true);
for(const auto playlist : m_playlists) {
synchronizePlayingItems(playlist, true);
}
}
}
}
......
......@@ -20,9 +20,12 @@
#include "playlist.h"
#include <QVector>
#include <QPointer>
class PlaylistDirtyObserver;
using GuardedPlaylist = QPointer<Playlist>;
/**
* A Playlist that is a union of other playlists that is created dynamically.
*/
......@@ -102,22 +105,12 @@ private:
void checkUpdateItems();
private:
QVector<PlaylistDirtyObserver *> m_observers;
PlaylistItemList m_siblings;
PlaylistList m_playlists;
QVector<GuardedPlaylist> m_playlists;
bool m_dirty;
bool m_synchronizePlaying;
};
class PlaylistDirtyObserver
{
public:
PlaylistDirtyObserver(DynamicPlaylist *parent, Playlist *playlist);
private:
DynamicPlaylist *m_parent;
};
#endif
// vim: set et sw=4 tw=0 sta:
......@@ -409,25 +409,29 @@ void Playlist::setSearchEnabled(bool enabled)
// Mostly seems to be for DynamicPlaylist
// TODO: See if this can't all be eliminated by making 'is-playing' a predicate
// of the playlist item itself
void Playlist::synchronizePlayingItems(const PlaylistList &sources, bool setMaster)
void Playlist::synchronizePlayingItems(Playlist *playlist, bool setMaster)
{
foreach(const Playlist *p, sources) {
if(p->playing()) {
CollectionListItem *base = playingItem()->collectionItem();
for(QTreeWidgetItemIterator itemIt(this); *itemIt; ++itemIt) {
PlaylistItem *item = static_cast<PlaylistItem *>(*itemIt);
if(base == item->collectionItem()) {
item->setPlaying(true, setMaster);
PlaylistItemList playing = PlaylistItem::playingItems();
TrackSequenceManager::instance()->setCurrent(item);
return;
}
}
if(!playlist || !playlist->playing())
return;
CollectionListItem *base = playingItem()->collectionItem();
for(QTreeWidgetItemIterator itemIt(playlist); *itemIt; ++itemIt) {
PlaylistItem *item = static_cast<PlaylistItem *>(*itemIt);
if(base == item->collectionItem()) {
item->setPlaying(true, setMaster);
TrackSequenceManager::instance()->setCurrent(item);
return;
}
}
}
void Playlist::synchronizePlayingItems(const PlaylistList &sources, bool setMaster)
{
for(auto p : sources) {
synchronizePlayingItems(p, setMaster);
}
}
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////
......
......@@ -301,6 +301,13 @@ public:
*/
virtual bool searchIsEditable() const { return false; }
/**
* Synchronizes the playing item in this playlist with the playing item
* in \a playlist. If \a setMaster is true, this list will become the source
* for determining the next item.
*/
void synchronizePlayingItems(Playlist *playlist, bool setMaster);
/**
* Synchronizes the playing item in this playlist with the playing item
* in \a sources. If \a setMaster is true, this list will become the source
......
......@@ -77,6 +77,8 @@ PlaylistSplitter::~PlaylistSplitter()
{
saveConfig();
m_playlistBox->stop(); // Remove playing item U/I state
// TagEditor needs to write its configuration out while it's still valid,
// destroy it now.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment