Changeset View
Changeset View
Standalone View
Standalone View
wallpapers/image/slidefiltermodel.cpp
Show All 18 Lines | |||||
19 | #include "slidefiltermodel.h" | 19 | #include "slidefiltermodel.h" | ||
20 | 20 | | |||
21 | #include "backgroundlistmodel.h" | 21 | #include "backgroundlistmodel.h" | ||
22 | #include "slidemodel.h" | 22 | #include "slidemodel.h" | ||
23 | 23 | | |||
24 | #include <QRandomGenerator> | 24 | #include <QRandomGenerator> | ||
25 | #include <QFileInfo> | 25 | #include <QFileInfo> | ||
26 | 26 | | |||
27 | #include <algorithm> | ||||
28 | | ||||
27 | SlideFilterModel::SlideFilterModel(QObject* parent) | 29 | SlideFilterModel::SlideFilterModel(QObject* parent) | ||
28 | : QSortFilterProxyModel{parent} | 30 | : QSortFilterProxyModel{parent} | ||
29 | , m_SortingMode{Image::Random} | 31 | , m_SortingMode{Image::Random} | ||
30 | , m_usedInConfig{false} | 32 | , m_usedInConfig{false} | ||
31 | { | 33 | { | ||
32 | setSortCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); | 34 | setSortCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); | ||
33 | connect(this, &SlideFilterModel::usedInConfigChanged, this, &SlideFilterModel::invalidateFilter); | 35 | connect(this, &SlideFilterModel::usedInConfigChanged, this, &SlideFilterModel::invalidateFilter); | ||
34 | } | 36 | } | ||
35 | 37 | | |||
36 | bool SlideFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const | 38 | bool SlideFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const | ||
37 | { | 39 | { | ||
38 | auto index = sourceModel()->index(source_row, 0, source_parent); | 40 | auto index = sourceModel()->index(source_row, 0, source_parent); | ||
39 | return m_usedInConfig || index.data(BackgroundListModel::ToggleRole).toBool(); | 41 | return m_usedInConfig || index.data(BackgroundListModel::ToggleRole).toBool(); | ||
40 | } | 42 | } | ||
41 | 43 | | |||
44 | void SlideFilterModel::setSourceModel(QAbstractItemModel *sourceModel) | ||||
45 | { | ||||
46 | if (this->sourceModel()) { | ||||
47 | disconnect(this->sourceModel(), nullptr, this, nullptr); | ||||
48 | } | ||||
49 | QSortFilterProxyModel::setSourceModel(sourceModel); | ||||
50 | if (m_SortingMode == Image::Random && !m_usedInConfig) { | ||||
51 | buildRandomOrder(); | ||||
broulik: Perhaps only `invalidate` if order is actually set to random?
I am actually not sure we need… | |||||
Good point. No need to invalidate in the other cases. Maybe. It depends where images are added in the model? Maybe we would end up showing pictures again because the indexes have shifted? Or the new images are always shown at the end because they get appended? Either way I think that*'s not to bad if the order is set to Random. The result could also be the result of a random permutation. davidre: Good point. No need to invalidate in the other cases.
Maybe. It depends where images are added… | |||||
52 | } | ||||
53 | if(sourceModel) { | ||||
54 | connect(sourceModel, &QAbstractItemModel::rowsInserted, this, [this] { | ||||
55 | if (m_SortingMode != Image::Random || m_usedInConfig) { | ||||
56 | return; | ||||
57 | } | ||||
58 | const int old_count = m_randomOrder.size(); | ||||
59 | m_randomOrder.resize(this->sourceModel()->rowCount()); | ||||
60 | std::iota(m_randomOrder.begin() + old_count, m_randomOrder.end(), old_count); | ||||
61 | }); | ||||
62 | connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, [this] { | ||||
63 | if (m_SortingMode != Image::Random || m_usedInConfig) { | ||||
64 | return; | ||||
65 | } | ||||
66 | m_randomOrder.erase(std::remove_if(m_randomOrder.begin(), m_randomOrder.end(), [this] (const int v) { | ||||
67 | return v >= this->sourceModel()->rowCount(); | ||||
68 | }), m_randomOrder.end()); | ||||
69 | }); | ||||
70 | } | ||||
71 | } | ||||
72 | | ||||
42 | bool SlideFilterModel::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const | 73 | bool SlideFilterModel::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const | ||
43 | { | 74 | { | ||
44 | switch (m_SortingMode) { | 75 | switch (m_SortingMode) { | ||
45 | case Image::Random: | 76 | case Image::Random: | ||
46 | return (*QRandomGenerator::system())() % 2 == 0; | 77 | if (m_usedInConfig) { | ||
78 | return source_left.row() < source_right.row(); | ||||
79 | } | ||||
80 | return m_randomOrder.indexOf(source_left.row()) < m_randomOrder.indexOf(source_right.row()); | ||||
47 | case Image::Alphabetical: | 81 | case Image::Alphabetical: | ||
48 | return QSortFilterProxyModel::lessThan(source_left, source_right); | 82 | return QSortFilterProxyModel::lessThan(source_left, source_right); | ||
49 | case Image::AlphabeticalReversed: | 83 | case Image::AlphabeticalReversed: | ||
50 | return !QSortFilterProxyModel::lessThan(source_left, source_right); | 84 | return !QSortFilterProxyModel::lessThan(source_left, source_right); | ||
51 | case Image::Modified: // oldest first | 85 | case Image::Modified: // oldest first | ||
52 | { | 86 | { | ||
53 | QFileInfo f1(source_left.data(BackgroundListModel::PathRole).toUrl().toLocalFile()); | 87 | QFileInfo f1(source_left.data(BackgroundListModel::PathRole).toUrl().toLocalFile()); | ||
54 | QFileInfo f2(source_right.data(BackgroundListModel::PathRole).toUrl().toLocalFile()); | 88 | QFileInfo f2(source_right.data(BackgroundListModel::PathRole).toUrl().toLocalFile()); | ||
55 | return f1.lastModified() < f2.lastModified(); | 89 | return f1.lastModified() < f2.lastModified(); | ||
56 | } | 90 | } | ||
57 | case Image::ModifiedReversed: // newest first | 91 | case Image::ModifiedReversed: // newest first | ||
58 | { | 92 | { | ||
59 | QFileInfo f1(source_left.data(BackgroundListModel::PathRole).toUrl().toLocalFile()); | 93 | QFileInfo f1(source_left.data(BackgroundListModel::PathRole).toUrl().toLocalFile()); | ||
60 | QFileInfo f2(source_right.data(BackgroundListModel::PathRole).toUrl().toLocalFile()); | 94 | QFileInfo f2(source_right.data(BackgroundListModel::PathRole).toUrl().toLocalFile()); | ||
61 | return !(f1.lastModified() < f2.lastModified()); | 95 | return !(f1.lastModified() < f2.lastModified()); | ||
62 | } | 96 | } | ||
63 | } | 97 | } | ||
64 | Q_UNREACHABLE(); | 98 | Q_UNREACHABLE(); | ||
65 | } | 99 | } | ||
66 | 100 | | |||
67 | void SlideFilterModel::setSortingMode(Image::SlideshowMode mode) | 101 | void SlideFilterModel::setSortingMode(Image::SlideshowMode mode) | ||
68 | { | 102 | { | ||
69 | m_SortingMode = mode; | 103 | if (m_SortingMode == Image::Random && !m_usedInConfig) { | ||
70 | if (!(m_usedInConfig && mode == Image::Random)) { | 104 | buildRandomOrder(); | ||
105 | } | ||||
71 | QSortFilterProxyModel::invalidate(); | 106 | QSortFilterProxyModel::invalidate(); | ||
72 | } | 107 | } | ||
108 | | ||||
109 | void SlideFilterModel::invalidate() | ||||
110 | { | ||||
111 | if (m_SortingMode == Image::Random && !m_usedInConfig) { | ||||
112 | std::random_shuffle(m_randomOrder.begin(), m_randomOrder.end()); | ||||
113 | } | ||||
114 | QSortFilterProxyModel::invalidate(); | ||||
73 | } | 115 | } | ||
74 | 116 | | |||
75 | void SlideFilterModel::invalidateFilter() | 117 | void SlideFilterModel::invalidateFilter() | ||
76 | { | 118 | { | ||
77 | QSortFilterProxyModel::invalidateFilter(); | 119 | QSortFilterProxyModel::invalidateFilter(); | ||
78 | } | 120 | } | ||
79 | 121 | | |||
80 | int SlideFilterModel::indexOf(const QString& path) | 122 | int SlideFilterModel::indexOf(const QString& path) | ||
81 | { | 123 | { | ||
82 | auto sourceIndex = sourceModel()->index(static_cast<SlideModel*>(sourceModel())->indexOf(path), 0); | 124 | auto sourceIndex = sourceModel()->index(static_cast<SlideModel*>(sourceModel())->indexOf(path), 0); | ||
83 | return mapFromSource(sourceIndex).row(); | 125 | return mapFromSource(sourceIndex).row(); | ||
84 | } | 126 | } | ||
85 | 127 | | |||
86 | void SlideFilterModel::openContainingFolder(int rowIndex) | 128 | void SlideFilterModel::openContainingFolder(int rowIndex) | ||
87 | { | 129 | { | ||
88 | auto sourceIndex = mapToSource(index(rowIndex, 0)); | 130 | auto sourceIndex = mapToSource(index(rowIndex, 0)); | ||
89 | static_cast<SlideModel*>(sourceModel())->openContainingFolder(sourceIndex.row()); | 131 | static_cast<SlideModel*>(sourceModel())->openContainingFolder(sourceIndex.row()); | ||
90 | } | 132 | } | ||
133 | | ||||
134 | void SlideFilterModel::buildRandomOrder() | ||||
135 | { | ||||
136 | if (sourceModel()) { | ||||
broulik: Can `sourceModel()` be null here? | |||||
137 | m_randomOrder.resize(sourceModel()->rowCount()); | ||||
138 | std::iota(m_randomOrder.begin(), m_randomOrder.end(), 0); | ||||
139 | std::random_shuffle(m_randomOrder.begin(), m_randomOrder.end()); | ||||
140 | } | ||||
141 | } |
Perhaps only invalidate if order is actually set to random?
I am actually not sure we need to invalidate at all when inserting items, unless you want to shuffle every time that happens? Perhaps all we need to do is shrink/grow the random vector when new items are added?