From 08f32d1de69fb76bf26dd07da91b84e3c68c34b2 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Sat, 29 Aug 2020 19:55:00 +0200 Subject: [PATCH] Refactor playlist view/header code - Don't reload all settings when changing playlists - Fix initial playlist header columns sizes - Properly reset header state when resetting columns --- src/core/mainwindow.cpp | 3 +- src/engine/gstenginepipeline.cpp | 1 - src/playlist/playlistdelegates.h | 6 +- src/playlist/playlistheader.cpp | 2 +- src/playlist/playlistview.cpp | 255 ++++++++++++++---------------- src/playlist/playlistview.h | 20 +-- src/widgets/stretchheaderview.cpp | 48 +++++- src/widgets/stretchheaderview.h | 3 +- 8 files changed, 181 insertions(+), 157 deletions(-) diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index 88765ee14..730e88ec8 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -361,7 +361,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSDBase *osd ui_->playlist->SetManager(app_->playlist_manager()); - ui_->playlist->view()->SetApplication(app_); + ui_->playlist->view()->Init(app_); collection_view_->view()->setModel(collection_sort_model_); collection_view_->view()->SetApplication(app_); @@ -1066,7 +1066,6 @@ void MainWindow::SaveSettings() { SaveGeometry(); SavePlaybackStatus(); ui_->tabs->SaveSettings(kSettingsGroup); - ui_->playlist->view()->SaveGeometry(); ui_->playlist->view()->SaveSettings(); app_->scrobbler()->WriteCache(); diff --git a/src/engine/gstenginepipeline.cpp b/src/engine/gstenginepipeline.cpp index c6d5a5515..553bf30d7 100644 --- a/src/engine/gstenginepipeline.cpp +++ b/src/engine/gstenginepipeline.cpp @@ -1054,7 +1054,6 @@ GstState GstEnginePipeline::state() const { QFuture GstEnginePipeline::SetState(const GstState state) { return ConcurrentRun::Run(&set_state_threadpool_, &gst_element_set_state, pipeline_, state); - } bool GstEnginePipeline::Seek(const qint64 nanosec) { diff --git a/src/playlist/playlistdelegates.h b/src/playlist/playlistdelegates.h index 776f65f21..123ca3a09 100644 --- a/src/playlist/playlistdelegates.h +++ b/src/playlist/playlistdelegates.h @@ -56,7 +56,7 @@ class CollectionBackend; class Player; class QueuedItemDelegate : public QStyledItemDelegate { -public: + public: explicit QueuedItemDelegate(QObject *parent, int indicator_column = Playlist::Column_Title); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; @@ -145,14 +145,14 @@ class TagCompletionModel : public QStringListModel { class TagCompleter : public QCompleter { Q_OBJECT -public: + public: explicit TagCompleter(CollectionBackend *backend, Playlist::Column column, QLineEdit *editor); ~TagCompleter() override; private slots: void ModelReady(QFuture future); -private: + private: QLineEdit *editor_; }; diff --git a/src/playlist/playlistheader.cpp b/src/playlist/playlistheader.cpp index 14a9f9292..71dabed56 100644 --- a/src/playlist/playlistheader.cpp +++ b/src/playlist/playlistheader.cpp @@ -143,5 +143,5 @@ void PlaylistHeader::enterEvent(QEvent*) { } void PlaylistHeader::ResetColumns() { - view_->ResetColumns(); + view_->ResetHeaderState(); } diff --git a/src/playlist/playlistview.cpp b/src/playlist/playlistview.cpp index e8f2bf66f..9766a7d91 100644 --- a/src/playlist/playlistview.cpp +++ b/src/playlist/playlistview.cpp @@ -128,7 +128,6 @@ void PlaylistProxyStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt } - PlaylistView::PlaylistView(QWidget *parent) : QTreeView(parent), app_(nullptr), @@ -143,11 +142,10 @@ PlaylistView::PlaylistView(QWidget *parent) background_image_keep_aspect_ratio_(true), blur_radius_(AppearanceSettingsPage::kDefaultBlurRadius), opacity_level_(AppearanceSettingsPage::kDefaultOpacityLevel), - initialized_(false), background_initialized_(false), - setting_initial_header_layout_(false), - read_only_settings_(true), - state_loaded_(false), + set_initial_header_layout_(false), + header_state_loaded_(false), + header_state_restored_(false), previous_background_image_opacity_(0.0), fade_animation_(new QTimeLine(1000, this)), force_background_redraw_(false), @@ -169,20 +167,28 @@ PlaylistView::PlaylistView(QWidget *parent) currenttrack_pause_(":/pictures/currenttrack_pause.png"), cached_current_row_row_(-1), drop_indicator_row_(-1), - drag_over_(false) { + drag_over_(false), + column_alignment_(DefaultColumnAlignment()) { setHeader(header_); header_->setSectionsMovable(true); #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) header_->setFirstSectionMovable(true); #endif + header_->setSortIndicator(Playlist::Column_Title, Qt::AscendingOrder); + setStyle(style_); setMouseTracking(true); + setAlternatingRowColors(true); + setAttribute(Qt::WA_MacShowFocusRect, false); +#ifdef Q_OS_MACOS + setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); +#endif - connect(header_, SIGNAL(sectionResized(int, int, int)), SLOT(SaveGeometry())); - connect(header_, SIGNAL(sectionMoved(int, int, int)), SLOT(SaveGeometry())); - connect(header_, SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), SLOT(SaveGeometry())); - connect(header_, SIGNAL(SectionVisibilityChanged(int, bool)), SLOT(SaveGeometry())); + connect(header_, SIGNAL(sectionResized(int, int, int)), SLOT(SetHeaderState())); + connect(header_, SIGNAL(sectionMoved(int, int, int)), SLOT(SetHeaderState())); + connect(header_, SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), SLOT(SetHeaderState())); + connect(header_, SIGNAL(SectionVisibilityChanged(int, bool)), SLOT(SetHeaderState())); connect(header_, SIGNAL(sectionResized(int, int, int)), SLOT(InvalidateCachedCurrentPixmap())); connect(header_, SIGNAL(sectionMoved(int, int, int)), SLOT(InvalidateCachedCurrentPixmap())); @@ -196,26 +202,17 @@ PlaylistView::PlaylistView(QWidget *parent) horizontalScrollBar()->installEventFilter(this); verticalScrollBar()->installEventFilter(this); - setAlternatingRowColors(true); - - setAttribute(Qt::WA_MacShowFocusRect, false); - -#ifdef Q_OS_MACOS - setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); -#endif // For fading connect(fade_animation_, SIGNAL(valueChanged(qreal)), SLOT(FadePreviousBackgroundImage(qreal))); fade_animation_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0 - initialized_ = true; - } PlaylistView::~PlaylistView() { - delete style_; + style_->deleteLater(); } -void PlaylistView::SetApplication(Application *app) { +void PlaylistView::Init(Application *app) { Q_ASSERT(app); app_ = app; @@ -263,28 +260,6 @@ void PlaylistView::SetItemDelegates() { } -void PlaylistView::SetPlaylist(Playlist *playlist) { - - if (playlist_) { - disconnect(playlist_, SIGNAL(MaybeAutoscroll(Playlist::AutoScroll)), this, SLOT(MaybeAutoscroll(Playlist::AutoScroll))); - disconnect(playlist_, SIGNAL(destroyed()), this, SLOT(PlaylistDestroyed())); - disconnect(playlist_, SIGNAL(QueueChanged()), this, SLOT(update())); - } - - playlist_ = playlist; - LoadGeometry(); - ReloadSettings(); - setFocus(); - read_only_settings_ = false; - JumpToLastPlayedTrack(); - - connect(playlist_, SIGNAL(RestoreFinished()), SLOT(JumpToLastPlayedTrack())); - connect(playlist_, SIGNAL(MaybeAutoscroll(Playlist::AutoScroll)), SLOT(MaybeAutoscroll(Playlist::AutoScroll))); - connect(playlist_, SIGNAL(destroyed()), SLOT(PlaylistDestroyed())); - connect(playlist_, SIGNAL(QueueChanged()), SLOT(update())); - -} - void PlaylistView::setModel(QAbstractItemModel *m) { if (model()) { @@ -301,44 +276,106 @@ void PlaylistView::setModel(QAbstractItemModel *m) { } -void PlaylistView::LoadGeometry() { +void PlaylistView::SetPlaylist(Playlist *playlist) { - if (!state_loaded_) { - QSettings s; - s.beginGroup(Playlist::kSettingsGroup); - state_ = s.value("state").toByteArray(); - state_loaded_ = true; - s.endGroup(); + if (playlist_) { + disconnect(playlist_, SIGNAL(MaybeAutoscroll(Playlist::AutoScroll)), this, SLOT(MaybeAutoscroll(Playlist::AutoScroll))); + disconnect(playlist_, SIGNAL(destroyed()), this, SLOT(PlaylistDestroyed())); + disconnect(playlist_, SIGNAL(QueueChanged()), this, SLOT(update())); } - if (!header_->RestoreState(state_)) { - // Maybe we're upgrading from a version that persisted the state with QHeaderView. - if (!header_->restoreState(state_)) { - header_->HideSection(Playlist::Column_AlbumArtist); - header_->HideSection(Playlist::Column_Performer); - header_->HideSection(Playlist::Column_Composer); - header_->HideSection(Playlist::Column_Year); - header_->HideSection(Playlist::Column_OriginalYear); - header_->HideSection(Playlist::Column_Disc); - header_->HideSection(Playlist::Column_Genre); - header_->HideSection(Playlist::Column_Filename); - header_->HideSection(Playlist::Column_BaseFilename); - header_->HideSection(Playlist::Column_Filesize); - header_->HideSection(Playlist::Column_DateCreated); - header_->HideSection(Playlist::Column_DateModified); - header_->HideSection(Playlist::Column_PlayCount); - header_->HideSection(Playlist::Column_SkipCount); - header_->HideSection(Playlist::Column_LastPlayed); - header_->HideSection(Playlist::Column_Comment); - header_->HideSection(Playlist::Column_Grouping); - header_->HideSection(Playlist::Column_Mood); + playlist_ = playlist; + RestoreHeaderState(); + setFocus(); + JumpToLastPlayedTrack(); + + connect(playlist_, SIGNAL(RestoreFinished()), SLOT(JumpToLastPlayedTrack())); + connect(playlist_, SIGNAL(MaybeAutoscroll(Playlist::AutoScroll)), SLOT(MaybeAutoscroll(Playlist::AutoScroll))); + connect(playlist_, SIGNAL(destroyed()), SLOT(PlaylistDestroyed())); + connect(playlist_, SIGNAL(QueueChanged()), SLOT(update())); + +} + +void PlaylistView::LoadHeaderState() { + + QSettings s; + s.beginGroup(Playlist::kSettingsGroup); + if (s.contains("state")) header_state_ = s.value("state").toByteArray(); + if (s.contains("column_alignments")) column_alignment_ = s.value("column_alignments").value(); + s.endGroup(); + + if (column_alignment_.isEmpty()) { + column_alignment_ = DefaultColumnAlignment(); + } + + header_state_loaded_ = true; + +} + +void PlaylistView::SetHeaderState() { + + if (!header_state_loaded_) return; + header_state_ = header_->SaveState(); + +} + +void PlaylistView::ResetHeaderState() { + + set_initial_header_layout_ = true; + header_state_ = header_->ResetState(); + RestoreHeaderState(); + +} + +void PlaylistView::RestoreHeaderState() { + + if (!header_state_loaded_) LoadHeaderState(); + + if (header_state_.isEmpty() || !header_->RestoreState(header_state_)) { + set_initial_header_layout_ = true; + } + + if (set_initial_header_layout_) { + + header_->HideSection(Playlist::Column_AlbumArtist); + header_->HideSection(Playlist::Column_Performer); + header_->HideSection(Playlist::Column_Composer); + header_->HideSection(Playlist::Column_Year); + header_->HideSection(Playlist::Column_OriginalYear); + header_->HideSection(Playlist::Column_Disc); + header_->HideSection(Playlist::Column_Genre); + header_->HideSection(Playlist::Column_Filename); + header_->HideSection(Playlist::Column_BaseFilename); + header_->HideSection(Playlist::Column_Filesize); + header_->HideSection(Playlist::Column_DateCreated); + header_->HideSection(Playlist::Column_DateModified); + header_->HideSection(Playlist::Column_PlayCount); + header_->HideSection(Playlist::Column_SkipCount); + header_->HideSection(Playlist::Column_LastPlayed); + header_->HideSection(Playlist::Column_Comment); + header_->HideSection(Playlist::Column_Grouping); + header_->HideSection(Playlist::Column_Mood); + + header_->moveSection(header_->visualIndex(Playlist::Column_Track), 0); + + header_->SetStretchEnabled(true); + + header_->SetColumnWidth(Playlist::Column_Track, 0.04); + header_->SetColumnWidth(Playlist::Column_Title, 0.26); + header_->SetColumnWidth(Playlist::Column_Artist, 0.20); + header_->SetColumnWidth(Playlist::Column_Album, 0.14); + header_->SetColumnWidth(Playlist::Column_Length, 0.03); + header_->SetColumnWidth(Playlist::Column_Samplerate, 0.07); + header_->SetColumnWidth(Playlist::Column_Bitdepth, 0.07); + header_->SetColumnWidth(Playlist::Column_Bitrate, 0.07); + header_->SetColumnWidth(Playlist::Column_Filetype, 0.06); + header_->SetColumnWidth(Playlist::Column_Source, 0.06); + + header_state_ = header_->SaveState(); + header_->RestoreState(header_state_); + + set_initial_header_layout_ = false; - header_->moveSection(header_->visualIndex(Playlist::Column_Track), 0); - setting_initial_header_layout_ = true; - } - else { - setting_initial_header_layout_ = true; - } } // Make sure at least one column is visible @@ -353,12 +390,9 @@ void PlaylistView::LoadGeometry() { header_->ShowSection(Playlist::Column_Title); } -} + header_state_restored_ = true; -void PlaylistView::SaveGeometry() { - - if (!initialized_ || !state_loaded_) return; - state_ = header_->SaveState(); + emit ColumnAlignmentChanged(column_alignment_); } @@ -805,11 +839,9 @@ void PlaylistView::JumpToLastPlayedTrack() { last_current_item_ = last_played; setCurrentIndex(last_current_item_); - currently_autoscrolling_ = true; - // Scroll to the item + currently_autoscrolling_ = true; scrollTo(last_played, QAbstractItemView::PositionAtCenter); - currently_autoscrolling_ = false; } @@ -1024,11 +1056,6 @@ void PlaylistView::ReloadSettings() { select_track_ = s.value("select_track", false).toBool(); s.endGroup(); - s.beginGroup(Playlist::kSettingsGroup); - bool stretch = s.value("stretch", true).toBool(); - column_alignment_ = s.value("column_alignments").value(); - s.endGroup(); - s.beginGroup(AppearanceSettingsPage::kSettingsGroup); QVariant background_image_type_var = s.value(AppearanceSettingsPage::kBackgroundImageType); QVariant background_image_position_var = s.value(AppearanceSettingsPage::kBackgroundImagePosition); @@ -1042,34 +1069,9 @@ void PlaylistView::ReloadSettings() { int opacity_level = s.value(AppearanceSettingsPage::kOpacityLevel, AppearanceSettingsPage::kDefaultOpacityLevel).toInt(); s.endGroup(); - if (setting_initial_header_layout_) { - - header_->SetStretchEnabled(stretch); - - header_->SetColumnWidth(Playlist::Column_Track, 0.02); - header_->SetColumnWidth(Playlist::Column_Title, 0.16); - header_->SetColumnWidth(Playlist::Column_Artist, 0.12); - header_->SetColumnWidth(Playlist::Column_Album, 0.12); - header_->SetColumnWidth(Playlist::Column_Length, 0.03); - header_->SetColumnWidth(Playlist::Column_Samplerate, 0.07); - header_->SetColumnWidth(Playlist::Column_Bitdepth, 0.07); - header_->SetColumnWidth(Playlist::Column_Bitrate, 0.07); - header_->SetColumnWidth(Playlist::Column_Filetype, 0.06); - header_->SetColumnWidth(Playlist::Column_Source, 0.06); - - setting_initial_header_layout_ = false; - - } - if (currently_glowing_ && glow_enabled_ && isVisible()) StartGlowing(); if (!glow_enabled_) StopGlowing(); - if (column_alignment_.isEmpty()) { - column_alignment_ = DefaultColumnAlignment(); - } - emit ColumnAlignmentChanged(column_alignment_); - - // Background: AppearanceSettingsPage::BackgroundImageType background_image_type(AppearanceSettingsPage::BackgroundImageType_Default); if (background_image_type_var.isValid()) { @@ -1144,7 +1146,7 @@ void PlaylistView::ReloadSettings() { void PlaylistView::SaveSettings() { - if (!initialized_ || read_only_settings_) return; + if (!header_state_loaded_) return; QSettings s; s.beginGroup(Playlist::kSettingsGroup); @@ -1156,9 +1158,10 @@ void PlaylistView::SaveSettings() { void PlaylistView::StretchChanged(const bool stretch) { - if (!initialized_) return; + if (!header_state_loaded_) return; + setHorizontalScrollBarPolicy(stretch ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded); - SaveGeometry(); + SetHeaderState(); } @@ -1354,19 +1357,3 @@ void PlaylistView::focusInEvent(QFocusEvent *event) { } } - -void PlaylistView::ResetColumns() { - - QSettings s; - s.beginGroup(Playlist::kSettingsGroup); - s.remove("state"); - s.endGroup(); - state_loaded_ = false; - read_only_settings_ = true; - setting_initial_header_layout_ = true; - ReloadSettings(); - LoadGeometry(); - read_only_settings_ = false; - SetPlaylist(playlist_); - -} diff --git a/src/playlist/playlistview.h b/src/playlist/playlistview.h index 2d1050e4c..c42a6ba44 100644 --- a/src/playlist/playlistview.h +++ b/src/playlist/playlistview.h @@ -98,7 +98,7 @@ class PlaylistView : public QTreeView { static ColumnAlignmentMap DefaultColumnAlignment(); - void SetApplication(Application *app); + void Init(Application *app); void SetItemDelegates(); void SetPlaylist(Playlist *playlist); void RemoveSelected(); @@ -109,14 +109,13 @@ class PlaylistView : public QTreeView { AppearanceSettingsPage::BackgroundImageType background_image_type() const { return background_image_type_; } Qt::Alignment column_alignment(int section) const; - void ResetColumns(); + void ResetHeaderState(); // QTreeView void setModel(QAbstractItemModel *model) override; public slots: void ReloadSettings(); - void SaveGeometry(); void SaveSettings(); void SetColumnAlignment(const int section, const Qt::Alignment alignment); void JumpToCurrentlyPlayingTrack(); @@ -163,6 +162,7 @@ class PlaylistView : public QTreeView { void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint) override; private slots: + void SetHeaderState(); void InhibitAutoscrollTimeout(); void MaybeAutoscroll(const Playlist::AutoScroll autoscroll); void InvalidateCachedCurrentPixmap(); @@ -179,7 +179,9 @@ class PlaylistView : public QTreeView { void AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResult result = AlbumCoverLoaderResult()); private: - void LoadGeometry(); + void LoadHeaderState(); + void RestoreHeaderState(); + void ReloadBarPixmaps(); QList LoadBarPixmap(const QString &filename); void UpdateCachedCurrentRowPixmap(QStyleOptionViewItem option, const QModelIndex &idx); @@ -219,11 +221,12 @@ class PlaylistView : public QTreeView { int blur_radius_; int opacity_level_; - bool initialized_; bool background_initialized_; - bool setting_initial_header_layout_; + bool set_initial_header_layout_; bool read_only_settings_; - bool state_loaded_; + bool header_state_loaded_; + bool header_state_restored_; + bool header_state_readonly_; QImage background_image_; QImage current_song_cover_art_; @@ -272,10 +275,9 @@ class PlaylistView : public QTreeView { int drop_indicator_row_; bool drag_over_; + QByteArray header_state_; ColumnAlignmentMap column_alignment_; - QByteArray state_; - Song song_playing_; }; diff --git a/src/widgets/stretchheaderview.cpp b/src/widgets/stretchheaderview.cpp index 4f6de2cee..0544f5c46 100644 --- a/src/widgets/stretchheaderview.cpp +++ b/src/widgets/stretchheaderview.cpp @@ -67,21 +67,21 @@ void StretchHeaderView::NormaliseWidths(const QList& sections) { if (!sections.isEmpty()) { selected_sum = 0.0; - for (int i=0 ; i& sections) { +void StretchHeaderView::UpdateWidths(const QList §ions) { if (!stretch_enabled_) return; @@ -116,7 +116,7 @@ void StretchHeaderView::HideSection(const int logical) { // Would this hide the last section? bool all_hidden = true; - for (int i=0 ; i 0) { all_hidden = false; break; @@ -134,6 +134,7 @@ void StretchHeaderView::HideSection(const int logical) { column_widths_[logical] = 0.0; NormaliseWidths(); UpdateWidths(); + } void StretchHeaderView::ShowSection(int logical) { @@ -145,7 +146,7 @@ void StretchHeaderView::ShowSection(int logical) { // How many sections are visible already? int visible_count = 0; - for (int i=0 ; i other_columns; - for (int i=0 ; i visual_indices; + QList pixel_widths; + for (int i = 0 ; i < count() ; ++i) { + pixel_widths << 10; + visual_indices << count(); + } + + s << stretch_enabled_; + s << pixel_widths; + s << visual_indices; + s << column_widths_; + s << int(Qt::AscendingOrder); + s << 0; + + RestoreState(ret); + + return ret; + +} diff --git a/src/widgets/stretchheaderview.h b/src/widgets/stretchheaderview.h index bd202bb32..1c7d0f55d 100644 --- a/src/widgets/stretchheaderview.h +++ b/src/widgets/stretchheaderview.h @@ -52,6 +52,7 @@ class StretchHeaderView : public QHeaderView { // Use these instead of QHeaderView::restoreState and QHeaderView::saveState to persist the proportional values directly and avoid floating point errors over time. bool RestoreState(const QByteArray &sdata); QByteArray SaveState() const; + QByteArray ResetState(); // Hides a section and resizes all other sections to fill the gap. Does nothing if you try to hide the last section. void HideSection(const int logical); @@ -85,7 +86,7 @@ class StretchHeaderView : public QHeaderView { private: // Scales column_widths_ values so the total is 1.0. - void NormaliseWidths(const QList& sections = QList()); + void NormaliseWidths(const QList §ions = QList()); // Resizes the actual columns to make them match the proportional values in column_widths_. void UpdateWidths(const QList& sections = QList());