diff --git a/Changelog b/Changelog index dd9ac62c..66b5573a 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,7 @@ Unreleased: * Added Deezer support * New improved fancy tabwidget * Fixed bug not loading engine settings + * Moved queue manager into tabbar for easier access Version 0.3.3: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 24c2d34a..d98a9182 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -164,11 +164,12 @@ set(SOURCES playlist/playlisttabbar.cpp playlist/playlistundocommands.cpp playlist/playlistview.cpp - playlist/queue.cpp - playlist/queuemanager.cpp playlist/songloaderinserter.cpp playlist/songplaylistitem.cpp + queue/queue.cpp + queue/queueview.cpp + playlistparsers/asxiniparser.cpp playlistparsers/asxparser.cpp playlistparsers/cueparser.cpp @@ -331,11 +332,12 @@ set(HEADERS playlist/playlisttabbar.h playlist/playlistview.h playlist/playlistitemmimedata.h - playlist/queue.h - playlist/queuemanager.h playlist/songloaderinserter.h playlist/songmimedata.h + queue/queue.h + queue/queueview.h + playlistparsers/asxiniparser.h playlistparsers/asxparser.h playlistparsers/cueparser.h @@ -446,7 +448,8 @@ set(UI playlist/playlistlistcontainer.ui playlist/playlistsaveoptionsdialog.ui playlist/playlistsequence.ui - playlist/queuemanager.ui + + queue/queueview.ui covermanager/albumcoverexport.ui covermanager/albumcovermanager.ui diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index 20a6da77..857348df 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -112,8 +112,8 @@ #include "playlist/playlistmanager.h" #include "playlist/playlistsequence.h" #include "playlist/playlistview.h" -#include "playlist/queue.h" -#include "playlist/queuemanager.h" +#include "queue/queue.h" +#include "queue/queueview.h" #include "playlistparsers/playlistparser.h" #include "analyzer/analyzercontainer.h" #include "equalizer/equalizer.h" @@ -187,6 +187,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co device_view_(device_view_container_->view()), #endif playlist_list_(new PlaylistListContainer(this)), + queue_view_(new QueueView(this)), settings_dialog_(std::bind(&MainWindow::CreateSettingsDialog, this)), cover_manager_([=]() { AlbumCoverManager *cover_manager = new AlbumCoverManager(app, app->collection_backend()); @@ -206,11 +207,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co return dialog; }), #endif - queue_manager_([=]() { - QueueManager *manager = new QueueManager; - manager->SetPlaylistManager(app->playlist_manager()); - return manager; - }), #ifdef HAVE_STREAM_TIDAL tidal_search_view_(new InternetSearchView(app_, app_->tidal_search(), TidalSettingsPage::kSettingsGroup, SettingsDialog::Page_Tidal, this)), #endif @@ -268,6 +264,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), "Collection"); ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), "Files"); ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), "Playlists"); + ui_->tabs->addTab(queue_view_, IconLoader::Load("footsteps"), "Queue"); #ifndef Q_OS_WIN ui_->tabs->addTab(device_view_, IconLoader::Load("device"), "Devices"); #endif @@ -360,7 +357,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co // Configure ui_->action_cover_manager->setIcon(IconLoader::Load("document-download")); - ui_->action_queue_manager->setIcon(IconLoader::Load("footsteps")); ui_->action_edit_track->setIcon(IconLoader::Load("edit-rename")); ui_->action_equalizer->setIcon(IconLoader::Load("equalizer")); ui_->action_update_collection->setIcon(IconLoader::Load("view-refresh")); @@ -413,7 +409,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co connect(ui_->action_jump, SIGNAL(triggered()), ui_->playlist->view(), SLOT(JumpToCurrentlyPlayingTrack())); connect(ui_->action_update_collection, SIGNAL(triggered()), app_->collection(), SLOT(IncrementalScan())); connect(ui_->action_full_collection_scan, SIGNAL(triggered()), app_->collection(), SLOT(FullScan())); - connect(ui_->action_queue_manager, SIGNAL(triggered()), SLOT(ShowQueueManager())); //connect(ui_->action_add_files_to_transcoder, SIGNAL(triggered()), SLOT(AddFilesToTranscoder())); // Playlist view actions @@ -699,6 +694,8 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co // Load playlists app_->playlist_manager()->Init(app_->collection_backend(), app_->playlist_backend(), ui_->playlist_sequence, ui_->playlist); + queue_view_->SetPlaylistManager(app_->playlist_manager()); + // This connection must be done after the playlists have been initialized. connect(this, SIGNAL(StopAfterToggled(bool)), osd_, SLOT(StopAfterToggle(bool))); @@ -2224,14 +2221,6 @@ void MainWindow::CheckFullRescanRevisions() { } } -void MainWindow::ShowQueueManager() { - //if (!queue_manager_) { - //queue_manager_.reset(new QueueManager); - //queue_manager_->SetPlaylistManager(app_->playlist_manager()); - //} - queue_manager_->show(); -} - void MainWindow::PlaylistViewSelectionModelChanged() { connect(ui_->playlist->view()->selectionModel(),SIGNAL(currentChanged(QModelIndex, QModelIndex)), SLOT(PlaylistCurrentChanged(QModelIndex))); diff --git a/src/core/mainwindow.h b/src/core/mainwindow.h index 89158fde..e03f3480 100644 --- a/src/core/mainwindow.h +++ b/src/core/mainwindow.h @@ -78,7 +78,7 @@ class GlobalShortcuts; class MimeData; class OrganiseDialog; class PlaylistListContainer; -class QueueManager; +class QueueView; class Song; class SystemTrayIcon; #if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT) @@ -252,7 +252,6 @@ signals: void ShowTranscodeDialog(); #endif void ShowErrorDialog(const QString& message); - void ShowQueueManager(); void EnsureSettingsDialogCreated(); void EnsureEditTagDialogCreated(); SettingsDialog *CreateSettingsDialog(); @@ -317,6 +316,7 @@ signals: DeviceView *device_view_; #endif PlaylistListContainer *playlist_list_; + QueueView *queue_view_; Lazy settings_dialog_; Lazy cover_manager_; @@ -328,7 +328,6 @@ signals: #ifdef HAVE_GSTREAMER Lazy organise_dialog_; #endif - Lazy queue_manager_; #if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT) std::unique_ptr tag_fetcher_; diff --git a/src/core/mainwindow.ui b/src/core/mainwindow.ui index 9e332b48..f1d256b0 100644 --- a/src/core/mainwindow.ui +++ b/src/core/mainwindow.ui @@ -435,7 +435,6 @@ &Tools - @@ -674,11 +673,6 @@ &Update changed collection folders - - - &Queue Manager - - About &Qt diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index d9db1bc3..3dbcc927 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -71,6 +71,7 @@ #include "collection/collection.h" #include "collection/collectionbackend.h" #include "collection/collectionplaylistitem.h" +#include "queue/queue.h" #include "playlist.h" #include "playlistitem.h" #include "playlistview.h" @@ -79,7 +80,6 @@ #include "playlistfilter.h" #include "playlistitemmimedata.h" #include "playlistundocommands.h" -#include "queue.h" #include "songloaderinserter.h" #include "songmimedata.h" #include "songplaylistitem.h" diff --git a/src/playlist/queue.cpp b/src/queue/queue.cpp similarity index 82% rename from src/playlist/queue.cpp rename to src/queue/queue.cpp index 7cd0fb98..5e0fb0df 100644 --- a/src/playlist/queue.cpp +++ b/src/queue/queue.cpp @@ -38,14 +38,22 @@ #include #include -#include "playlist.h" +#include "core/utilities.h" +#include "playlist/playlist.h" #include "queue.h" using std::stable_sort; const char *Queue::kRowsMimetype = "application/x-strawberry-queue-rows"; -Queue::Queue(QObject *parent) : QAbstractProxyModel(parent) {} +Queue::Queue(Playlist *parent) : QAbstractProxyModel(parent), playlist_(parent), total_length_ns_(0) { + + connect(this, SIGNAL(ItemCountChanged(int)), SLOT(UpdateTotalLength())); + connect(this, SIGNAL(TotalLengthChanged(quint64)), SLOT(UpdateSummaryText())); + + UpdateSummaryText(); + +} QModelIndex Queue::mapFromSource(const QModelIndex &source_index) const { @@ -101,6 +109,7 @@ void Queue::SourceDataChanged(const QModelIndex &top_left, const QModelIndex &bo emit dataChanged(proxy_index, proxy_index); } + emit ItemCountChanged(this->ItemCount()); } @@ -114,6 +123,7 @@ void Queue::SourceLayoutChanged() { --i; } } + emit ItemCountChanged(this->ItemCount()); } @@ -176,20 +186,83 @@ void Queue::ToggleTracks(const QModelIndexList &source_indexes) { } +void Queue::InsertFirst(const QModelIndexList &source_indexes) { + + for (const QModelIndex &source_index : source_indexes) { + QModelIndex proxy_index = mapFromSource(source_index); + if (proxy_index.isValid()) { + // Already in the queue, so remove it to be reinserted later + const int row = proxy_index.row(); + beginRemoveRows(QModelIndex(), row, row); + source_indexes_.removeAt(row); + endRemoveRows(); + } + } + + const int rows = source_indexes.count(); + // Enqueue the tracks at the beginning + beginInsertRows(QModelIndex(), 0, rows - 1); + int offset = 0; + for (const QModelIndex& source_index : source_indexes) { + source_indexes_.insert(offset, QPersistentModelIndex(source_index)); + offset++; + } + endInsertRows(); + +} + int Queue::PositionOf(const QModelIndex &source_index) const { return mapFromSource(source_index).row(); } -bool Queue::is_empty() const { - return source_indexes_.isEmpty(); +bool Queue::is_empty() const { return source_indexes_.isEmpty(); } + +int Queue::ItemCount() const { return source_indexes_.length(); } + +quint64 Queue::GetTotalLength() const { return total_length_ns_; } + +void Queue::UpdateTotalLength() { + + quint64 total = 0; + + for (QPersistentModelIndex row : source_indexes_) { + int id = row.row(); + + Q_ASSERT(playlist_->has_item_at(id)); + + quint64 length = playlist_->item_at(id)->Metadata().length_nanosec(); + if (length > 0) total += length; + } + + total_length_ns_ = total; + + emit TotalLengthChanged(total); + +} + +void Queue::UpdateSummaryText() { + + QString summary; + int tracks = this->ItemCount(); + quint64 nanoseconds = this->GetTotalLength(); + + summary += tracks == 1 ? tr("1 track") : tr("%1 tracks").arg(tracks); + + if (nanoseconds) + summary += " - [ " + Utilities::WordyTimeNanosec(nanoseconds) + " ]"; + + emit SummaryTextChanged(summary); + } void Queue::Clear() { + if (source_indexes_.isEmpty()) return; beginRemoveRows(QModelIndex(), 0, source_indexes_.count() - 1); source_indexes_.clear(); endRemoveRows(); + } void Queue::Move(const QList &proxy_rows, int pos) { diff --git a/src/playlist/queue.h b/src/queue/queue.h similarity index 84% rename from src/playlist/queue.h rename to src/queue/queue.h index eb7b368d..9507b441 100644 --- a/src/playlist/queue.h +++ b/src/queue/queue.h @@ -34,11 +34,13 @@ #include #include +#include "playlist/playlist.h" + class Queue : public QAbstractProxyModel { Q_OBJECT public: - Queue(QObject *parent = nullptr); + Queue(Playlist *parent = nullptr); static const char *kRowsMimetype; @@ -47,10 +49,13 @@ class Queue : public QAbstractProxyModel { int PositionOf(const QModelIndex &source_index) const; bool ContainsSourceRow(int source_row) const; int PeekNext() const; + int ItemCount() const; + quint64 GetTotalLength() const; // Modify the queue int TakeNext(); void ToggleTracks(const QModelIndexList &source_indexes); + void InsertFirst(const QModelIndexList &source_indexes); void Clear(); void Move(const QList &proxy_rows, int pos); void MoveUp(int row); @@ -75,12 +80,24 @@ class Queue : public QAbstractProxyModel { bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); Qt::ItemFlags flags(const QModelIndex &index) const; -private slots: + public slots: + void UpdateSummaryText(); + + signals: + void TotalLengthChanged(const quint64 length); + void ItemCountChanged(const int count); + void SummaryTextChanged(const QString& message); + + private slots: void SourceDataChanged(const QModelIndex &top_left, const QModelIndex &bottom_right); void SourceLayoutChanged(); + void UpdateTotalLength(); -private: + private: QList source_indexes_; + const Playlist *playlist_; + quint64 total_length_ns_; + }; #endif // QUEUE_H diff --git a/src/playlist/queuemanager.cpp b/src/queue/queueview.cpp similarity index 83% rename from src/playlist/queuemanager.cpp rename to src/queue/queueview.cpp index e0f22053..a04479b5 100644 --- a/src/playlist/queuemanager.cpp +++ b/src/queue/queueview.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -31,22 +30,24 @@ #include #include #include +#include #include "core/iconloader.h" -#include "playlist.h" -#include "playlistdelegates.h" -#include "playlistmanager.h" +#include "playlist/playlist.h" +#include "playlist/playlistdelegates.h" +#include "playlist/playlistmanager.h" #include "queue.h" -#include "queuemanager.h" -#include "ui_queuemanager.h" +#include "queueview.h" +#include "ui_queueview.h" using std::stable_sort; -QueueManager::QueueManager(QWidget *parent) - : QDialog(parent), - ui_(new Ui_QueueManager), +QueueView::QueueView(QWidget *parent) + : QWidget(parent), + ui_(new Ui_QueueView), playlists_(nullptr), current_playlist_(nullptr) { + ui_->setupUi(this); ui_->list->setItemDelegate(new QueuedItemDelegate(this, 0)); @@ -65,16 +66,13 @@ QueueManager::QueueManager(QWidget *parent) connect(ui_->remove, SIGNAL(clicked()), SLOT(Remove())); connect(ui_->clear, SIGNAL(clicked()), SLOT(Clear())); - QShortcut *close = new QShortcut(QKeySequence::Close, this); - connect(close, SIGNAL(activated()), SLOT(close())); - } -QueueManager::~QueueManager() { +QueueView::~QueueView() { delete ui_; } -void QueueManager::SetPlaylistManager(PlaylistManager *manager) { +void QueueView::SetPlaylistManager(PlaylistManager *manager) { playlists_ = manager; @@ -83,12 +81,13 @@ void QueueManager::SetPlaylistManager(PlaylistManager *manager) { } -void QueueManager::CurrentPlaylistChanged(Playlist *playlist) { +void QueueView::CurrentPlaylistChanged(Playlist *playlist) { if (current_playlist_) { disconnect(current_playlist_->queue(), SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(UpdateButtonState())); disconnect(current_playlist_->queue(), SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(UpdateButtonState())); disconnect(current_playlist_->queue(), SIGNAL(layoutChanged()), this, SLOT(UpdateButtonState())); + disconnect(current_playlist_->queue(), SIGNAL(SummaryTextChanged(QString)), ui_->summary, SLOT(setText(QString))); disconnect(current_playlist_, SIGNAL(destroyed()), this, SLOT(PlaylistDestroyed())); } @@ -97,15 +96,18 @@ void QueueManager::CurrentPlaylistChanged(Playlist *playlist) { connect(current_playlist_->queue(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(UpdateButtonState())); connect(current_playlist_->queue(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(UpdateButtonState())); connect(current_playlist_->queue(), SIGNAL(layoutChanged()), this, SLOT(UpdateButtonState())); + connect(current_playlist_->queue(), SIGNAL(SummaryTextChanged(QString)), ui_->summary, SLOT(setText(QString))); connect(current_playlist_, SIGNAL(destroyed()), this, SLOT(PlaylistDestroyed())); ui_->list->setModel(current_playlist_->queue()); connect(ui_->list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(UpdateButtonState())); + QTimer::singleShot(0, current_playlist_->queue(), SLOT(UpdateSummaryText())); + } -void QueueManager::MoveUp() { +void QueueView::MoveUp() { QModelIndexList indexes = ui_->list->selectionModel()->selectedRows(); std::stable_sort(indexes.begin(), indexes.end()); @@ -118,7 +120,7 @@ void QueueManager::MoveUp() { } -void QueueManager::MoveDown() { +void QueueView::MoveDown() { QModelIndexList indexes = ui_->list->selectionModel()->selectedRows(); std::stable_sort(indexes.begin(), indexes.end()); @@ -132,11 +134,11 @@ void QueueManager::MoveDown() { } -void QueueManager::Clear() { +void QueueView::Clear() { current_playlist_->queue()->Clear(); } -void QueueManager::Remove() { +void QueueView::Remove() { // collect the rows to be removed QList row_list; @@ -148,7 +150,7 @@ void QueueManager::Remove() { } -void QueueManager::UpdateButtonState() { +void QueueView::UpdateButtonState() { const QModelIndex current = ui_->list->selectionModel()->currentIndex(); @@ -167,7 +169,7 @@ void QueueManager::UpdateButtonState() { } -void QueueManager::PlaylistDestroyed() { +void QueueView::PlaylistDestroyed() { current_playlist_ = nullptr; // We'll get another CurrentPlaylistChanged() soon } diff --git a/src/playlist/queuemanager.h b/src/queue/queueview.h similarity index 85% rename from src/playlist/queuemanager.h rename to src/queue/queueview.h index aac6a5df..3493c862 100644 --- a/src/playlist/queuemanager.h +++ b/src/queue/queueview.h @@ -18,8 +18,8 @@ * */ -#ifndef QUEUEMANAGER_H -#define QUEUEMANAGER_H +#ifndef QUEUEVIEW_H +#define QUEUEVIEW_H #include "config.h" @@ -30,14 +30,14 @@ class Playlist; class PlaylistManager; -class Ui_QueueManager; +class Ui_QueueView; -class QueueManager : public QDialog { +class QueueView : public QWidget { Q_OBJECT public: - QueueManager(QWidget *parent = nullptr); - ~QueueManager(); + QueueView(QWidget *parent = nullptr); + ~QueueView(); void SetPlaylistManager(PlaylistManager *manager); @@ -52,10 +52,10 @@ private slots: void Clear(); private: - Ui_QueueManager *ui_; + Ui_QueueView *ui_; PlaylistManager *playlists_; Playlist *current_playlist_; }; -#endif // QUEUEMANAGER_H +#endif // QUEUEVIEW_H diff --git a/src/playlist/queuemanager.ui b/src/queue/queueview.ui similarity index 65% rename from src/playlist/queuemanager.ui rename to src/queue/queueview.ui index 807e31f2..547dee15 100644 --- a/src/playlist/queuemanager.ui +++ b/src/queue/queueview.ui @@ -1,7 +1,7 @@ - QueueManager - + QueueView + 0 @@ -11,15 +11,127 @@ - Queue Manager + QueueView - + :/icons/64x64/strawberry.png:/icons/64x64/strawberry.png - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - + + + 0 + + + + + + + false + + + Move down + + + + 16 + 16 + + + + Ctrl+↑ + + + + + + + false + + + Move up + + + + 16 + 16 + + + + Ctrl+↓ + + + + + + + false + + + Remove + + + + + + + + + + false + + + Clear + + + + 16 + 16 + + + + Ctrl+K + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + @@ -54,143 +166,10 @@ - - - - - - false - - - Move up - - - - 16 - 16 - - - - Ctrl+Up - - - - - - - false - - - Move down - - - - 16 - 16 - - - - Ctrl+Down - - - - - - - false - - - Remove - - - - - - - - - - false - - - Clear - - - - 16 - 16 - - - - Ctrl+K - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Close - - - - - - - - - - buttonBox - accepted() - QueueManager - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - QueueManager - reject() - - - 316 - 260 - - - 286 - 274 - - - - + +