Use PlaylistFilter directly

This commit is contained in:
Jonas Kvinge
2022-08-09 17:23:46 +02:00
parent 553d4cce93
commit acb6c0fc83
10 changed files with 81 additions and 78 deletions

View File

@@ -120,7 +120,7 @@ const qint64 Playlist::kMaxScrobblePointNsecs = 240LL * kNsecPerSec;
Playlist::Playlist(PlaylistBackend *backend, TaskManager *task_manager, CollectionBackend *collection, const int id, const QString &special_type, const bool favorite, QObject *parent)
: QAbstractListModel(parent),
is_loading_(false),
proxy_(new PlaylistFilter(this)),
filter_(new PlaylistFilter(this)),
queue_(new Queue(this, this)),
timer_save_(new QTimer(this)),
backend_(backend),
@@ -150,7 +150,7 @@ Playlist::Playlist(PlaylistBackend *backend, TaskManager *task_manager, Collecti
Restore();
proxy_->setSourceModel(this);
filter_->setSourceModel(this);
queue_->setSourceModel(this);
QObject::connect(queue_, &Queue::rowsAboutToBeRemoved, this, &Playlist::TracksAboutToBeDequeued);
@@ -491,7 +491,7 @@ void Playlist::ShuffleModeChanged(const PlaylistSequence::ShuffleMode mode) {
bool Playlist::FilterContainsVirtualIndex(const int i) const {
if (i < 0 || i >= virtual_items_.count()) return false;
return proxy_->filterAcceptsRow(virtual_items_[i], QModelIndex());
return filter_->filterAcceptsRow(virtual_items_[i], QModelIndex());
}
int Playlist::NextVirtualIndex(int i, const bool ignore_repeat_track) const {
@@ -2013,7 +2013,7 @@ void Playlist::set_sequence(PlaylistSequence *v) {
}
QSortFilterProxyModel *Playlist::proxy() const { return proxy_; }
PlaylistFilter *Playlist::filter() const { return filter_; }
SongList Playlist::GetAllSongs() const {

View File

@@ -49,7 +49,6 @@
#include "smartplaylists/playlistgenerator_fwd.h"
class QMimeData;
class QSortFilterProxyModel;
class QUndoStack;
class QTimer;
@@ -180,7 +179,7 @@ class Playlist : public QAbstractListModel {
void ScheduleSaveAsync();
// Accessors
QSortFilterProxyModel *proxy() const;
PlaylistFilter *filter() const;
Queue *queue() const { return queue_; }
int id() const { return id_; }
@@ -380,7 +379,7 @@ class Playlist : public QAbstractListModel {
private:
bool is_loading_;
PlaylistFilter *proxy_;
PlaylistFilter *filter_;
Queue *queue_;
QTimer *timer_save_;

View File

@@ -55,6 +55,7 @@
#include "playlistview.h"
#include "playlistcontainer.h"
#include "playlistmanager.h"
#include "playlistfilter.h"
#include "playlistparsers/playlistparser.h"
#include "ui_playlistcontainer.h"
#include "widgets/qsearchfield.h"
@@ -120,9 +121,9 @@ PlaylistContainer::PlaylistContainer(QWidget *parent)
QObject::connect(filter_timer_, &QTimer::timeout, this, &PlaylistContainer::UpdateFilter);
// Replace playlist search filter with native search box.
QObject::connect(ui_->filter, &QSearchField::textChanged, this, &PlaylistContainer::MaybeUpdateFilter);
QObject::connect(ui_->search_field, &QSearchField::textChanged, this, &PlaylistContainer::MaybeUpdateFilter);
QObject::connect(ui_->playlist, &PlaylistView::FocusOnFilterSignal, this, &PlaylistContainer::FocusOnFilter);
ui_->filter->installEventFilter(this);
ui_->search_field->installEventFilter(this);
ReloadSettings();
@@ -177,10 +178,10 @@ void PlaylistContainer::SetViewModel(Playlist *playlist, const int scroll_positi
if (view()->selectionModel()) {
QObject::disconnect(view()->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PlaylistContainer::SelectionChanged);
}
if (playlist_ && playlist_->proxy()) {
QObject::disconnect(playlist_->proxy(), &QSortFilterProxyModel::modelReset, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::disconnect(playlist_->proxy(), &QSortFilterProxyModel::rowsInserted, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::disconnect(playlist_->proxy(), &QSortFilterProxyModel::rowsRemoved, this, &PlaylistContainer::UpdateNoMatchesLabel);
if (playlist_ && playlist_->filter()) {
QObject::disconnect(playlist_->filter(), &QSortFilterProxyModel::modelReset, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::disconnect(playlist_->filter(), &QSortFilterProxyModel::rowsInserted, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::disconnect(playlist_->filter(), &QSortFilterProxyModel::rowsRemoved, this, &PlaylistContainer::UpdateNoMatchesLabel);
}
if (playlist_) {
QObject::disconnect(playlist_, &Playlist::modelReset, this, &PlaylistContainer::UpdateNoMatchesLabel);
@@ -192,7 +193,7 @@ void PlaylistContainer::SetViewModel(Playlist *playlist, const int scroll_positi
// Set the view
playlist->IgnoreSorting(true);
view()->setModel(playlist->proxy());
view()->setModel(playlist->filter());
view()->SetPlaylist(playlist);
view()->selectionModel()->select(manager_->current_selection(), QItemSelectionModel::ClearAndSelect);
if (scroll_position != 0) view()->verticalScrollBar()->setValue(scroll_position);
@@ -202,16 +203,12 @@ void PlaylistContainer::SetViewModel(Playlist *playlist, const int scroll_positi
emit ViewSelectionModelChanged();
// Update filter
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
ui_->filter->setText(playlist->proxy()->filterRegularExpression().pattern().remove('\\'));
#else
ui_->filter->setText(playlist->proxy()->filterRegExp().pattern());
#endif
ui_->search_field->setText(playlist->filter()->filter_text());
// Update the no matches label
QObject::connect(playlist_->proxy(), &QSortFilterProxyModel::modelReset, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::connect(playlist_->proxy(), &QSortFilterProxyModel::rowsInserted, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::connect(playlist_->proxy(), &QSortFilterProxyModel::rowsRemoved, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::connect(playlist_->filter(), &QSortFilterProxyModel::modelReset, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::connect(playlist_->filter(), &QSortFilterProxyModel::rowsInserted, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::connect(playlist_->filter(), &QSortFilterProxyModel::rowsRemoved, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::connect(playlist_, &Playlist::modelReset, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::connect(playlist_, &Playlist::rowsInserted, this, &PlaylistContainer::UpdateNoMatchesLabel);
QObject::connect(playlist_, &Playlist::rowsRemoved, this, &PlaylistContainer::UpdateNoMatchesLabel);
@@ -252,7 +249,7 @@ void PlaylistContainer::ReloadSettings() {
ui_->clear->setIconSize(QSize(iconsize, iconsize));
ui_->undo->setIconSize(QSize(iconsize, iconsize));
ui_->redo->setIconSize(QSize(iconsize, iconsize));
ui_->filter->setIconSize(iconsize);
ui_->search_field->setIconSize(iconsize);
bool playlist_clear = settings_.value("playlist_clear", true).toBool();
if (playlist_clear) {
@@ -265,16 +262,16 @@ void PlaylistContainer::ReloadSettings() {
bool show_toolbar = settings_.value("show_toolbar", true).toBool();
ui_->toolbar->setVisible(show_toolbar);
if (!show_toolbar) ui_->filter->clear();
if (!show_toolbar) ui_->search_field->clear();
}
bool PlaylistContainer::SearchFieldHasFocus() const {
return ui_->filter->hasFocus();
return ui_->search_field->hasFocus();
}
void PlaylistContainer::FocusSearchField() {
if (ui_->toolbar->isVisible()) ui_->filter->setFocus();
if (ui_->toolbar->isVisible()) ui_->search_field->setFocus();
}
void PlaylistContainer::ActivePlaying() {
@@ -409,7 +406,7 @@ void PlaylistContainer::SetTabBarHeight(const int height) {
void PlaylistContainer::MaybeUpdateFilter() {
// delaying the filter update on small playlists is undesirable and an empty filter applies very quickly, too
if (manager_->current()->rowCount() < kFilterDelayPlaylistSizeThreshold || ui_->filter->text().isEmpty()) {
if (manager_->current()->rowCount() < kFilterDelayPlaylistSizeThreshold || ui_->search_field->text().isEmpty()) {
UpdateFilter();
}
else {
@@ -420,7 +417,7 @@ void PlaylistContainer::MaybeUpdateFilter() {
void PlaylistContainer::UpdateFilter() {
manager_->current()->proxy()->setFilterFixedString(ui_->filter->text());
manager_->current()->filter()->SetFilterText(ui_->search_field->text());
ui_->playlist->JumpToCurrentlyPlayingTrack();
UpdateNoMatchesLabel();
@@ -431,7 +428,7 @@ void PlaylistContainer::UpdateNoMatchesLabel() {
Playlist *playlist = manager_->current();
const bool has_rows = playlist->rowCount() != 0;
const bool has_results = playlist->proxy()->rowCount() != 0;
const bool has_results = playlist->filter()->rowCount() != 0;
QString text;
if (has_rows && !has_results) {
@@ -457,15 +454,15 @@ void PlaylistContainer::resizeEvent(QResizeEvent *e) {
void PlaylistContainer::FocusOnFilter(QKeyEvent *event) {
if (ui_->toolbar->isVisible()) {
ui_->filter->setFocus();
ui_->search_field->setFocus();
switch (event->key()) {
case Qt::Key_Backspace:
break;
case Qt::Key_Escape:
ui_->filter->clear();
ui_->search_field->clear();
break;
default:
ui_->filter->setText(ui_->filter->text() + event->text());
ui_->search_field->setText(ui_->search_field->text() + event->text());
break;
}
}
@@ -494,7 +491,7 @@ void PlaylistContainer::SelectionChanged() {
bool PlaylistContainer::eventFilter(QObject *objectWatched, QEvent *event) {
if (objectWatched == ui_->filter) {
if (objectWatched == ui_->search_field) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent *e = static_cast<QKeyEvent*>(event);
switch (e->key()) {
@@ -508,7 +505,7 @@ bool PlaylistContainer::eventFilter(QObject *objectWatched, QEvent *event) {
QApplication::sendEvent(ui_->playlist, event);
return true;
case Qt::Key_Escape:
ui_->filter->clear();
ui_->search_field->clear();
return true;
default:
break;

View File

@@ -143,7 +143,7 @@
</widget>
</item>
<item>
<widget class="QSearchField" name="filter" native="true"/>
<widget class="QSearchField" name="search_field" native="true"/>
</item>
</layout>
</widget>

View File

@@ -23,7 +23,6 @@
#include <QObject>
#include <QString>
#include <QRegularExpression>
#include <QAbstractItemModel>
#include <QSortFilterProxyModel>
@@ -66,6 +65,7 @@ PlaylistFilter::PlaylistFilter(QObject *parent)
<< Playlist::Column_Samplerate
<< Playlist::Column_Bitdepth
<< Playlist::Column_Bitrate;
}
PlaylistFilter::~PlaylistFilter() = default;
@@ -78,19 +78,13 @@ void PlaylistFilter::sort(int column, Qt::SortOrder order) {
bool PlaylistFilter::filterAcceptsRow(int row, const QModelIndex &parent) const {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QString filter = filterRegularExpression().pattern().remove('\\');
size_t hash = qHash(filter_text_);
#else
QString filter = filterRegExp().pattern();
#endif
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
size_t hash = qHash(filter);
#else
uint hash = qHash(filter);
uint hash = qHash(filter_text_);
#endif
if (hash != query_hash_) {
// Parse the query
FilterParser p(filter, column_names_, numerical_columns_);
FilterParser p(filter_text_, column_names_, numerical_columns_);
filter_tree_.reset(p.parse());
query_hash_ = hash;
@@ -100,3 +94,10 @@ bool PlaylistFilter::filterAcceptsRow(int row, const QModelIndex &parent) const
return filter_tree_->accept(row, parent, sourceModel());
}
void PlaylistFilter::SetFilterText(const QString &filter_text) {
filter_text_ = filter_text;
setFilterFixedString(filter_text);
}

View File

@@ -48,6 +48,10 @@ class PlaylistFilter : public QSortFilterProxyModel {
// public so Playlist::NextVirtualIndex and friends can get at it
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
void SetFilterText(const QString &filter_text);
QString filter_text() const { return filter_text_; }
private:
// Mutable because they're modified from filterAcceptsRow() const
mutable QScopedPointer<FilterTree> filter_tree_;
@@ -59,6 +63,7 @@ class PlaylistFilter : public QSortFilterProxyModel {
QMap<QString, int> column_names_;
QSet<int> numerical_columns_;
QString filter_text_;
};
#endif // PLAYLISTFILTER_H

View File

@@ -29,7 +29,6 @@
#include <QWidget>
#include <QAbstractItemView>
#include <QItemSelectionModel>
#include <QSortFilterProxyModel>
#include <QTreeView>
#include <QHeaderView>
#include <QByteArray>
@@ -75,6 +74,7 @@
#include "playlistdelegates.h"
#include "playlistheader.h"
#include "playlistview.h"
#include "playlistfilter.h"
#include "covermanager/currentalbumcoverloader.h"
#include "covermanager/albumcoverloaderresult.h"
#include "settings/appearancesettingspage.h"
@@ -903,7 +903,7 @@ void PlaylistView::mousePressEvent(QMouseEvent *event) {
QModelIndexList src_index_list;
for (const QModelIndex &i : selectedIndexes()) {
if (i.data(Playlist::Role_CanSetRating).toBool()) {
src_index_list << playlist_->proxy()->mapToSource(i);
src_index_list << playlist_->filter()->mapToSource(i);
}
}
if (!src_index_list.isEmpty()) {
@@ -912,7 +912,7 @@ void PlaylistView::mousePressEvent(QMouseEvent *event) {
}
else {
// Update only this item rating
playlist_->RateSong(playlist_->proxy()->mapToSource(idx), new_rating);
playlist_->RateSong(playlist_->filter()->mapToSource(idx), new_rating);
}
}
break;
@@ -965,7 +965,7 @@ void PlaylistView::JumpToCurrentlyPlayingTrack() {
if (playlist_->current_row() == -1) return;
QModelIndex current = playlist_->proxy()->mapFromSource(playlist_->index(playlist_->current_row(), 0));
QModelIndex current = playlist_->filter()->mapFromSource(playlist_->index(playlist_->current_row(), 0));
if (!current.isValid()) return;
if (visibleRegion().boundingRect().contains(visualRect(current))) return;
@@ -986,7 +986,7 @@ void PlaylistView::JumpToLastPlayedTrack() {
if (playlist_->last_played_row() == -1) return;
QModelIndex last_played = playlist_->proxy()->mapFromSource(playlist_->index(playlist_->last_played_row(), 0));
QModelIndex last_played = playlist_->filter()->mapFromSource(playlist_->index(playlist_->last_played_row(), 0));
if (!last_played.isValid()) return;
// Select last played song