1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
From 9d162207ef01c5972e4bb718d390c494f0ad0241 Mon Sep 17 00:00:00 2001
From: John Lindgren <john@jlindgren.net>
Date: Tue, 4 Sep 2018 23:39:00 -0400
Subject: [PATCH] qtui: Fix slow searching on large playlists. Closes: #819.
---
src/qtui/playlist-qt.cc | 58 +++++++++++++++++++++++++++++------------
src/qtui/playlist-qt.h | 1 +
2 files changed, 42 insertions(+), 17 deletions(-)
diff --git a/src/qtui/playlist-qt.cc b/src/qtui/playlist-qt.cc
index 28c480ead..750d87c37 100644
--- a/src/qtui/playlist-qt.cc
+++ b/src/qtui/playlist-qt.cc
@@ -89,6 +89,31 @@ int PlaylistWidget::indexToRow (const QModelIndex & index)
return proxyModel->mapToSource (index).row ();
}
+QModelIndex PlaylistWidget::visibleIndexNear (int row)
+{
+ QModelIndex index = rowToIndex (row);
+ if (index.isValid ())
+ return index;
+
+ int n_entries = m_playlist.n_entries ();
+
+ for (int r = row + 1; r < n_entries; r ++)
+ {
+ index = rowToIndex (r);
+ if (index.isValid ())
+ return index;
+ }
+
+ for (int r = row - 1; r >= 0; r --)
+ {
+ index = rowToIndex (r);
+ if (index.isValid ())
+ return index;
+ }
+
+ return index;
+}
+
void PlaylistWidget::contextMenuEvent (QContextMenuEvent * event)
{
if (contextMenu)
@@ -379,33 +404,32 @@ void PlaylistWidget::playCurrentIndex ()
void PlaylistWidget::setFilter (const char * text)
{
+ // Save the current focus before filtering
+ int focus = m_playlist.get_focus ();
+
+ // Empty the model before updating the filter. This prevents Qt from
+ // performing a series of "rows added" or "rows deleted" updates, which can
+ // be very slow (worst case O(N^2) complexity) on a large playlist.
+ model->entriesRemoved (0, model->rowCount ());
+
+ // Update the filter
proxyModel->setFilter (text);
- int focus = m_playlist.get_focus ();
- QModelIndex index;
+ // Repopulate the model
+ model->entriesAdded (0, m_playlist.n_entries ());
- // If there was a valid focus before filtering, Qt updates it for us via
- // currentChanged(). If not, we will set focus on the first visible row.
+ // If the previously focused row is no longer visible with the new filter,
+ // try to find a nearby one that is, and focus it.
+ auto index = visibleIndexNear (focus);
- if (focus >= 0)
- index = rowToIndex (focus);
- else
+ if (index.isValid ())
{
- if (! proxyModel->rowCount ())
- return;
-
- index = proxyModel->index (0, 0);
focus = indexToRow (index);
m_playlist.set_focus (focus);
- }
-
- if (! m_playlist.entry_selected (focus))
- {
m_playlist.select_all (false);
m_playlist.select_entry (focus, true);
+ scrollTo (index);
}
-
- scrollTo (index);
}
void PlaylistWidget::setFirstVisibleColumn (int col)
diff --git a/src/qtui/playlist-qt.h b/src/qtui/playlist-qt.h
index a2894323c..df44205af 100644
--- a/src/qtui/playlist-qt.h
+++ b/src/qtui/playlist-qt.h
@@ -66,6 +66,7 @@ class PlaylistWidget : public QTreeView
QModelIndex rowToIndex (int row);
int indexToRow (const QModelIndex & index);
+ QModelIndex visibleIndexNear (int row);
void getSelectedRanges (int rowsBefore, int rowsAfter,
QItemSelection & selected, QItemSelection & deselected);
|