Merge lp:~saviq/ubuntu/saucy/qtbase-opensource-src/add-proxymodel-patch into lp:ubuntu/saucy/qtbase-opensource-src
- Saucy (13.10)
- add-proxymodel-patch
- Merge into saucy
Proposed by
Michał Sawicz
Status: | Merged |
---|---|
Merge reported by: | Sebastien Bacher |
Merged at revision: | not available |
Proposed branch: | lp:~saviq/ubuntu/saucy/qtbase-opensource-src/add-proxymodel-patch |
Merge into: | lp:ubuntu/saucy/qtbase-opensource-src |
Diff against target: |
6723 lines (+6654/-2) 7 files modified
.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/src/corelib/itemmodels/qsortfilterproxymodel.cpp (+2767/-0) .pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp (+3640/-0) .pc/applied-patches (+1/-0) debian/patches/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch (+145/-0) debian/patches/series (+1/-0) src/corelib/itemmodels/qsortfilterproxymodel.cpp (+5/-2) tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp (+95/-0) |
To merge this branch: | bzr merge lp:~saviq/ubuntu/saucy/qtbase-opensource-src/add-proxymodel-patch |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+189028@code.launchpad.net |
Commit message
Add QSortFilterProx
Qt code review at https:/
Description of the change
A fix from:
https:/
Problem: reordering categories in dash breaks.
To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch' | |||
2 | === added directory '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/src' | |||
3 | === added directory '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/src/corelib' | |||
4 | === added directory '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/src/corelib/itemmodels' | |||
5 | === added file '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/src/corelib/itemmodels/qsortfilterproxymodel.cpp' | |||
6 | --- .pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/src/corelib/itemmodels/qsortfilterproxymodel.cpp 1970-01-01 00:00:00 +0000 | |||
7 | +++ .pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/src/corelib/itemmodels/qsortfilterproxymodel.cpp 2013-10-03 10:06:38 +0000 | |||
8 | @@ -0,0 +1,2767 @@ | |||
9 | 1 | /**************************************************************************** | ||
10 | 2 | ** | ||
11 | 3 | ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). | ||
12 | 4 | ** Contact: http://www.qt-project.org/legal | ||
13 | 5 | ** | ||
14 | 6 | ** This file is part of the QtGui module of the Qt Toolkit. | ||
15 | 7 | ** | ||
16 | 8 | ** $QT_BEGIN_LICENSE:LGPL$ | ||
17 | 9 | ** Commercial License Usage | ||
18 | 10 | ** Licensees holding valid commercial Qt licenses may use this file in | ||
19 | 11 | ** accordance with the commercial license agreement provided with the | ||
20 | 12 | ** Software or, alternatively, in accordance with the terms contained in | ||
21 | 13 | ** a written agreement between you and Digia. For licensing terms and | ||
22 | 14 | ** conditions see http://qt.digia.com/licensing. For further information | ||
23 | 15 | ** use the contact form at http://qt.digia.com/contact-us. | ||
24 | 16 | ** | ||
25 | 17 | ** GNU Lesser General Public License Usage | ||
26 | 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | ||
27 | 19 | ** General Public License version 2.1 as published by the Free Software | ||
28 | 20 | ** Foundation and appearing in the file LICENSE.LGPL included in the | ||
29 | 21 | ** packaging of this file. Please review the following information to | ||
30 | 22 | ** ensure the GNU Lesser General Public License version 2.1 requirements | ||
31 | 23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | ||
32 | 24 | ** | ||
33 | 25 | ** In addition, as a special exception, Digia gives you certain additional | ||
34 | 26 | ** rights. These rights are described in the Digia Qt LGPL Exception | ||
35 | 27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | ||
36 | 28 | ** | ||
37 | 29 | ** GNU General Public License Usage | ||
38 | 30 | ** Alternatively, this file may be used under the terms of the GNU | ||
39 | 31 | ** General Public License version 3.0 as published by the Free Software | ||
40 | 32 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
41 | 33 | ** packaging of this file. Please review the following information to | ||
42 | 34 | ** ensure the GNU General Public License version 3.0 requirements will be | ||
43 | 35 | ** met: http://www.gnu.org/copyleft/gpl.html. | ||
44 | 36 | ** | ||
45 | 37 | ** | ||
46 | 38 | ** $QT_END_LICENSE$ | ||
47 | 39 | ** | ||
48 | 40 | ****************************************************************************/ | ||
49 | 41 | |||
50 | 42 | #include "qsortfilterproxymodel.h" | ||
51 | 43 | |||
52 | 44 | #ifndef QT_NO_SORTFILTERPROXYMODEL | ||
53 | 45 | |||
54 | 46 | #include "qitemselectionmodel.h" | ||
55 | 47 | #include <qsize.h> | ||
56 | 48 | #include <qdebug.h> | ||
57 | 49 | #include <qdatetime.h> | ||
58 | 50 | #include <qpair.h> | ||
59 | 51 | #include <qstringlist.h> | ||
60 | 52 | #include <private/qabstractitemmodel_p.h> | ||
61 | 53 | #include <private/qabstractproxymodel_p.h> | ||
62 | 54 | |||
63 | 55 | #include <algorithm> | ||
64 | 56 | |||
65 | 57 | QT_BEGIN_NAMESPACE | ||
66 | 58 | |||
67 | 59 | typedef QList<QPair<QModelIndex, QPersistentModelIndex> > QModelIndexPairList; | ||
68 | 60 | |||
69 | 61 | static inline QSet<int> qVectorToSet(const QVector<int> &vector) | ||
70 | 62 | { | ||
71 | 63 | QSet<int> set; | ||
72 | 64 | set.reserve(vector.size()); | ||
73 | 65 | for(int i=0; i < vector.size(); ++i) | ||
74 | 66 | set << vector.at(i); | ||
75 | 67 | return set; | ||
76 | 68 | } | ||
77 | 69 | |||
78 | 70 | class QSortFilterProxyModelLessThan | ||
79 | 71 | { | ||
80 | 72 | public: | ||
81 | 73 | inline QSortFilterProxyModelLessThan(int column, const QModelIndex &parent, | ||
82 | 74 | const QAbstractItemModel *source, | ||
83 | 75 | const QSortFilterProxyModel *proxy) | ||
84 | 76 | : sort_column(column), source_parent(parent), source_model(source), proxy_model(proxy) {} | ||
85 | 77 | |||
86 | 78 | inline bool operator()(int r1, int r2) const | ||
87 | 79 | { | ||
88 | 80 | QModelIndex i1 = source_model->index(r1, sort_column, source_parent); | ||
89 | 81 | QModelIndex i2 = source_model->index(r2, sort_column, source_parent); | ||
90 | 82 | return proxy_model->lessThan(i1, i2); | ||
91 | 83 | } | ||
92 | 84 | |||
93 | 85 | private: | ||
94 | 86 | int sort_column; | ||
95 | 87 | QModelIndex source_parent; | ||
96 | 88 | const QAbstractItemModel *source_model; | ||
97 | 89 | const QSortFilterProxyModel *proxy_model; | ||
98 | 90 | }; | ||
99 | 91 | |||
100 | 92 | class QSortFilterProxyModelGreaterThan | ||
101 | 93 | { | ||
102 | 94 | public: | ||
103 | 95 | inline QSortFilterProxyModelGreaterThan(int column, const QModelIndex &parent, | ||
104 | 96 | const QAbstractItemModel *source, | ||
105 | 97 | const QSortFilterProxyModel *proxy) | ||
106 | 98 | : sort_column(column), source_parent(parent), | ||
107 | 99 | source_model(source), proxy_model(proxy) {} | ||
108 | 100 | |||
109 | 101 | inline bool operator()(int r1, int r2) const | ||
110 | 102 | { | ||
111 | 103 | QModelIndex i1 = source_model->index(r1, sort_column, source_parent); | ||
112 | 104 | QModelIndex i2 = source_model->index(r2, sort_column, source_parent); | ||
113 | 105 | return proxy_model->lessThan(i2, i1); | ||
114 | 106 | } | ||
115 | 107 | |||
116 | 108 | private: | ||
117 | 109 | int sort_column; | ||
118 | 110 | QModelIndex source_parent; | ||
119 | 111 | const QAbstractItemModel *source_model; | ||
120 | 112 | const QSortFilterProxyModel *proxy_model; | ||
121 | 113 | }; | ||
122 | 114 | |||
123 | 115 | |||
124 | 116 | //this struct is used to store what are the rows that are removed | ||
125 | 117 | //between a call to rowsAboutToBeRemoved and rowsRemoved | ||
126 | 118 | //it avoids readding rows to the mapping that are currently being removed | ||
127 | 119 | struct QRowsRemoval | ||
128 | 120 | { | ||
129 | 121 | QRowsRemoval(const QModelIndex &parent_source, int start, int end) : parent_source(parent_source), start(start), end(end) | ||
130 | 122 | { | ||
131 | 123 | } | ||
132 | 124 | |||
133 | 125 | QRowsRemoval() : start(-1), end(-1) | ||
134 | 126 | { | ||
135 | 127 | } | ||
136 | 128 | |||
137 | 129 | bool contains(QModelIndex parent, int row) | ||
138 | 130 | { | ||
139 | 131 | do { | ||
140 | 132 | if (parent == parent_source) | ||
141 | 133 | return row >= start && row <= end; | ||
142 | 134 | row = parent.row(); | ||
143 | 135 | parent = parent.parent(); | ||
144 | 136 | } while (row >= 0); | ||
145 | 137 | return false; | ||
146 | 138 | } | ||
147 | 139 | private: | ||
148 | 140 | QModelIndex parent_source; | ||
149 | 141 | int start; | ||
150 | 142 | int end; | ||
151 | 143 | }; | ||
152 | 144 | |||
153 | 145 | class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate | ||
154 | 146 | { | ||
155 | 147 | Q_DECLARE_PUBLIC(QSortFilterProxyModel) | ||
156 | 148 | |||
157 | 149 | public: | ||
158 | 150 | struct Mapping { | ||
159 | 151 | QVector<int> source_rows; | ||
160 | 152 | QVector<int> source_columns; | ||
161 | 153 | QVector<int> proxy_rows; | ||
162 | 154 | QVector<int> proxy_columns; | ||
163 | 155 | QVector<QModelIndex> mapped_children; | ||
164 | 156 | QHash<QModelIndex, Mapping *>::const_iterator map_iter; | ||
165 | 157 | }; | ||
166 | 158 | |||
167 | 159 | mutable QHash<QModelIndex, Mapping*> source_index_mapping; | ||
168 | 160 | |||
169 | 161 | int source_sort_column; | ||
170 | 162 | int proxy_sort_column; | ||
171 | 163 | Qt::SortOrder sort_order; | ||
172 | 164 | Qt::CaseSensitivity sort_casesensitivity; | ||
173 | 165 | int sort_role; | ||
174 | 166 | bool sort_localeaware; | ||
175 | 167 | |||
176 | 168 | int filter_column; | ||
177 | 169 | QRegExp filter_regexp; | ||
178 | 170 | int filter_role; | ||
179 | 171 | |||
180 | 172 | bool dynamic_sortfilter; | ||
181 | 173 | QRowsRemoval itemsBeingRemoved; | ||
182 | 174 | |||
183 | 175 | QModelIndexPairList saved_persistent_indexes; | ||
184 | 176 | |||
185 | 177 | QHash<QModelIndex, Mapping *>::const_iterator create_mapping( | ||
186 | 178 | const QModelIndex &source_parent) const; | ||
187 | 179 | QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const; | ||
188 | 180 | QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const; | ||
189 | 181 | bool can_create_mapping(const QModelIndex &source_parent) const; | ||
190 | 182 | |||
191 | 183 | void remove_from_mapping(const QModelIndex &source_parent); | ||
192 | 184 | |||
193 | 185 | inline QHash<QModelIndex, Mapping *>::const_iterator index_to_iterator( | ||
194 | 186 | const QModelIndex &proxy_index) const | ||
195 | 187 | { | ||
196 | 188 | Q_ASSERT(proxy_index.isValid()); | ||
197 | 189 | Q_ASSERT(proxy_index.model() == q_func()); | ||
198 | 190 | const void *p = proxy_index.internalPointer(); | ||
199 | 191 | Q_ASSERT(p); | ||
200 | 192 | QHash<QModelIndex, Mapping *>::const_iterator it = | ||
201 | 193 | static_cast<const Mapping*>(p)->map_iter; | ||
202 | 194 | Q_ASSERT(it != source_index_mapping.constEnd()); | ||
203 | 195 | Q_ASSERT(it.value()); | ||
204 | 196 | return it; | ||
205 | 197 | } | ||
206 | 198 | |||
207 | 199 | inline QModelIndex create_index(int row, int column, | ||
208 | 200 | QHash<QModelIndex, Mapping*>::const_iterator it) const | ||
209 | 201 | { | ||
210 | 202 | return q_func()->createIndex(row, column, *it); | ||
211 | 203 | } | ||
212 | 204 | |||
213 | 205 | void _q_sourceDataChanged(const QModelIndex &source_top_left, | ||
214 | 206 | const QModelIndex &source_bottom_right); | ||
215 | 207 | void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end); | ||
216 | 208 | |||
217 | 209 | void _q_sourceAboutToBeReset(); | ||
218 | 210 | void _q_sourceReset(); | ||
219 | 211 | |||
220 | 212 | void _q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint); | ||
221 | 213 | void _q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint); | ||
222 | 214 | |||
223 | 215 | void _q_sourceRowsAboutToBeInserted(const QModelIndex &source_parent, | ||
224 | 216 | int start, int end); | ||
225 | 217 | void _q_sourceRowsInserted(const QModelIndex &source_parent, | ||
226 | 218 | int start, int end); | ||
227 | 219 | void _q_sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, | ||
228 | 220 | int start, int end); | ||
229 | 221 | void _q_sourceRowsRemoved(const QModelIndex &source_parent, | ||
230 | 222 | int start, int end); | ||
231 | 223 | void _q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, | ||
232 | 224 | int sourceStart, int sourceEnd, | ||
233 | 225 | const QModelIndex &destParent, int dest); | ||
234 | 226 | void _q_sourceRowsMoved(const QModelIndex &sourceParent, | ||
235 | 227 | int sourceStart, int sourceEnd, | ||
236 | 228 | const QModelIndex &destParent, int dest); | ||
237 | 229 | void _q_sourceColumnsAboutToBeInserted(const QModelIndex &source_parent, | ||
238 | 230 | int start, int end); | ||
239 | 231 | void _q_sourceColumnsInserted(const QModelIndex &source_parent, | ||
240 | 232 | int start, int end); | ||
241 | 233 | void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &source_parent, | ||
242 | 234 | int start, int end); | ||
243 | 235 | void _q_sourceColumnsRemoved(const QModelIndex &source_parent, | ||
244 | 236 | int start, int end); | ||
245 | 237 | void _q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, | ||
246 | 238 | int sourceStart, int sourceEnd, | ||
247 | 239 | const QModelIndex &destParent, int dest); | ||
248 | 240 | void _q_sourceColumnsMoved(const QModelIndex &sourceParent, | ||
249 | 241 | int sourceStart, int sourceEnd, | ||
250 | 242 | const QModelIndex &destParent, int dest); | ||
251 | 243 | |||
252 | 244 | void _q_clearMapping(); | ||
253 | 245 | |||
254 | 246 | void sort(); | ||
255 | 247 | bool update_source_sort_column(); | ||
256 | 248 | void sort_source_rows(QVector<int> &source_rows, | ||
257 | 249 | const QModelIndex &source_parent) const; | ||
258 | 250 | QVector<QPair<int, QVector<int > > > proxy_intervals_for_source_items_to_add( | ||
259 | 251 | const QVector<int> &proxy_to_source, const QVector<int> &source_items, | ||
260 | 252 | const QModelIndex &source_parent, Qt::Orientation orient) const; | ||
261 | 253 | QVector<QPair<int, int > > proxy_intervals_for_source_items( | ||
262 | 254 | const QVector<int> &source_to_proxy, const QVector<int> &source_items) const; | ||
263 | 255 | void insert_source_items( | ||
264 | 256 | QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, | ||
265 | 257 | const QVector<int> &source_items, const QModelIndex &source_parent, | ||
266 | 258 | Qt::Orientation orient, bool emit_signal = true); | ||
267 | 259 | void remove_source_items( | ||
268 | 260 | QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, | ||
269 | 261 | const QVector<int> &source_items, const QModelIndex &source_parent, | ||
270 | 262 | Qt::Orientation orient, bool emit_signal = true); | ||
271 | 263 | void remove_proxy_interval( | ||
272 | 264 | QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, | ||
273 | 265 | int proxy_start, int proxy_end, const QModelIndex &proxy_parent, | ||
274 | 266 | Qt::Orientation orient, bool emit_signal = true); | ||
275 | 267 | void build_source_to_proxy_mapping( | ||
276 | 268 | const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const; | ||
277 | 269 | void source_items_inserted(const QModelIndex &source_parent, | ||
278 | 270 | int start, int end, Qt::Orientation orient); | ||
279 | 271 | void source_items_about_to_be_removed(const QModelIndex &source_parent, | ||
280 | 272 | int start, int end, Qt::Orientation orient); | ||
281 | 273 | void source_items_removed(const QModelIndex &source_parent, | ||
282 | 274 | int start, int end, Qt::Orientation orient); | ||
283 | 275 | void proxy_item_range( | ||
284 | 276 | const QVector<int> &source_to_proxy, const QVector<int> &source_items, | ||
285 | 277 | int &proxy_low, int &proxy_high) const; | ||
286 | 278 | |||
287 | 279 | QModelIndexPairList store_persistent_indexes(); | ||
288 | 280 | void update_persistent_indexes(const QModelIndexPairList &source_indexes); | ||
289 | 281 | |||
290 | 282 | void filter_changed(const QModelIndex &source_parent = QModelIndex()); | ||
291 | 283 | QSet<int> handle_filter_changed( | ||
292 | 284 | QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, | ||
293 | 285 | const QModelIndex &source_parent, Qt::Orientation orient); | ||
294 | 286 | |||
295 | 287 | void updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping, | ||
296 | 288 | Qt::Orientation orient, int start, int end, int delta_item_count, bool remove); | ||
297 | 289 | |||
298 | 290 | virtual void _q_sourceModelDestroyed(); | ||
299 | 291 | }; | ||
300 | 292 | |||
301 | 293 | typedef QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping *> IndexMap; | ||
302 | 294 | |||
303 | 295 | void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed() | ||
304 | 296 | { | ||
305 | 297 | QAbstractProxyModelPrivate::_q_sourceModelDestroyed(); | ||
306 | 298 | _q_clearMapping(); | ||
307 | 299 | } | ||
308 | 300 | |||
309 | 301 | void QSortFilterProxyModelPrivate::remove_from_mapping(const QModelIndex &source_parent) | ||
310 | 302 | { | ||
311 | 303 | if (Mapping *m = source_index_mapping.take(source_parent)) { | ||
312 | 304 | for (int i = 0; i < m->mapped_children.size(); ++i) | ||
313 | 305 | remove_from_mapping(m->mapped_children.at(i)); | ||
314 | 306 | delete m; | ||
315 | 307 | } | ||
316 | 308 | } | ||
317 | 309 | |||
318 | 310 | void QSortFilterProxyModelPrivate::_q_clearMapping() | ||
319 | 311 | { | ||
320 | 312 | // store the persistent indexes | ||
321 | 313 | QModelIndexPairList source_indexes = store_persistent_indexes(); | ||
322 | 314 | |||
323 | 315 | qDeleteAll(source_index_mapping); | ||
324 | 316 | source_index_mapping.clear(); | ||
325 | 317 | if (dynamic_sortfilter && update_source_sort_column()) { | ||
326 | 318 | //update_source_sort_column might have created wrong mapping so we have to clear it again | ||
327 | 319 | qDeleteAll(source_index_mapping); | ||
328 | 320 | source_index_mapping.clear(); | ||
329 | 321 | } | ||
330 | 322 | |||
331 | 323 | // update the persistent indexes | ||
332 | 324 | update_persistent_indexes(source_indexes); | ||
333 | 325 | } | ||
334 | 326 | |||
335 | 327 | IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping( | ||
336 | 328 | const QModelIndex &source_parent) const | ||
337 | 329 | { | ||
338 | 330 | Q_Q(const QSortFilterProxyModel); | ||
339 | 331 | |||
340 | 332 | IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); | ||
341 | 333 | if (it != source_index_mapping.constEnd()) // was mapped already | ||
342 | 334 | return it; | ||
343 | 335 | |||
344 | 336 | Mapping *m = new Mapping; | ||
345 | 337 | |||
346 | 338 | int source_rows = model->rowCount(source_parent); | ||
347 | 339 | m->source_rows.reserve(source_rows); | ||
348 | 340 | for (int i = 0; i < source_rows; ++i) { | ||
349 | 341 | if (q->filterAcceptsRow(i, source_parent)) | ||
350 | 342 | m->source_rows.append(i); | ||
351 | 343 | } | ||
352 | 344 | int source_cols = model->columnCount(source_parent); | ||
353 | 345 | m->source_columns.reserve(source_cols); | ||
354 | 346 | for (int i = 0; i < source_cols; ++i) { | ||
355 | 347 | if (q->filterAcceptsColumn(i, source_parent)) | ||
356 | 348 | m->source_columns.append(i); | ||
357 | 349 | } | ||
358 | 350 | |||
359 | 351 | sort_source_rows(m->source_rows, source_parent); | ||
360 | 352 | m->proxy_rows.resize(source_rows); | ||
361 | 353 | build_source_to_proxy_mapping(m->source_rows, m->proxy_rows); | ||
362 | 354 | m->proxy_columns.resize(source_cols); | ||
363 | 355 | build_source_to_proxy_mapping(m->source_columns, m->proxy_columns); | ||
364 | 356 | |||
365 | 357 | it = IndexMap::const_iterator(source_index_mapping.insert(source_parent, m)); | ||
366 | 358 | m->map_iter = it; | ||
367 | 359 | |||
368 | 360 | if (source_parent.isValid()) { | ||
369 | 361 | QModelIndex source_grand_parent = source_parent.parent(); | ||
370 | 362 | IndexMap::const_iterator it2 = create_mapping(source_grand_parent); | ||
371 | 363 | Q_ASSERT(it2 != source_index_mapping.constEnd()); | ||
372 | 364 | it2.value()->mapped_children.append(source_parent); | ||
373 | 365 | } | ||
374 | 366 | |||
375 | 367 | Q_ASSERT(it != source_index_mapping.constEnd()); | ||
376 | 368 | Q_ASSERT(it.value()); | ||
377 | 369 | |||
378 | 370 | return it; | ||
379 | 371 | } | ||
380 | 372 | |||
381 | 373 | QModelIndex QSortFilterProxyModelPrivate::proxy_to_source(const QModelIndex &proxy_index) const | ||
382 | 374 | { | ||
383 | 375 | if (!proxy_index.isValid()) | ||
384 | 376 | return QModelIndex(); // for now; we may want to be able to set a root index later | ||
385 | 377 | if (proxy_index.model() != q_func()) { | ||
386 | 378 | qWarning() << "QSortFilterProxyModel: index from wrong model passed to mapToSource"; | ||
387 | 379 | Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapToSource"); | ||
388 | 380 | return QModelIndex(); | ||
389 | 381 | } | ||
390 | 382 | IndexMap::const_iterator it = index_to_iterator(proxy_index); | ||
391 | 383 | Mapping *m = it.value(); | ||
392 | 384 | if ((proxy_index.row() >= m->source_rows.size()) || (proxy_index.column() >= m->source_columns.size())) | ||
393 | 385 | return QModelIndex(); | ||
394 | 386 | int source_row = m->source_rows.at(proxy_index.row()); | ||
395 | 387 | int source_col = m->source_columns.at(proxy_index.column()); | ||
396 | 388 | return model->index(source_row, source_col, it.key()); | ||
397 | 389 | } | ||
398 | 390 | |||
399 | 391 | QModelIndex QSortFilterProxyModelPrivate::source_to_proxy(const QModelIndex &source_index) const | ||
400 | 392 | { | ||
401 | 393 | if (!source_index.isValid()) | ||
402 | 394 | return QModelIndex(); // for now; we may want to be able to set a root index later | ||
403 | 395 | if (source_index.model() != model) { | ||
404 | 396 | qWarning() << "QSortFilterProxyModel: index from wrong model passed to mapFromSource"; | ||
405 | 397 | Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapFromSource"); | ||
406 | 398 | return QModelIndex(); | ||
407 | 399 | } | ||
408 | 400 | QModelIndex source_parent = source_index.parent(); | ||
409 | 401 | IndexMap::const_iterator it = create_mapping(source_parent); | ||
410 | 402 | Mapping *m = it.value(); | ||
411 | 403 | if ((source_index.row() >= m->proxy_rows.size()) || (source_index.column() >= m->proxy_columns.size())) | ||
412 | 404 | return QModelIndex(); | ||
413 | 405 | int proxy_row = m->proxy_rows.at(source_index.row()); | ||
414 | 406 | int proxy_column = m->proxy_columns.at(source_index.column()); | ||
415 | 407 | if (proxy_row == -1 || proxy_column == -1) | ||
416 | 408 | return QModelIndex(); | ||
417 | 409 | return create_index(proxy_row, proxy_column, it); | ||
418 | 410 | } | ||
419 | 411 | |||
420 | 412 | bool QSortFilterProxyModelPrivate::can_create_mapping(const QModelIndex &source_parent) const | ||
421 | 413 | { | ||
422 | 414 | if (source_parent.isValid()) { | ||
423 | 415 | QModelIndex source_grand_parent = source_parent.parent(); | ||
424 | 416 | IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent); | ||
425 | 417 | if (it == source_index_mapping.constEnd()) { | ||
426 | 418 | // Don't care, since we don't have mapping for the grand parent | ||
427 | 419 | return false; | ||
428 | 420 | } | ||
429 | 421 | Mapping *gm = it.value(); | ||
430 | 422 | if (gm->proxy_rows.at(source_parent.row()) == -1 || | ||
431 | 423 | gm->proxy_columns.at(source_parent.column()) == -1) { | ||
432 | 424 | // Don't care, since parent is filtered | ||
433 | 425 | return false; | ||
434 | 426 | } | ||
435 | 427 | } | ||
436 | 428 | return true; | ||
437 | 429 | } | ||
438 | 430 | |||
439 | 431 | /*! | ||
440 | 432 | \internal | ||
441 | 433 | |||
442 | 434 | Sorts the existing mappings. | ||
443 | 435 | */ | ||
444 | 436 | void QSortFilterProxyModelPrivate::sort() | ||
445 | 437 | { | ||
446 | 438 | Q_Q(QSortFilterProxyModel); | ||
447 | 439 | emit q->layoutAboutToBeChanged(QList<QPersistentModelIndex>(), QAbstractItemModel::VerticalSortHint); | ||
448 | 440 | QModelIndexPairList source_indexes = store_persistent_indexes(); | ||
449 | 441 | IndexMap::const_iterator it = source_index_mapping.constBegin(); | ||
450 | 442 | for (; it != source_index_mapping.constEnd(); ++it) { | ||
451 | 443 | QModelIndex source_parent = it.key(); | ||
452 | 444 | Mapping *m = it.value(); | ||
453 | 445 | sort_source_rows(m->source_rows, source_parent); | ||
454 | 446 | build_source_to_proxy_mapping(m->source_rows, m->proxy_rows); | ||
455 | 447 | } | ||
456 | 448 | update_persistent_indexes(source_indexes); | ||
457 | 449 | emit q->layoutChanged(QList<QPersistentModelIndex>(), QAbstractItemModel::VerticalSortHint); | ||
458 | 450 | } | ||
459 | 451 | |||
460 | 452 | /*! | ||
461 | 453 | \internal | ||
462 | 454 | |||
463 | 455 | update the source_sort_column according to the proxy_sort_column | ||
464 | 456 | return true if the column was changed | ||
465 | 457 | */ | ||
466 | 458 | bool QSortFilterProxyModelPrivate::update_source_sort_column() | ||
467 | 459 | { | ||
468 | 460 | Q_Q(QSortFilterProxyModel); | ||
469 | 461 | QModelIndex proxy_index = q->index(0, proxy_sort_column, QModelIndex()); | ||
470 | 462 | int old_source_sort_column = source_sort_column; | ||
471 | 463 | source_sort_column = q->mapToSource(proxy_index).column(); | ||
472 | 464 | return old_source_sort_column != source_sort_column; | ||
473 | 465 | } | ||
474 | 466 | |||
475 | 467 | |||
476 | 468 | /*! | ||
477 | 469 | \internal | ||
478 | 470 | |||
479 | 471 | Sorts the given \a source_rows according to current sort column and order. | ||
480 | 472 | */ | ||
481 | 473 | void QSortFilterProxyModelPrivate::sort_source_rows( | ||
482 | 474 | QVector<int> &source_rows, const QModelIndex &source_parent) const | ||
483 | 475 | { | ||
484 | 476 | Q_Q(const QSortFilterProxyModel); | ||
485 | 477 | if (source_sort_column >= 0) { | ||
486 | 478 | if (sort_order == Qt::AscendingOrder) { | ||
487 | 479 | QSortFilterProxyModelLessThan lt(source_sort_column, source_parent, model, q); | ||
488 | 480 | std::stable_sort(source_rows.begin(), source_rows.end(), lt); | ||
489 | 481 | } else { | ||
490 | 482 | QSortFilterProxyModelGreaterThan gt(source_sort_column, source_parent, model, q); | ||
491 | 483 | std::stable_sort(source_rows.begin(), source_rows.end(), gt); | ||
492 | 484 | } | ||
493 | 485 | } else { // restore the source model order | ||
494 | 486 | std::stable_sort(source_rows.begin(), source_rows.end()); | ||
495 | 487 | } | ||
496 | 488 | } | ||
497 | 489 | |||
498 | 490 | /*! | ||
499 | 491 | \internal | ||
500 | 492 | |||
501 | 493 | Given source-to-proxy mapping \a source_to_proxy and the set of | ||
502 | 494 | source items \a source_items (which are part of that mapping), | ||
503 | 495 | determines the corresponding proxy item intervals that should | ||
504 | 496 | be removed from the proxy model. | ||
505 | 497 | |||
506 | 498 | The result is a vector of pairs, where each pair represents a | ||
507 | 499 | (start, end) tuple, sorted in ascending order. | ||
508 | 500 | */ | ||
509 | 501 | QVector<QPair<int, int > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items( | ||
510 | 502 | const QVector<int> &source_to_proxy, const QVector<int> &source_items) const | ||
511 | 503 | { | ||
512 | 504 | QVector<QPair<int, int> > proxy_intervals; | ||
513 | 505 | if (source_items.isEmpty()) | ||
514 | 506 | return proxy_intervals; | ||
515 | 507 | |||
516 | 508 | int source_items_index = 0; | ||
517 | 509 | while (source_items_index < source_items.size()) { | ||
518 | 510 | int first_proxy_item = source_to_proxy.at(source_items.at(source_items_index)); | ||
519 | 511 | Q_ASSERT(first_proxy_item != -1); | ||
520 | 512 | int last_proxy_item = first_proxy_item; | ||
521 | 513 | ++source_items_index; | ||
522 | 514 | // Find end of interval | ||
523 | 515 | while ((source_items_index < source_items.size()) | ||
524 | 516 | && (source_to_proxy.at(source_items.at(source_items_index)) == last_proxy_item + 1)) { | ||
525 | 517 | ++last_proxy_item; | ||
526 | 518 | ++source_items_index; | ||
527 | 519 | } | ||
528 | 520 | // Add interval to result | ||
529 | 521 | proxy_intervals.append(QPair<int, int>(first_proxy_item, last_proxy_item)); | ||
530 | 522 | } | ||
531 | 523 | std::stable_sort(proxy_intervals.begin(), proxy_intervals.end()); | ||
532 | 524 | return proxy_intervals; | ||
533 | 525 | } | ||
534 | 526 | |||
535 | 527 | /*! | ||
536 | 528 | \internal | ||
537 | 529 | |||
538 | 530 | Given source-to-proxy mapping \a src_to_proxy and proxy-to-source mapping | ||
539 | 531 | \a proxy_to_source, removes \a source_items from this proxy model. | ||
540 | 532 | The corresponding proxy items are removed in intervals, so that the proper | ||
541 | 533 | rows/columnsRemoved(start, end) signals will be generated. | ||
542 | 534 | */ | ||
543 | 535 | void QSortFilterProxyModelPrivate::remove_source_items( | ||
544 | 536 | QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, | ||
545 | 537 | const QVector<int> &source_items, const QModelIndex &source_parent, | ||
546 | 538 | Qt::Orientation orient, bool emit_signal) | ||
547 | 539 | { | ||
548 | 540 | Q_Q(QSortFilterProxyModel); | ||
549 | 541 | QModelIndex proxy_parent = q->mapFromSource(source_parent); | ||
550 | 542 | if (!proxy_parent.isValid() && source_parent.isValid()) | ||
551 | 543 | return; // nothing to do (already removed) | ||
552 | 544 | |||
553 | 545 | QVector<QPair<int, int> > proxy_intervals; | ||
554 | 546 | proxy_intervals = proxy_intervals_for_source_items(source_to_proxy, source_items); | ||
555 | 547 | |||
556 | 548 | for (int i = proxy_intervals.size()-1; i >= 0; --i) { | ||
557 | 549 | QPair<int, int> interval = proxy_intervals.at(i); | ||
558 | 550 | int proxy_start = interval.first; | ||
559 | 551 | int proxy_end = interval.second; | ||
560 | 552 | remove_proxy_interval(source_to_proxy, proxy_to_source, proxy_start, proxy_end, | ||
561 | 553 | proxy_parent, orient, emit_signal); | ||
562 | 554 | } | ||
563 | 555 | } | ||
564 | 556 | |||
565 | 557 | /*! | ||
566 | 558 | \internal | ||
567 | 559 | |||
568 | 560 | Given source-to-proxy mapping \a source_to_proxy and proxy-to-source mapping | ||
569 | 561 | \a proxy_to_source, removes items from \a proxy_start to \a proxy_end | ||
570 | 562 | (inclusive) from this proxy model. | ||
571 | 563 | */ | ||
572 | 564 | void QSortFilterProxyModelPrivate::remove_proxy_interval( | ||
573 | 565 | QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, int proxy_start, int proxy_end, | ||
574 | 566 | const QModelIndex &proxy_parent, Qt::Orientation orient, bool emit_signal) | ||
575 | 567 | { | ||
576 | 568 | Q_Q(QSortFilterProxyModel); | ||
577 | 569 | if (emit_signal) { | ||
578 | 570 | if (orient == Qt::Vertical) | ||
579 | 571 | q->beginRemoveRows(proxy_parent, proxy_start, proxy_end); | ||
580 | 572 | else | ||
581 | 573 | q->beginRemoveColumns(proxy_parent, proxy_start, proxy_end); | ||
582 | 574 | } | ||
583 | 575 | |||
584 | 576 | // Remove items from proxy-to-source mapping | ||
585 | 577 | proxy_to_source.remove(proxy_start, proxy_end - proxy_start + 1); | ||
586 | 578 | |||
587 | 579 | build_source_to_proxy_mapping(proxy_to_source, source_to_proxy); | ||
588 | 580 | |||
589 | 581 | if (emit_signal) { | ||
590 | 582 | if (orient == Qt::Vertical) | ||
591 | 583 | q->endRemoveRows(); | ||
592 | 584 | else | ||
593 | 585 | q->endRemoveColumns(); | ||
594 | 586 | } | ||
595 | 587 | } | ||
596 | 588 | |||
597 | 589 | /*! | ||
598 | 590 | \internal | ||
599 | 591 | |||
600 | 592 | Given proxy-to-source mapping \a proxy_to_source and a set of | ||
601 | 593 | unmapped source items \a source_items, determines the proxy item | ||
602 | 594 | intervals at which the subsets of source items should be inserted | ||
603 | 595 | (but does not actually add them to the mapping). | ||
604 | 596 | |||
605 | 597 | The result is a vector of pairs, each pair representing a tuple (start, | ||
606 | 598 | items), where items is a vector containing the (sorted) source items that | ||
607 | 599 | should be inserted at that proxy model location. | ||
608 | 600 | */ | ||
609 | 601 | QVector<QPair<int, QVector<int > > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add( | ||
610 | 602 | const QVector<int> &proxy_to_source, const QVector<int> &source_items, | ||
611 | 603 | const QModelIndex &source_parent, Qt::Orientation orient) const | ||
612 | 604 | { | ||
613 | 605 | Q_Q(const QSortFilterProxyModel); | ||
614 | 606 | QVector<QPair<int, QVector<int> > > proxy_intervals; | ||
615 | 607 | if (source_items.isEmpty()) | ||
616 | 608 | return proxy_intervals; | ||
617 | 609 | |||
618 | 610 | int proxy_low = 0; | ||
619 | 611 | int proxy_item = 0; | ||
620 | 612 | int source_items_index = 0; | ||
621 | 613 | QVector<int> source_items_in_interval; | ||
622 | 614 | bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter); | ||
623 | 615 | while (source_items_index < source_items.size()) { | ||
624 | 616 | source_items_in_interval.clear(); | ||
625 | 617 | int first_new_source_item = source_items.at(source_items_index); | ||
626 | 618 | source_items_in_interval.append(first_new_source_item); | ||
627 | 619 | ++source_items_index; | ||
628 | 620 | |||
629 | 621 | // Find proxy item at which insertion should be started | ||
630 | 622 | int proxy_high = proxy_to_source.size() - 1; | ||
631 | 623 | QModelIndex i1 = compare ? model->index(first_new_source_item, source_sort_column, source_parent) : QModelIndex(); | ||
632 | 624 | while (proxy_low <= proxy_high) { | ||
633 | 625 | proxy_item = (proxy_low + proxy_high) / 2; | ||
634 | 626 | if (compare) { | ||
635 | 627 | QModelIndex i2 = model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent); | ||
636 | 628 | if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1)) | ||
637 | 629 | proxy_high = proxy_item - 1; | ||
638 | 630 | else | ||
639 | 631 | proxy_low = proxy_item + 1; | ||
640 | 632 | } else { | ||
641 | 633 | if (first_new_source_item < proxy_to_source.at(proxy_item)) | ||
642 | 634 | proxy_high = proxy_item - 1; | ||
643 | 635 | else | ||
644 | 636 | proxy_low = proxy_item + 1; | ||
645 | 637 | } | ||
646 | 638 | } | ||
647 | 639 | proxy_item = proxy_low; | ||
648 | 640 | |||
649 | 641 | // Find the sequence of new source items that should be inserted here | ||
650 | 642 | if (proxy_item >= proxy_to_source.size()) { | ||
651 | 643 | for ( ; source_items_index < source_items.size(); ++source_items_index) | ||
652 | 644 | source_items_in_interval.append(source_items.at(source_items_index)); | ||
653 | 645 | } else { | ||
654 | 646 | i1 = compare ? model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent) : QModelIndex(); | ||
655 | 647 | for ( ; source_items_index < source_items.size(); ++source_items_index) { | ||
656 | 648 | int new_source_item = source_items.at(source_items_index); | ||
657 | 649 | if (compare) { | ||
658 | 650 | QModelIndex i2 = model->index(new_source_item, source_sort_column, source_parent); | ||
659 | 651 | if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1)) | ||
660 | 652 | break; | ||
661 | 653 | } else { | ||
662 | 654 | if (proxy_to_source.at(proxy_item) < new_source_item) | ||
663 | 655 | break; | ||
664 | 656 | } | ||
665 | 657 | source_items_in_interval.append(new_source_item); | ||
666 | 658 | } | ||
667 | 659 | } | ||
668 | 660 | |||
669 | 661 | // Add interval to result | ||
670 | 662 | proxy_intervals.append(QPair<int, QVector<int> >(proxy_item, source_items_in_interval)); | ||
671 | 663 | } | ||
672 | 664 | return proxy_intervals; | ||
673 | 665 | } | ||
674 | 666 | |||
675 | 667 | /*! | ||
676 | 668 | \internal | ||
677 | 669 | |||
678 | 670 | Given source-to-proxy mapping \a source_to_proxy and proxy-to-source mapping | ||
679 | 671 | \a proxy_to_source, inserts the given \a source_items into this proxy model. | ||
680 | 672 | The source items are inserted in intervals (based on some sorted order), so | ||
681 | 673 | that the proper rows/columnsInserted(start, end) signals will be generated. | ||
682 | 674 | */ | ||
683 | 675 | void QSortFilterProxyModelPrivate::insert_source_items( | ||
684 | 676 | QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, | ||
685 | 677 | const QVector<int> &source_items, const QModelIndex &source_parent, | ||
686 | 678 | Qt::Orientation orient, bool emit_signal) | ||
687 | 679 | { | ||
688 | 680 | Q_Q(QSortFilterProxyModel); | ||
689 | 681 | QModelIndex proxy_parent = q->mapFromSource(source_parent); | ||
690 | 682 | if (!proxy_parent.isValid() && source_parent.isValid()) | ||
691 | 683 | return; // nothing to do (source_parent is not mapped) | ||
692 | 684 | |||
693 | 685 | QVector<QPair<int, QVector<int> > > proxy_intervals; | ||
694 | 686 | proxy_intervals = proxy_intervals_for_source_items_to_add( | ||
695 | 687 | proxy_to_source, source_items, source_parent, orient); | ||
696 | 688 | |||
697 | 689 | for (int i = proxy_intervals.size()-1; i >= 0; --i) { | ||
698 | 690 | QPair<int, QVector<int> > interval = proxy_intervals.at(i); | ||
699 | 691 | int proxy_start = interval.first; | ||
700 | 692 | QVector<int> source_items = interval.second; | ||
701 | 693 | int proxy_end = proxy_start + source_items.size() - 1; | ||
702 | 694 | |||
703 | 695 | if (emit_signal) { | ||
704 | 696 | if (orient == Qt::Vertical) | ||
705 | 697 | q->beginInsertRows(proxy_parent, proxy_start, proxy_end); | ||
706 | 698 | else | ||
707 | 699 | q->beginInsertColumns(proxy_parent, proxy_start, proxy_end); | ||
708 | 700 | } | ||
709 | 701 | |||
710 | 702 | for (int i = 0; i < source_items.size(); ++i) | ||
711 | 703 | proxy_to_source.insert(proxy_start + i, source_items.at(i)); | ||
712 | 704 | |||
713 | 705 | build_source_to_proxy_mapping(proxy_to_source, source_to_proxy); | ||
714 | 706 | |||
715 | 707 | if (emit_signal) { | ||
716 | 708 | if (orient == Qt::Vertical) | ||
717 | 709 | q->endInsertRows(); | ||
718 | 710 | else | ||
719 | 711 | q->endInsertColumns(); | ||
720 | 712 | } | ||
721 | 713 | } | ||
722 | 714 | } | ||
723 | 715 | |||
724 | 716 | /*! | ||
725 | 717 | \internal | ||
726 | 718 | |||
727 | 719 | Handles source model items insertion (columnsInserted(), rowsInserted()). | ||
728 | 720 | Determines | ||
729 | 721 | 1) which of the inserted items to also insert into proxy model (filtering), | ||
730 | 722 | 2) where to insert the items into the proxy model (sorting), | ||
731 | 723 | then inserts those items. | ||
732 | 724 | The items are inserted into the proxy model in intervals (based on | ||
733 | 725 | sorted order), so that the proper rows/columnsInserted(start, end) | ||
734 | 726 | signals will be generated. | ||
735 | 727 | */ | ||
736 | 728 | void QSortFilterProxyModelPrivate::source_items_inserted( | ||
737 | 729 | const QModelIndex &source_parent, int start, int end, Qt::Orientation orient) | ||
738 | 730 | { | ||
739 | 731 | Q_Q(QSortFilterProxyModel); | ||
740 | 732 | if ((start < 0) || (end < 0)) | ||
741 | 733 | return; | ||
742 | 734 | IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); | ||
743 | 735 | if (it == source_index_mapping.constEnd()) { | ||
744 | 736 | if (!can_create_mapping(source_parent)) | ||
745 | 737 | return; | ||
746 | 738 | it = create_mapping(source_parent); | ||
747 | 739 | Mapping *m = it.value(); | ||
748 | 740 | QModelIndex proxy_parent = q->mapFromSource(source_parent); | ||
749 | 741 | if (m->source_rows.count() > 0) { | ||
750 | 742 | q->beginInsertRows(proxy_parent, 0, m->source_rows.count() - 1); | ||
751 | 743 | q->endInsertRows(); | ||
752 | 744 | } | ||
753 | 745 | if (m->source_columns.count() > 0) { | ||
754 | 746 | q->beginInsertColumns(proxy_parent, 0, m->source_columns.count() - 1); | ||
755 | 747 | q->endInsertColumns(); | ||
756 | 748 | } | ||
757 | 749 | return; | ||
758 | 750 | } | ||
759 | 751 | |||
760 | 752 | Mapping *m = it.value(); | ||
761 | 753 | QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns; | ||
762 | 754 | QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns; | ||
763 | 755 | |||
764 | 756 | int delta_item_count = end - start + 1; | ||
765 | 757 | int old_item_count = source_to_proxy.size(); | ||
766 | 758 | |||
767 | 759 | updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, false); | ||
768 | 760 | |||
769 | 761 | // Expand source-to-proxy mapping to account for new items | ||
770 | 762 | if (start < 0 || start > source_to_proxy.size()) { | ||
771 | 763 | qWarning("QSortFilterProxyModel: invalid inserted rows reported by source model"); | ||
772 | 764 | remove_from_mapping(source_parent); | ||
773 | 765 | return; | ||
774 | 766 | } | ||
775 | 767 | source_to_proxy.insert(start, delta_item_count, -1); | ||
776 | 768 | |||
777 | 769 | if (start < old_item_count) { | ||
778 | 770 | // Adjust existing "stale" indexes in proxy-to-source mapping | ||
779 | 771 | int proxy_count = proxy_to_source.size(); | ||
780 | 772 | for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) { | ||
781 | 773 | int source_item = proxy_to_source.at(proxy_item); | ||
782 | 774 | if (source_item >= start) | ||
783 | 775 | proxy_to_source.replace(proxy_item, source_item + delta_item_count); | ||
784 | 776 | } | ||
785 | 777 | build_source_to_proxy_mapping(proxy_to_source, source_to_proxy); | ||
786 | 778 | } | ||
787 | 779 | |||
788 | 780 | // Figure out which items to add to mapping based on filter | ||
789 | 781 | QVector<int> source_items; | ||
790 | 782 | for (int i = start; i <= end; ++i) { | ||
791 | 783 | if ((orient == Qt::Vertical) | ||
792 | 784 | ? q->filterAcceptsRow(i, source_parent) | ||
793 | 785 | : q->filterAcceptsColumn(i, source_parent)) { | ||
794 | 786 | source_items.append(i); | ||
795 | 787 | } | ||
796 | 788 | } | ||
797 | 789 | |||
798 | 790 | if (model->rowCount(source_parent) == delta_item_count) { | ||
799 | 791 | // Items were inserted where there were none before. | ||
800 | 792 | // If it was new rows make sure to create mappings for columns so that a | ||
801 | 793 | // valid mapping can be retrieved later and vice-versa. | ||
802 | 794 | |||
803 | 795 | QVector<int> &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns; | ||
804 | 796 | QVector<int> &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns; | ||
805 | 797 | |||
806 | 798 | if (orthogonal_source_to_proxy.isEmpty()) { | ||
807 | 799 | const int ortho_end = (orient == Qt::Horizontal) ? model->rowCount(source_parent) : model->columnCount(source_parent); | ||
808 | 800 | |||
809 | 801 | orthogonal_source_to_proxy.resize(ortho_end); | ||
810 | 802 | |||
811 | 803 | for (int ortho_item = 0; ortho_item < ortho_end; ++ortho_item) { | ||
812 | 804 | if ((orient == Qt::Horizontal) ? q->filterAcceptsRow(ortho_item, source_parent) | ||
813 | 805 | : q->filterAcceptsColumn(ortho_item, source_parent)) { | ||
814 | 806 | orthogonal_proxy_to_source.append(ortho_item); | ||
815 | 807 | } | ||
816 | 808 | } | ||
817 | 809 | if (orient == Qt::Horizontal) { | ||
818 | 810 | // We're reacting to columnsInserted, but we've just inserted new rows. Sort them. | ||
819 | 811 | sort_source_rows(orthogonal_proxy_to_source, source_parent); | ||
820 | 812 | } | ||
821 | 813 | build_source_to_proxy_mapping(orthogonal_proxy_to_source, orthogonal_source_to_proxy); | ||
822 | 814 | } | ||
823 | 815 | } | ||
824 | 816 | |||
825 | 817 | // Sort and insert the items | ||
826 | 818 | if (orient == Qt::Vertical) // Only sort rows | ||
827 | 819 | sort_source_rows(source_items, source_parent); | ||
828 | 820 | insert_source_items(source_to_proxy, proxy_to_source, source_items, source_parent, orient); | ||
829 | 821 | } | ||
830 | 822 | |||
831 | 823 | /*! | ||
832 | 824 | \internal | ||
833 | 825 | |||
834 | 826 | Handles source model items removal | ||
835 | 827 | (columnsAboutToBeRemoved(), rowsAboutToBeRemoved()). | ||
836 | 828 | */ | ||
837 | 829 | void QSortFilterProxyModelPrivate::source_items_about_to_be_removed( | ||
838 | 830 | const QModelIndex &source_parent, int start, int end, Qt::Orientation orient) | ||
839 | 831 | { | ||
840 | 832 | if ((start < 0) || (end < 0)) | ||
841 | 833 | return; | ||
842 | 834 | IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); | ||
843 | 835 | if (it == source_index_mapping.constEnd()) { | ||
844 | 836 | // Don't care, since we don't have mapping for this index | ||
845 | 837 | return; | ||
846 | 838 | } | ||
847 | 839 | |||
848 | 840 | Mapping *m = it.value(); | ||
849 | 841 | QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns; | ||
850 | 842 | QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns; | ||
851 | 843 | |||
852 | 844 | // figure out which items to remove | ||
853 | 845 | QVector<int> source_items_to_remove; | ||
854 | 846 | int proxy_count = proxy_to_source.size(); | ||
855 | 847 | for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) { | ||
856 | 848 | int source_item = proxy_to_source.at(proxy_item); | ||
857 | 849 | if ((source_item >= start) && (source_item <= end)) | ||
858 | 850 | source_items_to_remove.append(source_item); | ||
859 | 851 | } | ||
860 | 852 | |||
861 | 853 | remove_source_items(source_to_proxy, proxy_to_source, source_items_to_remove, | ||
862 | 854 | source_parent, orient); | ||
863 | 855 | } | ||
864 | 856 | |||
865 | 857 | /*! | ||
866 | 858 | \internal | ||
867 | 859 | |||
868 | 860 | Handles source model items removal (columnsRemoved(), rowsRemoved()). | ||
869 | 861 | */ | ||
870 | 862 | void QSortFilterProxyModelPrivate::source_items_removed( | ||
871 | 863 | const QModelIndex &source_parent, int start, int end, Qt::Orientation orient) | ||
872 | 864 | { | ||
873 | 865 | if ((start < 0) || (end < 0)) | ||
874 | 866 | return; | ||
875 | 867 | IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); | ||
876 | 868 | if (it == source_index_mapping.constEnd()) { | ||
877 | 869 | // Don't care, since we don't have mapping for this index | ||
878 | 870 | return; | ||
879 | 871 | } | ||
880 | 872 | |||
881 | 873 | Mapping *m = it.value(); | ||
882 | 874 | QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns; | ||
883 | 875 | QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns; | ||
884 | 876 | |||
885 | 877 | if (end >= source_to_proxy.size()) | ||
886 | 878 | end = source_to_proxy.size() - 1; | ||
887 | 879 | |||
888 | 880 | // Shrink the source-to-proxy mapping to reflect the new item count | ||
889 | 881 | int delta_item_count = end - start + 1; | ||
890 | 882 | source_to_proxy.remove(start, delta_item_count); | ||
891 | 883 | |||
892 | 884 | int proxy_count = proxy_to_source.size(); | ||
893 | 885 | if (proxy_count > source_to_proxy.size()) { | ||
894 | 886 | // mapping is in an inconsistent state -- redo the whole mapping | ||
895 | 887 | qWarning("QSortFilterProxyModel: inconsistent changes reported by source model"); | ||
896 | 888 | Q_Q(QSortFilterProxyModel); | ||
897 | 889 | q->beginResetModel(); | ||
898 | 890 | remove_from_mapping(source_parent); | ||
899 | 891 | q->endResetModel(); | ||
900 | 892 | return; | ||
901 | 893 | } | ||
902 | 894 | |||
903 | 895 | // Adjust "stale" indexes in proxy-to-source mapping | ||
904 | 896 | for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) { | ||
905 | 897 | int source_item = proxy_to_source.at(proxy_item); | ||
906 | 898 | if (source_item >= start) { | ||
907 | 899 | Q_ASSERT(source_item - delta_item_count >= 0); | ||
908 | 900 | proxy_to_source.replace(proxy_item, source_item - delta_item_count); | ||
909 | 901 | } | ||
910 | 902 | } | ||
911 | 903 | build_source_to_proxy_mapping(proxy_to_source, source_to_proxy); | ||
912 | 904 | |||
913 | 905 | updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, true); | ||
914 | 906 | |||
915 | 907 | } | ||
916 | 908 | |||
917 | 909 | |||
918 | 910 | /*! | ||
919 | 911 | \internal | ||
920 | 912 | updates the mapping of the children when inserting or removing items | ||
921 | 913 | */ | ||
922 | 914 | void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping, | ||
923 | 915 | Qt::Orientation orient, int start, int end, int delta_item_count, bool remove) | ||
924 | 916 | { | ||
925 | 917 | // see if any mapped children should be (re)moved | ||
926 | 918 | QVector<QPair<QModelIndex, Mapping*> > moved_source_index_mappings; | ||
927 | 919 | QVector<QModelIndex>::iterator it2 = parent_mapping->mapped_children.begin(); | ||
928 | 920 | for ( ; it2 != parent_mapping->mapped_children.end();) { | ||
929 | 921 | const QModelIndex source_child_index = *it2; | ||
930 | 922 | const int pos = (orient == Qt::Vertical) | ||
931 | 923 | ? source_child_index.row() | ||
932 | 924 | : source_child_index.column(); | ||
933 | 925 | if (pos < start) { | ||
934 | 926 | // not affected | ||
935 | 927 | ++it2; | ||
936 | 928 | } else if (remove && pos <= end) { | ||
937 | 929 | // in the removed interval | ||
938 | 930 | it2 = parent_mapping->mapped_children.erase(it2); | ||
939 | 931 | remove_from_mapping(source_child_index); | ||
940 | 932 | } else { | ||
941 | 933 | // below the removed items -- recompute the index | ||
942 | 934 | QModelIndex new_index; | ||
943 | 935 | const int newpos = remove ? pos - delta_item_count : pos + delta_item_count; | ||
944 | 936 | if (orient == Qt::Vertical) { | ||
945 | 937 | new_index = model->index(newpos, | ||
946 | 938 | source_child_index.column(), | ||
947 | 939 | source_parent); | ||
948 | 940 | } else { | ||
949 | 941 | new_index = model->index(source_child_index.row(), | ||
950 | 942 | newpos, | ||
951 | 943 | source_parent); | ||
952 | 944 | } | ||
953 | 945 | *it2 = new_index; | ||
954 | 946 | ++it2; | ||
955 | 947 | |||
956 | 948 | // update mapping | ||
957 | 949 | Mapping *cm = source_index_mapping.take(source_child_index); | ||
958 | 950 | Q_ASSERT(cm); | ||
959 | 951 | // we do not reinsert right away, because the new index might be identical with another, old index | ||
960 | 952 | moved_source_index_mappings.append(QPair<QModelIndex, Mapping*>(new_index, cm)); | ||
961 | 953 | } | ||
962 | 954 | } | ||
963 | 955 | |||
964 | 956 | // reinsert moved, mapped indexes | ||
965 | 957 | QVector<QPair<QModelIndex, Mapping*> >::iterator it = moved_source_index_mappings.begin(); | ||
966 | 958 | for (; it != moved_source_index_mappings.end(); ++it) { | ||
967 | 959 | #ifdef QT_STRICT_ITERATORS | ||
968 | 960 | source_index_mapping.insert((*it).first, (*it).second); | ||
969 | 961 | (*it).second->map_iter = source_index_mapping.constFind((*it).first); | ||
970 | 962 | #else | ||
971 | 963 | (*it).second->map_iter = source_index_mapping.insert((*it).first, (*it).second); | ||
972 | 964 | #endif | ||
973 | 965 | } | ||
974 | 966 | } | ||
975 | 967 | |||
976 | 968 | /*! | ||
977 | 969 | \internal | ||
978 | 970 | */ | ||
979 | 971 | void QSortFilterProxyModelPrivate::proxy_item_range( | ||
980 | 972 | const QVector<int> &source_to_proxy, const QVector<int> &source_items, | ||
981 | 973 | int &proxy_low, int &proxy_high) const | ||
982 | 974 | { | ||
983 | 975 | proxy_low = INT_MAX; | ||
984 | 976 | proxy_high = INT_MIN; | ||
985 | 977 | for (int i = 0; i < source_items.count(); ++i) { | ||
986 | 978 | int proxy_item = source_to_proxy.at(source_items.at(i)); | ||
987 | 979 | Q_ASSERT(proxy_item != -1); | ||
988 | 980 | if (proxy_item < proxy_low) | ||
989 | 981 | proxy_low = proxy_item; | ||
990 | 982 | if (proxy_item > proxy_high) | ||
991 | 983 | proxy_high = proxy_item; | ||
992 | 984 | } | ||
993 | 985 | } | ||
994 | 986 | |||
995 | 987 | /*! | ||
996 | 988 | \internal | ||
997 | 989 | */ | ||
998 | 990 | void QSortFilterProxyModelPrivate::build_source_to_proxy_mapping( | ||
999 | 991 | const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const | ||
1000 | 992 | { | ||
1001 | 993 | source_to_proxy.fill(-1); | ||
1002 | 994 | int proxy_count = proxy_to_source.size(); | ||
1003 | 995 | for (int i = 0; i < proxy_count; ++i) | ||
1004 | 996 | source_to_proxy[proxy_to_source.at(i)] = i; | ||
1005 | 997 | } | ||
1006 | 998 | |||
1007 | 999 | /*! | ||
1008 | 1000 | \internal | ||
1009 | 1001 | |||
1010 | 1002 | Maps the persistent proxy indexes to source indexes and | ||
1011 | 1003 | returns the list of source indexes. | ||
1012 | 1004 | */ | ||
1013 | 1005 | QModelIndexPairList QSortFilterProxyModelPrivate::store_persistent_indexes() | ||
1014 | 1006 | { | ||
1015 | 1007 | Q_Q(QSortFilterProxyModel); | ||
1016 | 1008 | QModelIndexPairList source_indexes; | ||
1017 | 1009 | foreach (QPersistentModelIndexData *data, persistent.indexes) { | ||
1018 | 1010 | QModelIndex proxy_index = data->index; | ||
1019 | 1011 | QModelIndex source_index = q->mapToSource(proxy_index); | ||
1020 | 1012 | source_indexes.append(qMakePair(proxy_index, QPersistentModelIndex(source_index))); | ||
1021 | 1013 | } | ||
1022 | 1014 | return source_indexes; | ||
1023 | 1015 | } | ||
1024 | 1016 | |||
1025 | 1017 | /*! | ||
1026 | 1018 | \internal | ||
1027 | 1019 | |||
1028 | 1020 | Maps \a source_indexes to proxy indexes and stores those | ||
1029 | 1021 | as persistent indexes. | ||
1030 | 1022 | */ | ||
1031 | 1023 | void QSortFilterProxyModelPrivate::update_persistent_indexes( | ||
1032 | 1024 | const QModelIndexPairList &source_indexes) | ||
1033 | 1025 | { | ||
1034 | 1026 | Q_Q(QSortFilterProxyModel); | ||
1035 | 1027 | QModelIndexList from, to; | ||
1036 | 1028 | for (int i = 0; i < source_indexes.count(); ++i) { | ||
1037 | 1029 | QModelIndex source_index = source_indexes.at(i).second; | ||
1038 | 1030 | QModelIndex old_proxy_index = source_indexes.at(i).first; | ||
1039 | 1031 | create_mapping(source_index.parent()); | ||
1040 | 1032 | QModelIndex proxy_index = q->mapFromSource(source_index); | ||
1041 | 1033 | from << old_proxy_index; | ||
1042 | 1034 | to << proxy_index; | ||
1043 | 1035 | } | ||
1044 | 1036 | q->changePersistentIndexList(from, to); | ||
1045 | 1037 | } | ||
1046 | 1038 | |||
1047 | 1039 | |||
1048 | 1040 | /*! | ||
1049 | 1041 | \internal | ||
1050 | 1042 | |||
1051 | 1043 | Updates the proxy model (adds/removes rows) based on the | ||
1052 | 1044 | new filter. | ||
1053 | 1045 | */ | ||
1054 | 1046 | void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_parent) | ||
1055 | 1047 | { | ||
1056 | 1048 | IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); | ||
1057 | 1049 | if (it == source_index_mapping.constEnd()) | ||
1058 | 1050 | return; | ||
1059 | 1051 | Mapping *m = it.value(); | ||
1060 | 1052 | QSet<int> rows_removed = handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical); | ||
1061 | 1053 | QSet<int> columns_removed = handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal); | ||
1062 | 1054 | |||
1063 | 1055 | // We need to iterate over a copy of m->mapped_children because otherwise it may be changed by other code, invalidating | ||
1064 | 1056 | // the iterator it2. | ||
1065 | 1057 | // The m->mapped_children vector can be appended to with indexes which are no longer filtered | ||
1066 | 1058 | // out (in create_mapping) when this function recurses for child indexes. | ||
1067 | 1059 | const QVector<QModelIndex> mappedChildren = m->mapped_children; | ||
1068 | 1060 | QVector<int> indexesToRemove; | ||
1069 | 1061 | for (int i = 0; i < mappedChildren.size(); ++i) { | ||
1070 | 1062 | const QModelIndex source_child_index = mappedChildren.at(i); | ||
1071 | 1063 | if (rows_removed.contains(source_child_index.row()) || columns_removed.contains(source_child_index.column())) { | ||
1072 | 1064 | indexesToRemove.push_back(i); | ||
1073 | 1065 | remove_from_mapping(source_child_index); | ||
1074 | 1066 | } else { | ||
1075 | 1067 | filter_changed(source_child_index); | ||
1076 | 1068 | } | ||
1077 | 1069 | } | ||
1078 | 1070 | QVector<int>::const_iterator removeIt = indexesToRemove.constEnd(); | ||
1079 | 1071 | const QVector<int>::const_iterator removeBegin = indexesToRemove.constBegin(); | ||
1080 | 1072 | |||
1081 | 1073 | // We can't just remove these items from mappedChildren while iterating above and then | ||
1082 | 1074 | // do something like m->mapped_children = mappedChildren, because mapped_children might | ||
1083 | 1075 | // be appended to in create_mapping, and we would lose those new items. | ||
1084 | 1076 | // Because they are always appended in create_mapping, we can still remove them by | ||
1085 | 1077 | // position here. | ||
1086 | 1078 | while (removeIt != removeBegin) { | ||
1087 | 1079 | --removeIt; | ||
1088 | 1080 | m->mapped_children.remove(*removeIt); | ||
1089 | 1081 | } | ||
1090 | 1082 | } | ||
1091 | 1083 | |||
1092 | 1084 | /*! | ||
1093 | 1085 | \internal | ||
1094 | 1086 | returns the removed items indexes | ||
1095 | 1087 | */ | ||
1096 | 1088 | QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed( | ||
1097 | 1089 | QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, | ||
1098 | 1090 | const QModelIndex &source_parent, Qt::Orientation orient) | ||
1099 | 1091 | { | ||
1100 | 1092 | Q_Q(QSortFilterProxyModel); | ||
1101 | 1093 | // Figure out which mapped items to remove | ||
1102 | 1094 | QVector<int> source_items_remove; | ||
1103 | 1095 | for (int i = 0; i < proxy_to_source.count(); ++i) { | ||
1104 | 1096 | const int source_item = proxy_to_source.at(i); | ||
1105 | 1097 | if ((orient == Qt::Vertical) | ||
1106 | 1098 | ? !q->filterAcceptsRow(source_item, source_parent) | ||
1107 | 1099 | : !q->filterAcceptsColumn(source_item, source_parent)) { | ||
1108 | 1100 | // This source item does not satisfy the filter, so it must be removed | ||
1109 | 1101 | source_items_remove.append(source_item); | ||
1110 | 1102 | } | ||
1111 | 1103 | } | ||
1112 | 1104 | // Figure out which non-mapped items to insert | ||
1113 | 1105 | QVector<int> source_items_insert; | ||
1114 | 1106 | int source_count = source_to_proxy.size(); | ||
1115 | 1107 | for (int source_item = 0; source_item < source_count; ++source_item) { | ||
1116 | 1108 | if (source_to_proxy.at(source_item) == -1) { | ||
1117 | 1109 | if ((orient == Qt::Vertical) | ||
1118 | 1110 | ? q->filterAcceptsRow(source_item, source_parent) | ||
1119 | 1111 | : q->filterAcceptsColumn(source_item, source_parent)) { | ||
1120 | 1112 | // This source item satisfies the filter, so it must be added | ||
1121 | 1113 | source_items_insert.append(source_item); | ||
1122 | 1114 | } | ||
1123 | 1115 | } | ||
1124 | 1116 | } | ||
1125 | 1117 | if (!source_items_remove.isEmpty() || !source_items_insert.isEmpty()) { | ||
1126 | 1118 | // Do item removal and insertion | ||
1127 | 1119 | remove_source_items(source_to_proxy, proxy_to_source, | ||
1128 | 1120 | source_items_remove, source_parent, orient); | ||
1129 | 1121 | if (orient == Qt::Vertical) | ||
1130 | 1122 | sort_source_rows(source_items_insert, source_parent); | ||
1131 | 1123 | insert_source_items(source_to_proxy, proxy_to_source, | ||
1132 | 1124 | source_items_insert, source_parent, orient); | ||
1133 | 1125 | } | ||
1134 | 1126 | return qVectorToSet(source_items_remove); | ||
1135 | 1127 | } | ||
1136 | 1128 | |||
1137 | 1129 | void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &source_top_left, | ||
1138 | 1130 | const QModelIndex &source_bottom_right) | ||
1139 | 1131 | { | ||
1140 | 1132 | Q_Q(QSortFilterProxyModel); | ||
1141 | 1133 | if (!source_top_left.isValid() || !source_bottom_right.isValid()) | ||
1142 | 1134 | return; | ||
1143 | 1135 | QModelIndex source_parent = source_top_left.parent(); | ||
1144 | 1136 | IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); | ||
1145 | 1137 | if (it == source_index_mapping.constEnd()) { | ||
1146 | 1138 | // Don't care, since we don't have mapping for this index | ||
1147 | 1139 | return; | ||
1148 | 1140 | } | ||
1149 | 1141 | Mapping *m = it.value(); | ||
1150 | 1142 | |||
1151 | 1143 | // Figure out how the source changes affect us | ||
1152 | 1144 | QVector<int> source_rows_remove; | ||
1153 | 1145 | QVector<int> source_rows_insert; | ||
1154 | 1146 | QVector<int> source_rows_change; | ||
1155 | 1147 | QVector<int> source_rows_resort; | ||
1156 | 1148 | int end = qMin(source_bottom_right.row(), m->proxy_rows.count() - 1); | ||
1157 | 1149 | for (int source_row = source_top_left.row(); source_row <= end; ++source_row) { | ||
1158 | 1150 | if (dynamic_sortfilter) { | ||
1159 | 1151 | if (m->proxy_rows.at(source_row) != -1) { | ||
1160 | 1152 | if (!q->filterAcceptsRow(source_row, source_parent)) { | ||
1161 | 1153 | // This source row no longer satisfies the filter, so it must be removed | ||
1162 | 1154 | source_rows_remove.append(source_row); | ||
1163 | 1155 | } else if (source_sort_column >= source_top_left.column() && source_sort_column <= source_bottom_right.column()) { | ||
1164 | 1156 | // This source row has changed in a way that may affect sorted order | ||
1165 | 1157 | source_rows_resort.append(source_row); | ||
1166 | 1158 | } else { | ||
1167 | 1159 | // This row has simply changed, without affecting filtering nor sorting | ||
1168 | 1160 | source_rows_change.append(source_row); | ||
1169 | 1161 | } | ||
1170 | 1162 | } else { | ||
1171 | 1163 | if (!itemsBeingRemoved.contains(source_parent, source_row) && q->filterAcceptsRow(source_row, source_parent)) { | ||
1172 | 1164 | // This source row now satisfies the filter, so it must be added | ||
1173 | 1165 | source_rows_insert.append(source_row); | ||
1174 | 1166 | } | ||
1175 | 1167 | } | ||
1176 | 1168 | } else { | ||
1177 | 1169 | if (m->proxy_rows.at(source_row) != -1) | ||
1178 | 1170 | source_rows_change.append(source_row); | ||
1179 | 1171 | } | ||
1180 | 1172 | } | ||
1181 | 1173 | |||
1182 | 1174 | if (!source_rows_remove.isEmpty()) { | ||
1183 | 1175 | remove_source_items(m->proxy_rows, m->source_rows, | ||
1184 | 1176 | source_rows_remove, source_parent, Qt::Vertical); | ||
1185 | 1177 | QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove); | ||
1186 | 1178 | QVector<QModelIndex>::iterator childIt = m->mapped_children.end(); | ||
1187 | 1179 | while (childIt != m->mapped_children.begin()) { | ||
1188 | 1180 | --childIt; | ||
1189 | 1181 | const QModelIndex source_child_index = *childIt; | ||
1190 | 1182 | if (source_rows_remove_set.contains(source_child_index.row())) { | ||
1191 | 1183 | childIt = m->mapped_children.erase(childIt); | ||
1192 | 1184 | remove_from_mapping(source_child_index); | ||
1193 | 1185 | } | ||
1194 | 1186 | } | ||
1195 | 1187 | } | ||
1196 | 1188 | |||
1197 | 1189 | if (!source_rows_resort.isEmpty()) { | ||
1198 | 1190 | // Re-sort the rows of this level | ||
1199 | 1191 | QList<QPersistentModelIndex> parents; | ||
1200 | 1192 | parents << q->mapFromSource(source_parent); | ||
1201 | 1193 | emit q->layoutAboutToBeChanged(parents, QAbstractItemModel::VerticalSortHint); | ||
1202 | 1194 | QModelIndexPairList source_indexes = store_persistent_indexes(); | ||
1203 | 1195 | remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort, | ||
1204 | 1196 | source_parent, Qt::Vertical, false); | ||
1205 | 1197 | sort_source_rows(source_rows_resort, source_parent); | ||
1206 | 1198 | insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort, | ||
1207 | 1199 | source_parent, Qt::Vertical, false); | ||
1208 | 1200 | update_persistent_indexes(source_indexes); | ||
1209 | 1201 | emit q->layoutChanged(parents, QAbstractItemModel::VerticalSortHint); | ||
1210 | 1202 | // Make sure we also emit dataChanged for the rows | ||
1211 | 1203 | source_rows_change += source_rows_resort; | ||
1212 | 1204 | } | ||
1213 | 1205 | |||
1214 | 1206 | if (!source_rows_change.isEmpty()) { | ||
1215 | 1207 | // Find the proxy row range | ||
1216 | 1208 | int proxy_start_row; | ||
1217 | 1209 | int proxy_end_row; | ||
1218 | 1210 | proxy_item_range(m->proxy_rows, source_rows_change, | ||
1219 | 1211 | proxy_start_row, proxy_end_row); | ||
1220 | 1212 | // ### Find the proxy column range also | ||
1221 | 1213 | if (proxy_end_row >= 0) { | ||
1222 | 1214 | // the row was accepted, but some columns might still be filtered out | ||
1223 | 1215 | int source_left_column = source_top_left.column(); | ||
1224 | 1216 | while (source_left_column < source_bottom_right.column() | ||
1225 | 1217 | && m->proxy_columns.at(source_left_column) == -1) | ||
1226 | 1218 | ++source_left_column; | ||
1227 | 1219 | const QModelIndex proxy_top_left = create_index( | ||
1228 | 1220 | proxy_start_row, m->proxy_columns.at(source_left_column), it); | ||
1229 | 1221 | int source_right_column = source_bottom_right.column(); | ||
1230 | 1222 | while (source_right_column > source_top_left.column() | ||
1231 | 1223 | && m->proxy_columns.at(source_right_column) == -1) | ||
1232 | 1224 | --source_right_column; | ||
1233 | 1225 | const QModelIndex proxy_bottom_right = create_index( | ||
1234 | 1226 | proxy_end_row, m->proxy_columns.at(source_right_column), it); | ||
1235 | 1227 | emit q->dataChanged(proxy_top_left, proxy_bottom_right); | ||
1236 | 1228 | } | ||
1237 | 1229 | } | ||
1238 | 1230 | |||
1239 | 1231 | if (!source_rows_insert.isEmpty()) { | ||
1240 | 1232 | sort_source_rows(source_rows_insert, source_parent); | ||
1241 | 1233 | insert_source_items(m->proxy_rows, m->source_rows, | ||
1242 | 1234 | source_rows_insert, source_parent, Qt::Vertical); | ||
1243 | 1235 | } | ||
1244 | 1236 | } | ||
1245 | 1237 | |||
1246 | 1238 | void QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation, | ||
1247 | 1239 | int start, int end) | ||
1248 | 1240 | { | ||
1249 | 1241 | Q_ASSERT(start <= end); | ||
1250 | 1242 | |||
1251 | 1243 | Q_Q(QSortFilterProxyModel); | ||
1252 | 1244 | Mapping *m = create_mapping(QModelIndex()).value(); | ||
1253 | 1245 | |||
1254 | 1246 | const QVector<int> &source_to_proxy = (orientation == Qt::Vertical) ? m->proxy_rows : m->proxy_columns; | ||
1255 | 1247 | |||
1256 | 1248 | QVector<int> proxy_positions; | ||
1257 | 1249 | proxy_positions.reserve(end - start + 1); | ||
1258 | 1250 | { | ||
1259 | 1251 | Q_ASSERT(source_to_proxy.size() > end); | ||
1260 | 1252 | QVector<int>::const_iterator it = source_to_proxy.constBegin() + start; | ||
1261 | 1253 | const QVector<int>::const_iterator endIt = source_to_proxy.constBegin() + end + 1; | ||
1262 | 1254 | for ( ; it != endIt; ++it) { | ||
1263 | 1255 | if (*it != -1) | ||
1264 | 1256 | proxy_positions.push_back(*it); | ||
1265 | 1257 | } | ||
1266 | 1258 | } | ||
1267 | 1259 | |||
1268 | 1260 | std::sort(proxy_positions.begin(), proxy_positions.end()); | ||
1269 | 1261 | |||
1270 | 1262 | int last_index = 0; | ||
1271 | 1263 | const int numItems = proxy_positions.size(); | ||
1272 | 1264 | while (last_index < numItems) { | ||
1273 | 1265 | const int proxyStart = proxy_positions.at(last_index); | ||
1274 | 1266 | int proxyEnd = proxyStart; | ||
1275 | 1267 | ++last_index; | ||
1276 | 1268 | for (int i = last_index; i < numItems; ++i) { | ||
1277 | 1269 | if (proxy_positions.at(i) == proxyEnd + 1) { | ||
1278 | 1270 | ++last_index; | ||
1279 | 1271 | ++proxyEnd; | ||
1280 | 1272 | } else { | ||
1281 | 1273 | break; | ||
1282 | 1274 | } | ||
1283 | 1275 | } | ||
1284 | 1276 | emit q->headerDataChanged(orientation, proxyStart, proxyEnd); | ||
1285 | 1277 | } | ||
1286 | 1278 | } | ||
1287 | 1279 | |||
1288 | 1280 | void QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset() | ||
1289 | 1281 | { | ||
1290 | 1282 | Q_Q(QSortFilterProxyModel); | ||
1291 | 1283 | q->beginResetModel(); | ||
1292 | 1284 | } | ||
1293 | 1285 | |||
1294 | 1286 | void QSortFilterProxyModelPrivate::_q_sourceReset() | ||
1295 | 1287 | { | ||
1296 | 1288 | Q_Q(QSortFilterProxyModel); | ||
1297 | 1289 | invalidatePersistentIndexes(); | ||
1298 | 1290 | _q_clearMapping(); | ||
1299 | 1291 | // All internal structures are deleted in clear() | ||
1300 | 1292 | q->endResetModel(); | ||
1301 | 1293 | update_source_sort_column(); | ||
1302 | 1294 | if (dynamic_sortfilter) | ||
1303 | 1295 | sort(); | ||
1304 | 1296 | } | ||
1305 | 1297 | |||
1306 | 1298 | void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint) | ||
1307 | 1299 | { | ||
1308 | 1300 | Q_Q(QSortFilterProxyModel); | ||
1309 | 1301 | saved_persistent_indexes.clear(); | ||
1310 | 1302 | |||
1311 | 1303 | QList<QPersistentModelIndex> parents; | ||
1312 | 1304 | foreach (const QPersistentModelIndex &parent, sourceParents) { | ||
1313 | 1305 | if (!parent.isValid()) { | ||
1314 | 1306 | parents << QPersistentModelIndex(); | ||
1315 | 1307 | continue; | ||
1316 | 1308 | } | ||
1317 | 1309 | const QModelIndex mappedParent = q->mapFromSource(parent); | ||
1318 | 1310 | // Might be filtered out. | ||
1319 | 1311 | if (mappedParent.isValid()) | ||
1320 | 1312 | parents << mappedParent; | ||
1321 | 1313 | } | ||
1322 | 1314 | |||
1323 | 1315 | // All parents filtered out. | ||
1324 | 1316 | if (!sourceParents.isEmpty() && parents.isEmpty()) | ||
1325 | 1317 | return; | ||
1326 | 1318 | |||
1327 | 1319 | emit q->layoutAboutToBeChanged(parents, hint); | ||
1328 | 1320 | if (persistent.indexes.isEmpty()) | ||
1329 | 1321 | return; | ||
1330 | 1322 | |||
1331 | 1323 | saved_persistent_indexes = store_persistent_indexes(); | ||
1332 | 1324 | } | ||
1333 | 1325 | |||
1334 | 1326 | void QSortFilterProxyModelPrivate::_q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint) | ||
1335 | 1327 | { | ||
1336 | 1328 | Q_Q(QSortFilterProxyModel); | ||
1337 | 1329 | |||
1338 | 1330 | // Optimize: We only actually have to clear the mapping related to the contents of | ||
1339 | 1331 | // sourceParents, not everything. | ||
1340 | 1332 | qDeleteAll(source_index_mapping); | ||
1341 | 1333 | source_index_mapping.clear(); | ||
1342 | 1334 | |||
1343 | 1335 | update_persistent_indexes(saved_persistent_indexes); | ||
1344 | 1336 | saved_persistent_indexes.clear(); | ||
1345 | 1337 | |||
1346 | 1338 | if (dynamic_sortfilter && update_source_sort_column()) { | ||
1347 | 1339 | //update_source_sort_column might have created wrong mapping so we have to clear it again | ||
1348 | 1340 | qDeleteAll(source_index_mapping); | ||
1349 | 1341 | source_index_mapping.clear(); | ||
1350 | 1342 | } | ||
1351 | 1343 | |||
1352 | 1344 | QList<QPersistentModelIndex> parents; | ||
1353 | 1345 | foreach (const QPersistentModelIndex &parent, sourceParents) { | ||
1354 | 1346 | if (!parent.isValid()) { | ||
1355 | 1347 | parents << QPersistentModelIndex(); | ||
1356 | 1348 | continue; | ||
1357 | 1349 | } | ||
1358 | 1350 | const QModelIndex mappedParent = q->mapFromSource(parent); | ||
1359 | 1351 | if (mappedParent.isValid()) | ||
1360 | 1352 | parents << mappedParent; | ||
1361 | 1353 | } | ||
1362 | 1354 | |||
1363 | 1355 | if (!sourceParents.isEmpty() && parents.isEmpty()) | ||
1364 | 1356 | return; | ||
1365 | 1357 | |||
1366 | 1358 | emit q->layoutChanged(parents, hint); | ||
1367 | 1359 | } | ||
1368 | 1360 | |||
1369 | 1361 | void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted( | ||
1370 | 1362 | const QModelIndex &source_parent, int start, int end) | ||
1371 | 1363 | { | ||
1372 | 1364 | Q_UNUSED(start); | ||
1373 | 1365 | Q_UNUSED(end); | ||
1374 | 1366 | //Force the creation of a mapping now, even if its empty. | ||
1375 | 1367 | //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items | ||
1376 | 1368 | if (can_create_mapping(source_parent)) | ||
1377 | 1369 | create_mapping(source_parent); | ||
1378 | 1370 | } | ||
1379 | 1371 | |||
1380 | 1372 | void QSortFilterProxyModelPrivate::_q_sourceRowsInserted( | ||
1381 | 1373 | const QModelIndex &source_parent, int start, int end) | ||
1382 | 1374 | { | ||
1383 | 1375 | source_items_inserted(source_parent, start, end, Qt::Vertical); | ||
1384 | 1376 | if (update_source_sort_column() && dynamic_sortfilter) //previous call to update_source_sort_column may fail if the model has no column. | ||
1385 | 1377 | sort(); // now it should succeed so we need to make sure to sort again | ||
1386 | 1378 | } | ||
1387 | 1379 | |||
1388 | 1380 | void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved( | ||
1389 | 1381 | const QModelIndex &source_parent, int start, int end) | ||
1390 | 1382 | { | ||
1391 | 1383 | itemsBeingRemoved = QRowsRemoval(source_parent, start, end); | ||
1392 | 1384 | source_items_about_to_be_removed(source_parent, start, end, | ||
1393 | 1385 | Qt::Vertical); | ||
1394 | 1386 | } | ||
1395 | 1387 | |||
1396 | 1388 | void QSortFilterProxyModelPrivate::_q_sourceRowsRemoved( | ||
1397 | 1389 | const QModelIndex &source_parent, int start, int end) | ||
1398 | 1390 | { | ||
1399 | 1391 | itemsBeingRemoved = QRowsRemoval(); | ||
1400 | 1392 | source_items_removed(source_parent, start, end, Qt::Vertical); | ||
1401 | 1393 | } | ||
1402 | 1394 | |||
1403 | 1395 | void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeMoved( | ||
1404 | 1396 | const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */) | ||
1405 | 1397 | { | ||
1406 | 1398 | Q_Q(QSortFilterProxyModel); | ||
1407 | 1399 | // Because rows which are contiguous in the source model might not be contiguous | ||
1408 | 1400 | // in the proxy due to sorting, the best thing we can do here is be specific about what | ||
1409 | 1401 | // parents are having their children changed. | ||
1410 | 1402 | // Optimize: Emit move signals if the proxy is not sorted. Will need to account for rows | ||
1411 | 1403 | // being filtered out though. | ||
1412 | 1404 | |||
1413 | 1405 | saved_persistent_indexes.clear(); | ||
1414 | 1406 | |||
1415 | 1407 | QList<QPersistentModelIndex> parents; | ||
1416 | 1408 | parents << q->mapFromSource(sourceParent); | ||
1417 | 1409 | if (sourceParent != destParent) | ||
1418 | 1410 | parents << q->mapFromSource(destParent); | ||
1419 | 1411 | emit q->layoutAboutToBeChanged(parents); | ||
1420 | 1412 | if (persistent.indexes.isEmpty()) | ||
1421 | 1413 | return; | ||
1422 | 1414 | saved_persistent_indexes = store_persistent_indexes(); | ||
1423 | 1415 | } | ||
1424 | 1416 | |||
1425 | 1417 | void QSortFilterProxyModelPrivate::_q_sourceRowsMoved( | ||
1426 | 1418 | const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */) | ||
1427 | 1419 | { | ||
1428 | 1420 | Q_Q(QSortFilterProxyModel); | ||
1429 | 1421 | |||
1430 | 1422 | // Optimize: We only need to clear and update the persistent indexes which are children of | ||
1431 | 1423 | // sourceParent or destParent | ||
1432 | 1424 | qDeleteAll(source_index_mapping); | ||
1433 | 1425 | source_index_mapping.clear(); | ||
1434 | 1426 | |||
1435 | 1427 | update_persistent_indexes(saved_persistent_indexes); | ||
1436 | 1428 | saved_persistent_indexes.clear(); | ||
1437 | 1429 | |||
1438 | 1430 | if (dynamic_sortfilter && update_source_sort_column()) { | ||
1439 | 1431 | //update_source_sort_column might have created wrong mapping so we have to clear it again | ||
1440 | 1432 | qDeleteAll(source_index_mapping); | ||
1441 | 1433 | source_index_mapping.clear(); | ||
1442 | 1434 | } | ||
1443 | 1435 | |||
1444 | 1436 | QList<QPersistentModelIndex> parents; | ||
1445 | 1437 | parents << q->mapFromSource(sourceParent); | ||
1446 | 1438 | if (sourceParent != destParent) | ||
1447 | 1439 | parents << q->mapFromSource(destParent); | ||
1448 | 1440 | emit q->layoutChanged(parents); | ||
1449 | 1441 | } | ||
1450 | 1442 | |||
1451 | 1443 | void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted( | ||
1452 | 1444 | const QModelIndex &source_parent, int start, int end) | ||
1453 | 1445 | { | ||
1454 | 1446 | Q_UNUSED(start); | ||
1455 | 1447 | Q_UNUSED(end); | ||
1456 | 1448 | //Force the creation of a mapping now, even if its empty. | ||
1457 | 1449 | //We need it because the proxy can be acessed at the moment it emits columnsAboutToBeInserted in insert_source_items | ||
1458 | 1450 | if (can_create_mapping(source_parent)) | ||
1459 | 1451 | create_mapping(source_parent); | ||
1460 | 1452 | } | ||
1461 | 1453 | |||
1462 | 1454 | void QSortFilterProxyModelPrivate::_q_sourceColumnsInserted( | ||
1463 | 1455 | const QModelIndex &source_parent, int start, int end) | ||
1464 | 1456 | { | ||
1465 | 1457 | Q_Q(const QSortFilterProxyModel); | ||
1466 | 1458 | source_items_inserted(source_parent, start, end, Qt::Horizontal); | ||
1467 | 1459 | |||
1468 | 1460 | if (source_parent.isValid()) | ||
1469 | 1461 | return; //we sort according to the root column only | ||
1470 | 1462 | if (source_sort_column == -1) { | ||
1471 | 1463 | //we update the source_sort_column depending on the proxy_sort_column | ||
1472 | 1464 | if (update_source_sort_column() && dynamic_sortfilter) | ||
1473 | 1465 | sort(); | ||
1474 | 1466 | } else { | ||
1475 | 1467 | if (start <= source_sort_column) | ||
1476 | 1468 | source_sort_column += end - start + 1; | ||
1477 | 1469 | |||
1478 | 1470 | proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column(); | ||
1479 | 1471 | } | ||
1480 | 1472 | } | ||
1481 | 1473 | |||
1482 | 1474 | void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved( | ||
1483 | 1475 | const QModelIndex &source_parent, int start, int end) | ||
1484 | 1476 | { | ||
1485 | 1477 | source_items_about_to_be_removed(source_parent, start, end, | ||
1486 | 1478 | Qt::Horizontal); | ||
1487 | 1479 | } | ||
1488 | 1480 | |||
1489 | 1481 | void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved( | ||
1490 | 1482 | const QModelIndex &source_parent, int start, int end) | ||
1491 | 1483 | { | ||
1492 | 1484 | Q_Q(const QSortFilterProxyModel); | ||
1493 | 1485 | source_items_removed(source_parent, start, end, Qt::Horizontal); | ||
1494 | 1486 | |||
1495 | 1487 | if (source_parent.isValid()) | ||
1496 | 1488 | return; //we sort according to the root column only | ||
1497 | 1489 | if (start <= source_sort_column) { | ||
1498 | 1490 | if (end < source_sort_column) | ||
1499 | 1491 | source_sort_column -= end - start + 1; | ||
1500 | 1492 | else | ||
1501 | 1493 | source_sort_column = -1; | ||
1502 | 1494 | } | ||
1503 | 1495 | |||
1504 | 1496 | proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column(); | ||
1505 | 1497 | } | ||
1506 | 1498 | |||
1507 | 1499 | void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeMoved( | ||
1508 | 1500 | const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */) | ||
1509 | 1501 | { | ||
1510 | 1502 | Q_Q(QSortFilterProxyModel); | ||
1511 | 1503 | |||
1512 | 1504 | saved_persistent_indexes.clear(); | ||
1513 | 1505 | |||
1514 | 1506 | QList<QPersistentModelIndex> parents; | ||
1515 | 1507 | parents << q->mapFromSource(sourceParent); | ||
1516 | 1508 | if (sourceParent != destParent) | ||
1517 | 1509 | parents << q->mapFromSource(destParent); | ||
1518 | 1510 | emit q->layoutAboutToBeChanged(parents); | ||
1519 | 1511 | |||
1520 | 1512 | if (persistent.indexes.isEmpty()) | ||
1521 | 1513 | return; | ||
1522 | 1514 | saved_persistent_indexes = store_persistent_indexes(); | ||
1523 | 1515 | } | ||
1524 | 1516 | |||
1525 | 1517 | void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved( | ||
1526 | 1518 | const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */) | ||
1527 | 1519 | { | ||
1528 | 1520 | Q_Q(QSortFilterProxyModel); | ||
1529 | 1521 | |||
1530 | 1522 | qDeleteAll(source_index_mapping); | ||
1531 | 1523 | source_index_mapping.clear(); | ||
1532 | 1524 | |||
1533 | 1525 | update_persistent_indexes(saved_persistent_indexes); | ||
1534 | 1526 | saved_persistent_indexes.clear(); | ||
1535 | 1527 | |||
1536 | 1528 | if (dynamic_sortfilter && update_source_sort_column()) { | ||
1537 | 1529 | qDeleteAll(source_index_mapping); | ||
1538 | 1530 | source_index_mapping.clear(); | ||
1539 | 1531 | } | ||
1540 | 1532 | |||
1541 | 1533 | QList<QPersistentModelIndex> parents; | ||
1542 | 1534 | parents << q->mapFromSource(sourceParent); | ||
1543 | 1535 | if (sourceParent != destParent) | ||
1544 | 1536 | parents << q->mapFromSource(destParent); | ||
1545 | 1537 | emit q->layoutChanged(parents); | ||
1546 | 1538 | } | ||
1547 | 1539 | |||
1548 | 1540 | /*! | ||
1549 | 1541 | \since 4.1 | ||
1550 | 1542 | \class QSortFilterProxyModel | ||
1551 | 1543 | \inmodule QtCore | ||
1552 | 1544 | \brief The QSortFilterProxyModel class provides support for sorting and | ||
1553 | 1545 | filtering data passed between another model and a view. | ||
1554 | 1546 | |||
1555 | 1547 | \ingroup model-view | ||
1556 | 1548 | |||
1557 | 1549 | QSortFilterProxyModel can be used for sorting items, filtering out items, | ||
1558 | 1550 | or both. The model transforms the structure of a source model by mapping | ||
1559 | 1551 | the model indexes it supplies to new indexes, corresponding to different | ||
1560 | 1552 | locations, for views to use. This approach allows a given source model to | ||
1561 | 1553 | be restructured as far as views are concerned without requiring any | ||
1562 | 1554 | transformations on the underlying data, and without duplicating the data in | ||
1563 | 1555 | memory. | ||
1564 | 1556 | |||
1565 | 1557 | Let's assume that we want to sort and filter the items provided by a custom | ||
1566 | 1558 | model. The code to set up the model and the view, \e without sorting and | ||
1567 | 1559 | filtering, would look like this: | ||
1568 | 1560 | |||
1569 | 1561 | \snippet qsortfilterproxymodel-details/main.cpp 1 | ||
1570 | 1562 | |||
1571 | 1563 | To add sorting and filtering support to \c MyItemModel, we need to create | ||
1572 | 1564 | a QSortFilterProxyModel, call setSourceModel() with the \c MyItemModel as | ||
1573 | 1565 | argument, and install the QSortFilterProxyModel on the view: | ||
1574 | 1566 | |||
1575 | 1567 | \snippet qsortfilterproxymodel-details/main.cpp 0 | ||
1576 | 1568 | \snippet qsortfilterproxymodel-details/main.cpp 2 | ||
1577 | 1569 | |||
1578 | 1570 | At this point, neither sorting nor filtering is enabled; the original data | ||
1579 | 1571 | is displayed in the view. Any changes made through the | ||
1580 | 1572 | QSortFilterProxyModel are applied to the original model. | ||
1581 | 1573 | |||
1582 | 1574 | The QSortFilterProxyModel acts as a wrapper for the original model. If you | ||
1583 | 1575 | need to convert source \l{QModelIndex}es to sorted/filtered model indexes | ||
1584 | 1576 | or vice versa, use mapToSource(), mapFromSource(), mapSelectionToSource(), | ||
1585 | 1577 | and mapSelectionFromSource(). | ||
1586 | 1578 | |||
1587 | 1579 | \note By default, the model dynamically re-sorts and re-filters data | ||
1588 | 1580 | whenever the original model changes. This behavior can be changed by | ||
1589 | 1581 | setting the \l{QSortFilterProxyModel::dynamicSortFilter}{dynamicSortFilter} | ||
1590 | 1582 | property. | ||
1591 | 1583 | |||
1592 | 1584 | The \l{itemviews/basicsortfiltermodel}{Basic Sort/Filter Model} and | ||
1593 | 1585 | \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model} examples | ||
1594 | 1586 | illustrate how to use QSortFilterProxyModel to perform basic sorting and | ||
1595 | 1587 | filtering and how to subclass it to implement custom behavior. | ||
1596 | 1588 | |||
1597 | 1589 | \section1 Sorting | ||
1598 | 1590 | |||
1599 | 1591 | QTableView and QTreeView have a | ||
1600 | 1592 | \l{QTreeView::sortingEnabled}{sortingEnabled} property that controls | ||
1601 | 1593 | whether the user can sort the view by clicking the view's horizontal | ||
1602 | 1594 | header. For example: | ||
1603 | 1595 | |||
1604 | 1596 | \snippet qsortfilterproxymodel-details/main.cpp 3 | ||
1605 | 1597 | |||
1606 | 1598 | When this feature is on (the default is off), clicking on a header section | ||
1607 | 1599 | sorts the items according to that column. By clicking repeatedly, the user | ||
1608 | 1600 | can alternate between ascending and descending order. | ||
1609 | 1601 | |||
1610 | 1602 | \image qsortfilterproxymodel-sorting.png A sorted QTreeView | ||
1611 | 1603 | |||
1612 | 1604 | Behind the scene, the view calls the sort() virtual function on the model | ||
1613 | 1605 | to reorder the data in the model. To make your data sortable, you can | ||
1614 | 1606 | either implement sort() in your model, or use a QSortFilterProxyModel to | ||
1615 | 1607 | wrap your model -- QSortFilterProxyModel provides a generic sort() | ||
1616 | 1608 | reimplementation that operates on the sortRole() (Qt::DisplayRole by | ||
1617 | 1609 | default) of the items and that understands several data types, including | ||
1618 | 1610 | \c int, QString, and QDateTime. For hierarchical models, sorting is applied | ||
1619 | 1611 | recursively to all child items. String comparisons are case sensitive by | ||
1620 | 1612 | default; this can be changed by setting the \l{QSortFilterProxyModel::} | ||
1621 | 1613 | {sortCaseSensitivity} property. | ||
1622 | 1614 | |||
1623 | 1615 | Custom sorting behavior is achieved by subclassing | ||
1624 | 1616 | QSortFilterProxyModel and reimplementing lessThan(), which is | ||
1625 | 1617 | used to compare items. For example: | ||
1626 | 1618 | |||
1627 | 1619 | \snippet ../widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 5 | ||
1628 | 1620 | |||
1629 | 1621 | (This code snippet comes from the | ||
1630 | 1622 | \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model} | ||
1631 | 1623 | example.) | ||
1632 | 1624 | |||
1633 | 1625 | An alternative approach to sorting is to disable sorting on the view and to | ||
1634 | 1626 | impose a certain order to the user. This is done by explicitly calling | ||
1635 | 1627 | sort() with the desired column and order as arguments on the | ||
1636 | 1628 | QSortFilterProxyModel (or on the original model if it implements sort()). | ||
1637 | 1629 | For example: | ||
1638 | 1630 | |||
1639 | 1631 | \snippet qsortfilterproxymodel-details/main.cpp 4 | ||
1640 | 1632 | |||
1641 | 1633 | QSortFilterProxyModel can be sorted by column -1, in which case it returns | ||
1642 | 1634 | to the sort order of the underlying source model. | ||
1643 | 1635 | |||
1644 | 1636 | \section1 Filtering | ||
1645 | 1637 | |||
1646 | 1638 | In addition to sorting, QSortFilterProxyModel can be used to hide items | ||
1647 | 1639 | that do not match a certain filter. The filter is specified using a QRegExp | ||
1648 | 1640 | object and is applied to the filterRole() (Qt::DisplayRole by default) of | ||
1649 | 1641 | each item, for a given column. The QRegExp object can be used to match a | ||
1650 | 1642 | regular expression, a wildcard pattern, or a fixed string. For example: | ||
1651 | 1643 | |||
1652 | 1644 | \snippet qsortfilterproxymodel-details/main.cpp 5 | ||
1653 | 1645 | |||
1654 | 1646 | For hierarchical models, the filter is applied recursively to all children. | ||
1655 | 1647 | If a parent item doesn't match the filter, none of its children will be | ||
1656 | 1648 | shown. | ||
1657 | 1649 | |||
1658 | 1650 | A common use case is to let the user specify the filter regexp, wildcard | ||
1659 | 1651 | pattern, or fixed string in a QLineEdit and to connect the | ||
1660 | 1652 | \l{QLineEdit::textChanged()}{textChanged()} signal to setFilterRegExp(), | ||
1661 | 1653 | setFilterWildcard(), or setFilterFixedString() to reapply the filter. | ||
1662 | 1654 | |||
1663 | 1655 | Custom filtering behavior can be achieved by reimplementing the | ||
1664 | 1656 | filterAcceptsRow() and filterAcceptsColumn() functions. For | ||
1665 | 1657 | example (from the \l{itemviews/customsortfiltermodel} | ||
1666 | 1658 | {Custom Sort/Filter Model} example), the following implementation ignores | ||
1667 | 1659 | the \l{QSortFilterProxyModel::filterKeyColumn}{filterKeyColumn} property | ||
1668 | 1660 | and performs filtering on columns 0, 1, and 2: | ||
1669 | 1661 | |||
1670 | 1662 | \snippet ../widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 3 | ||
1671 | 1663 | |||
1672 | 1664 | (This code snippet comes from the | ||
1673 | 1665 | \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model} | ||
1674 | 1666 | example.) | ||
1675 | 1667 | |||
1676 | 1668 | If you are working with large amounts of filtering and have to invoke | ||
1677 | 1669 | invalidateFilter() repeatedly, using reset() may be more efficient, | ||
1678 | 1670 | depending on the implementation of your model. However, reset() returns the | ||
1679 | 1671 | proxy model to its original state, losing selection information, and will | ||
1680 | 1672 | cause the proxy model to be repopulated. | ||
1681 | 1673 | |||
1682 | 1674 | \section1 Subclassing | ||
1683 | 1675 | |||
1684 | 1676 | Since QAbstractProxyModel and its subclasses are derived from | ||
1685 | 1677 | QAbstractItemModel, much of the same advice about subclassing normal models | ||
1686 | 1678 | also applies to proxy models. In addition, it is worth noting that many of | ||
1687 | 1679 | the default implementations of functions in this class are written so that | ||
1688 | 1680 | they call the equivalent functions in the relevant source model. This | ||
1689 | 1681 | simple proxying mechanism may need to be overridden for source models with | ||
1690 | 1682 | more complex behavior; for example, if the source model provides a custom | ||
1691 | 1683 | hasChildren() implementation, you should also provide one in the proxy | ||
1692 | 1684 | model. | ||
1693 | 1685 | |||
1694 | 1686 | \note Some general guidelines for subclassing models are available in the | ||
1695 | 1687 | \l{Model Subclassing Reference}. | ||
1696 | 1688 | |||
1697 | 1689 | \sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming}, | ||
1698 | 1690 | {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example}, QIdentityProxyModel | ||
1699 | 1691 | */ | ||
1700 | 1692 | |||
1701 | 1693 | /*! | ||
1702 | 1694 | Constructs a sorting filter model with the given \a parent. | ||
1703 | 1695 | */ | ||
1704 | 1696 | |||
1705 | 1697 | QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent) | ||
1706 | 1698 | : QAbstractProxyModel(*new QSortFilterProxyModelPrivate, parent) | ||
1707 | 1699 | { | ||
1708 | 1700 | Q_D(QSortFilterProxyModel); | ||
1709 | 1701 | d->proxy_sort_column = d->source_sort_column = -1; | ||
1710 | 1702 | d->sort_order = Qt::AscendingOrder; | ||
1711 | 1703 | d->sort_casesensitivity = Qt::CaseSensitive; | ||
1712 | 1704 | d->sort_role = Qt::DisplayRole; | ||
1713 | 1705 | d->sort_localeaware = false; | ||
1714 | 1706 | d->filter_column = 0; | ||
1715 | 1707 | d->filter_role = Qt::DisplayRole; | ||
1716 | 1708 | d->dynamic_sortfilter = true; | ||
1717 | 1709 | connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping())); | ||
1718 | 1710 | } | ||
1719 | 1711 | |||
1720 | 1712 | /*! | ||
1721 | 1713 | Destroys this sorting filter model. | ||
1722 | 1714 | */ | ||
1723 | 1715 | QSortFilterProxyModel::~QSortFilterProxyModel() | ||
1724 | 1716 | { | ||
1725 | 1717 | Q_D(QSortFilterProxyModel); | ||
1726 | 1718 | qDeleteAll(d->source_index_mapping); | ||
1727 | 1719 | d->source_index_mapping.clear(); | ||
1728 | 1720 | } | ||
1729 | 1721 | |||
1730 | 1722 | /*! | ||
1731 | 1723 | \reimp | ||
1732 | 1724 | */ | ||
1733 | 1725 | void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) | ||
1734 | 1726 | { | ||
1735 | 1727 | Q_D(QSortFilterProxyModel); | ||
1736 | 1728 | |||
1737 | 1729 | beginResetModel(); | ||
1738 | 1730 | |||
1739 | 1731 | disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), | ||
1740 | 1732 | this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex))); | ||
1741 | 1733 | |||
1742 | 1734 | disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), | ||
1743 | 1735 | this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); | ||
1744 | 1736 | |||
1745 | 1737 | disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), | ||
1746 | 1738 | this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int))); | ||
1747 | 1739 | |||
1748 | 1740 | disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), | ||
1749 | 1741 | this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int))); | ||
1750 | 1742 | |||
1751 | 1743 | disconnect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), | ||
1752 | 1744 | this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int))); | ||
1753 | 1745 | |||
1754 | 1746 | disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)), | ||
1755 | 1747 | this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int))); | ||
1756 | 1748 | |||
1757 | 1749 | disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), | ||
1758 | 1750 | this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int))); | ||
1759 | 1751 | |||
1760 | 1752 | disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), | ||
1761 | 1753 | this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int))); | ||
1762 | 1754 | |||
1763 | 1755 | disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), | ||
1764 | 1756 | this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int))); | ||
1765 | 1757 | |||
1766 | 1758 | disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)), | ||
1767 | 1759 | this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int))); | ||
1768 | 1760 | |||
1769 | 1761 | disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), | ||
1770 | 1762 | this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); | ||
1771 | 1763 | |||
1772 | 1764 | disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), | ||
1773 | 1765 | this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))); | ||
1774 | 1766 | |||
1775 | 1767 | disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), | ||
1776 | 1768 | this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); | ||
1777 | 1769 | |||
1778 | 1770 | disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), | ||
1779 | 1771 | this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int))); | ||
1780 | 1772 | |||
1781 | 1773 | disconnect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), | ||
1782 | 1774 | this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); | ||
1783 | 1775 | |||
1784 | 1776 | disconnect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), | ||
1785 | 1777 | this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); | ||
1786 | 1778 | |||
1787 | 1779 | disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset())); | ||
1788 | 1780 | disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); | ||
1789 | 1781 | |||
1790 | 1782 | QAbstractProxyModel::setSourceModel(sourceModel); | ||
1791 | 1783 | |||
1792 | 1784 | connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), | ||
1793 | 1785 | this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex))); | ||
1794 | 1786 | |||
1795 | 1787 | connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), | ||
1796 | 1788 | this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); | ||
1797 | 1789 | |||
1798 | 1790 | connect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), | ||
1799 | 1791 | this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int))); | ||
1800 | 1792 | |||
1801 | 1793 | connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), | ||
1802 | 1794 | this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int))); | ||
1803 | 1795 | |||
1804 | 1796 | connect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), | ||
1805 | 1797 | this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int))); | ||
1806 | 1798 | |||
1807 | 1799 | connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)), | ||
1808 | 1800 | this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int))); | ||
1809 | 1801 | |||
1810 | 1802 | connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), | ||
1811 | 1803 | this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int))); | ||
1812 | 1804 | |||
1813 | 1805 | connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), | ||
1814 | 1806 | this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int))); | ||
1815 | 1807 | |||
1816 | 1808 | connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), | ||
1817 | 1809 | this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int))); | ||
1818 | 1810 | |||
1819 | 1811 | connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)), | ||
1820 | 1812 | this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int))); | ||
1821 | 1813 | |||
1822 | 1814 | connect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), | ||
1823 | 1815 | this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); | ||
1824 | 1816 | |||
1825 | 1817 | connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), | ||
1826 | 1818 | this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))); | ||
1827 | 1819 | |||
1828 | 1820 | connect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), | ||
1829 | 1821 | this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); | ||
1830 | 1822 | |||
1831 | 1823 | connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), | ||
1832 | 1824 | this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int))); | ||
1833 | 1825 | |||
1834 | 1826 | connect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), | ||
1835 | 1827 | this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); | ||
1836 | 1828 | |||
1837 | 1829 | connect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), | ||
1838 | 1830 | this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); | ||
1839 | 1831 | |||
1840 | 1832 | connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset())); | ||
1841 | 1833 | connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); | ||
1842 | 1834 | |||
1843 | 1835 | d->_q_clearMapping(); | ||
1844 | 1836 | endResetModel(); | ||
1845 | 1837 | if (d->update_source_sort_column() && d->dynamic_sortfilter) | ||
1846 | 1838 | d->sort(); | ||
1847 | 1839 | } | ||
1848 | 1840 | |||
1849 | 1841 | /*! | ||
1850 | 1842 | \reimp | ||
1851 | 1843 | */ | ||
1852 | 1844 | QModelIndex QSortFilterProxyModel::index(int row, int column, const QModelIndex &parent) const | ||
1853 | 1845 | { | ||
1854 | 1846 | Q_D(const QSortFilterProxyModel); | ||
1855 | 1847 | if (row < 0 || column < 0) | ||
1856 | 1848 | return QModelIndex(); | ||
1857 | 1849 | |||
1858 | 1850 | QModelIndex source_parent = mapToSource(parent); // parent is already mapped at this point | ||
1859 | 1851 | IndexMap::const_iterator it = d->create_mapping(source_parent); // but make sure that the children are mapped | ||
1860 | 1852 | if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column) | ||
1861 | 1853 | return QModelIndex(); | ||
1862 | 1854 | |||
1863 | 1855 | return d->create_index(row, column, it); | ||
1864 | 1856 | } | ||
1865 | 1857 | |||
1866 | 1858 | /*! | ||
1867 | 1859 | \reimp | ||
1868 | 1860 | */ | ||
1869 | 1861 | QModelIndex QSortFilterProxyModel::parent(const QModelIndex &child) const | ||
1870 | 1862 | { | ||
1871 | 1863 | Q_D(const QSortFilterProxyModel); | ||
1872 | 1864 | if (!d->indexValid(child)) | ||
1873 | 1865 | return QModelIndex(); | ||
1874 | 1866 | IndexMap::const_iterator it = d->index_to_iterator(child); | ||
1875 | 1867 | Q_ASSERT(it != d->source_index_mapping.constEnd()); | ||
1876 | 1868 | QModelIndex source_parent = it.key(); | ||
1877 | 1869 | QModelIndex proxy_parent = mapFromSource(source_parent); | ||
1878 | 1870 | return proxy_parent; | ||
1879 | 1871 | } | ||
1880 | 1872 | |||
1881 | 1873 | /*! | ||
1882 | 1874 | \reimp | ||
1883 | 1875 | */ | ||
1884 | 1876 | QModelIndex QSortFilterProxyModel::sibling(int row, int column, const QModelIndex &idx) const | ||
1885 | 1877 | { | ||
1886 | 1878 | Q_D(const QSortFilterProxyModel); | ||
1887 | 1879 | if (!d->indexValid(idx)) | ||
1888 | 1880 | return QModelIndex(); | ||
1889 | 1881 | |||
1890 | 1882 | const IndexMap::const_iterator it = d->index_to_iterator(idx); | ||
1891 | 1883 | if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column) | ||
1892 | 1884 | return QModelIndex(); | ||
1893 | 1885 | |||
1894 | 1886 | return d->create_index(row, column, it); | ||
1895 | 1887 | } | ||
1896 | 1888 | |||
1897 | 1889 | /*! | ||
1898 | 1890 | \reimp | ||
1899 | 1891 | */ | ||
1900 | 1892 | int QSortFilterProxyModel::rowCount(const QModelIndex &parent) const | ||
1901 | 1893 | { | ||
1902 | 1894 | Q_D(const QSortFilterProxyModel); | ||
1903 | 1895 | QModelIndex source_parent = mapToSource(parent); | ||
1904 | 1896 | if (parent.isValid() && !source_parent.isValid()) | ||
1905 | 1897 | return 0; | ||
1906 | 1898 | IndexMap::const_iterator it = d->create_mapping(source_parent); | ||
1907 | 1899 | return it.value()->source_rows.count(); | ||
1908 | 1900 | } | ||
1909 | 1901 | |||
1910 | 1902 | /*! | ||
1911 | 1903 | \reimp | ||
1912 | 1904 | */ | ||
1913 | 1905 | int QSortFilterProxyModel::columnCount(const QModelIndex &parent) const | ||
1914 | 1906 | { | ||
1915 | 1907 | Q_D(const QSortFilterProxyModel); | ||
1916 | 1908 | QModelIndex source_parent = mapToSource(parent); | ||
1917 | 1909 | if (parent.isValid() && !source_parent.isValid()) | ||
1918 | 1910 | return 0; | ||
1919 | 1911 | IndexMap::const_iterator it = d->create_mapping(source_parent); | ||
1920 | 1912 | return it.value()->source_columns.count(); | ||
1921 | 1913 | } | ||
1922 | 1914 | |||
1923 | 1915 | /*! | ||
1924 | 1916 | \reimp | ||
1925 | 1917 | */ | ||
1926 | 1918 | bool QSortFilterProxyModel::hasChildren(const QModelIndex &parent) const | ||
1927 | 1919 | { | ||
1928 | 1920 | Q_D(const QSortFilterProxyModel); | ||
1929 | 1921 | QModelIndex source_parent = mapToSource(parent); | ||
1930 | 1922 | if (parent.isValid() && !source_parent.isValid()) | ||
1931 | 1923 | return false; | ||
1932 | 1924 | if (!d->model->hasChildren(source_parent)) | ||
1933 | 1925 | return false; | ||
1934 | 1926 | |||
1935 | 1927 | if (d->model->canFetchMore(source_parent)) | ||
1936 | 1928 | return true; //we assume we might have children that can be fetched | ||
1937 | 1929 | |||
1938 | 1930 | QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value(); | ||
1939 | 1931 | return m->source_rows.count() != 0 && m->source_columns.count() != 0; | ||
1940 | 1932 | } | ||
1941 | 1933 | |||
1942 | 1934 | /*! | ||
1943 | 1935 | \reimp | ||
1944 | 1936 | */ | ||
1945 | 1937 | QVariant QSortFilterProxyModel::data(const QModelIndex &index, int role) const | ||
1946 | 1938 | { | ||
1947 | 1939 | Q_D(const QSortFilterProxyModel); | ||
1948 | 1940 | QModelIndex source_index = mapToSource(index); | ||
1949 | 1941 | if (index.isValid() && !source_index.isValid()) | ||
1950 | 1942 | return QVariant(); | ||
1951 | 1943 | return d->model->data(source_index, role); | ||
1952 | 1944 | } | ||
1953 | 1945 | |||
1954 | 1946 | /*! | ||
1955 | 1947 | \reimp | ||
1956 | 1948 | */ | ||
1957 | 1949 | bool QSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) | ||
1958 | 1950 | { | ||
1959 | 1951 | Q_D(QSortFilterProxyModel); | ||
1960 | 1952 | QModelIndex source_index = mapToSource(index); | ||
1961 | 1953 | if (index.isValid() && !source_index.isValid()) | ||
1962 | 1954 | return false; | ||
1963 | 1955 | return d->model->setData(source_index, value, role); | ||
1964 | 1956 | } | ||
1965 | 1957 | |||
1966 | 1958 | /*! | ||
1967 | 1959 | \reimp | ||
1968 | 1960 | */ | ||
1969 | 1961 | QVariant QSortFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const | ||
1970 | 1962 | { | ||
1971 | 1963 | Q_D(const QSortFilterProxyModel); | ||
1972 | 1964 | IndexMap::const_iterator it = d->create_mapping(QModelIndex()); | ||
1973 | 1965 | if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0) | ||
1974 | 1966 | return QAbstractProxyModel::headerData(section, orientation, role); | ||
1975 | 1967 | int source_section; | ||
1976 | 1968 | if (orientation == Qt::Vertical) { | ||
1977 | 1969 | if (section < 0 || section >= it.value()->source_rows.count()) | ||
1978 | 1970 | return QVariant(); | ||
1979 | 1971 | source_section = it.value()->source_rows.at(section); | ||
1980 | 1972 | } else { | ||
1981 | 1973 | if (section < 0 || section >= it.value()->source_columns.count()) | ||
1982 | 1974 | return QVariant(); | ||
1983 | 1975 | source_section = it.value()->source_columns.at(section); | ||
1984 | 1976 | } | ||
1985 | 1977 | return d->model->headerData(source_section, orientation, role); | ||
1986 | 1978 | } | ||
1987 | 1979 | |||
1988 | 1980 | /*! | ||
1989 | 1981 | \reimp | ||
1990 | 1982 | */ | ||
1991 | 1983 | bool QSortFilterProxyModel::setHeaderData(int section, Qt::Orientation orientation, | ||
1992 | 1984 | const QVariant &value, int role) | ||
1993 | 1985 | { | ||
1994 | 1986 | Q_D(QSortFilterProxyModel); | ||
1995 | 1987 | IndexMap::const_iterator it = d->create_mapping(QModelIndex()); | ||
1996 | 1988 | if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0) | ||
1997 | 1989 | return QAbstractProxyModel::setHeaderData(section, orientation, value, role); | ||
1998 | 1990 | int source_section; | ||
1999 | 1991 | if (orientation == Qt::Vertical) { | ||
2000 | 1992 | if (section < 0 || section >= it.value()->source_rows.count()) | ||
2001 | 1993 | return false; | ||
2002 | 1994 | source_section = it.value()->source_rows.at(section); | ||
2003 | 1995 | } else { | ||
2004 | 1996 | if (section < 0 || section >= it.value()->source_columns.count()) | ||
2005 | 1997 | return false; | ||
2006 | 1998 | source_section = it.value()->source_columns.at(section); | ||
2007 | 1999 | } | ||
2008 | 2000 | return d->model->setHeaderData(source_section, orientation, value, role); | ||
2009 | 2001 | } | ||
2010 | 2002 | |||
2011 | 2003 | /*! | ||
2012 | 2004 | \reimp | ||
2013 | 2005 | */ | ||
2014 | 2006 | QMimeData *QSortFilterProxyModel::mimeData(const QModelIndexList &indexes) const | ||
2015 | 2007 | { | ||
2016 | 2008 | Q_D(const QSortFilterProxyModel); | ||
2017 | 2009 | QModelIndexList source_indexes; | ||
2018 | 2010 | for (int i = 0; i < indexes.count(); ++i) | ||
2019 | 2011 | source_indexes << mapToSource(indexes.at(i)); | ||
2020 | 2012 | return d->model->mimeData(source_indexes); | ||
2021 | 2013 | } | ||
2022 | 2014 | |||
2023 | 2015 | /*! | ||
2024 | 2016 | \reimp | ||
2025 | 2017 | */ | ||
2026 | 2018 | QStringList QSortFilterProxyModel::mimeTypes() const | ||
2027 | 2019 | { | ||
2028 | 2020 | Q_D(const QSortFilterProxyModel); | ||
2029 | 2021 | return d->model->mimeTypes(); | ||
2030 | 2022 | } | ||
2031 | 2023 | |||
2032 | 2024 | /*! | ||
2033 | 2025 | \reimp | ||
2034 | 2026 | */ | ||
2035 | 2027 | Qt::DropActions QSortFilterProxyModel::supportedDropActions() const | ||
2036 | 2028 | { | ||
2037 | 2029 | Q_D(const QSortFilterProxyModel); | ||
2038 | 2030 | return d->model->supportedDropActions(); | ||
2039 | 2031 | } | ||
2040 | 2032 | |||
2041 | 2033 | /*! | ||
2042 | 2034 | \reimp | ||
2043 | 2035 | */ | ||
2044 | 2036 | bool QSortFilterProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action, | ||
2045 | 2037 | int row, int column, const QModelIndex &parent) | ||
2046 | 2038 | { | ||
2047 | 2039 | Q_D(QSortFilterProxyModel); | ||
2048 | 2040 | if ((row == -1) && (column == -1)) | ||
2049 | 2041 | return d->model->dropMimeData(data, action, -1, -1, mapToSource(parent)); | ||
2050 | 2042 | int source_destination_row = -1; | ||
2051 | 2043 | int source_destination_column = -1; | ||
2052 | 2044 | QModelIndex source_parent; | ||
2053 | 2045 | if (row == rowCount(parent)) { | ||
2054 | 2046 | source_parent = mapToSource(parent); | ||
2055 | 2047 | source_destination_row = d->model->rowCount(source_parent); | ||
2056 | 2048 | } else { | ||
2057 | 2049 | QModelIndex proxy_index = index(row, column, parent); | ||
2058 | 2050 | QModelIndex source_index = mapToSource(proxy_index); | ||
2059 | 2051 | source_destination_row = source_index.row(); | ||
2060 | 2052 | source_destination_column = source_index.column(); | ||
2061 | 2053 | source_parent = source_index.parent(); | ||
2062 | 2054 | } | ||
2063 | 2055 | return d->model->dropMimeData(data, action, source_destination_row, | ||
2064 | 2056 | source_destination_column, source_parent); | ||
2065 | 2057 | } | ||
2066 | 2058 | |||
2067 | 2059 | /*! | ||
2068 | 2060 | \reimp | ||
2069 | 2061 | */ | ||
2070 | 2062 | bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &parent) | ||
2071 | 2063 | { | ||
2072 | 2064 | Q_D(QSortFilterProxyModel); | ||
2073 | 2065 | if (row < 0 || count <= 0) | ||
2074 | 2066 | return false; | ||
2075 | 2067 | QModelIndex source_parent = mapToSource(parent); | ||
2076 | 2068 | if (parent.isValid() && !source_parent.isValid()) | ||
2077 | 2069 | return false; | ||
2078 | 2070 | QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value(); | ||
2079 | 2071 | if (row > m->source_rows.count()) | ||
2080 | 2072 | return false; | ||
2081 | 2073 | int source_row = (row >= m->source_rows.count() | ||
2082 | 2074 | ? m->source_rows.count() | ||
2083 | 2075 | : m->source_rows.at(row)); | ||
2084 | 2076 | return d->model->insertRows(source_row, count, source_parent); | ||
2085 | 2077 | } | ||
2086 | 2078 | |||
2087 | 2079 | /*! | ||
2088 | 2080 | \reimp | ||
2089 | 2081 | */ | ||
2090 | 2082 | bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelIndex &parent) | ||
2091 | 2083 | { | ||
2092 | 2084 | Q_D(QSortFilterProxyModel); | ||
2093 | 2085 | if (column < 0|| count <= 0) | ||
2094 | 2086 | return false; | ||
2095 | 2087 | QModelIndex source_parent = mapToSource(parent); | ||
2096 | 2088 | if (parent.isValid() && !source_parent.isValid()) | ||
2097 | 2089 | return false; | ||
2098 | 2090 | QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value(); | ||
2099 | 2091 | if (column > m->source_columns.count()) | ||
2100 | 2092 | return false; | ||
2101 | 2093 | int source_column = (column >= m->source_columns.count() | ||
2102 | 2094 | ? m->source_columns.count() | ||
2103 | 2095 | : m->source_columns.at(column)); | ||
2104 | 2096 | return d->model->insertColumns(source_column, count, source_parent); | ||
2105 | 2097 | } | ||
2106 | 2098 | |||
2107 | 2099 | /*! | ||
2108 | 2100 | \reimp | ||
2109 | 2101 | */ | ||
2110 | 2102 | bool QSortFilterProxyModel::removeRows(int row, int count, const QModelIndex &parent) | ||
2111 | 2103 | { | ||
2112 | 2104 | Q_D(QSortFilterProxyModel); | ||
2113 | 2105 | if (row < 0 || count <= 0) | ||
2114 | 2106 | return false; | ||
2115 | 2107 | QModelIndex source_parent = mapToSource(parent); | ||
2116 | 2108 | if (parent.isValid() && !source_parent.isValid()) | ||
2117 | 2109 | return false; | ||
2118 | 2110 | QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value(); | ||
2119 | 2111 | if (row + count > m->source_rows.count()) | ||
2120 | 2112 | return false; | ||
2121 | 2113 | if ((count == 1) | ||
2122 | 2114 | || ((d->source_sort_column < 0) && (m->proxy_rows.count() == m->source_rows.count()))) { | ||
2123 | 2115 | int source_row = m->source_rows.at(row); | ||
2124 | 2116 | return d->model->removeRows(source_row, count, source_parent); | ||
2125 | 2117 | } | ||
2126 | 2118 | // remove corresponding source intervals | ||
2127 | 2119 | // ### if this proves to be slow, we can switch to single-row removal | ||
2128 | 2120 | QVector<int> rows; | ||
2129 | 2121 | for (int i = row; i < row + count; ++i) | ||
2130 | 2122 | rows.append(m->source_rows.at(i)); | ||
2131 | 2123 | std::sort(rows.begin(), rows.end()); | ||
2132 | 2124 | |||
2133 | 2125 | int pos = rows.count() - 1; | ||
2134 | 2126 | bool ok = true; | ||
2135 | 2127 | while (pos >= 0) { | ||
2136 | 2128 | const int source_end = rows.at(pos--); | ||
2137 | 2129 | int source_start = source_end; | ||
2138 | 2130 | while ((pos >= 0) && (rows.at(pos) == (source_start - 1))) { | ||
2139 | 2131 | --source_start; | ||
2140 | 2132 | --pos; | ||
2141 | 2133 | } | ||
2142 | 2134 | ok = ok && d->model->removeRows(source_start, source_end - source_start + 1, | ||
2143 | 2135 | source_parent); | ||
2144 | 2136 | } | ||
2145 | 2137 | return ok; | ||
2146 | 2138 | } | ||
2147 | 2139 | |||
2148 | 2140 | /*! | ||
2149 | 2141 | \reimp | ||
2150 | 2142 | */ | ||
2151 | 2143 | bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelIndex &parent) | ||
2152 | 2144 | { | ||
2153 | 2145 | Q_D(QSortFilterProxyModel); | ||
2154 | 2146 | if (column < 0 || count <= 0) | ||
2155 | 2147 | return false; | ||
2156 | 2148 | QModelIndex source_parent = mapToSource(parent); | ||
2157 | 2149 | if (parent.isValid() && !source_parent.isValid()) | ||
2158 | 2150 | return false; | ||
2159 | 2151 | QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value(); | ||
2160 | 2152 | if (column + count > m->source_columns.count()) | ||
2161 | 2153 | return false; | ||
2162 | 2154 | if ((count == 1) || (m->proxy_columns.count() == m->source_columns.count())) { | ||
2163 | 2155 | int source_column = m->source_columns.at(column); | ||
2164 | 2156 | return d->model->removeColumns(source_column, count, source_parent); | ||
2165 | 2157 | } | ||
2166 | 2158 | // remove corresponding source intervals | ||
2167 | 2159 | QVector<int> columns; | ||
2168 | 2160 | for (int i = column; i < column + count; ++i) | ||
2169 | 2161 | columns.append(m->source_columns.at(i)); | ||
2170 | 2162 | |||
2171 | 2163 | int pos = columns.count() - 1; | ||
2172 | 2164 | bool ok = true; | ||
2173 | 2165 | while (pos >= 0) { | ||
2174 | 2166 | const int source_end = columns.at(pos--); | ||
2175 | 2167 | int source_start = source_end; | ||
2176 | 2168 | while ((pos >= 0) && (columns.at(pos) == (source_start - 1))) { | ||
2177 | 2169 | --source_start; | ||
2178 | 2170 | --pos; | ||
2179 | 2171 | } | ||
2180 | 2172 | ok = ok && d->model->removeColumns(source_start, source_end - source_start + 1, | ||
2181 | 2173 | source_parent); | ||
2182 | 2174 | } | ||
2183 | 2175 | return ok; | ||
2184 | 2176 | } | ||
2185 | 2177 | |||
2186 | 2178 | /*! | ||
2187 | 2179 | \reimp | ||
2188 | 2180 | */ | ||
2189 | 2181 | void QSortFilterProxyModel::fetchMore(const QModelIndex &parent) | ||
2190 | 2182 | { | ||
2191 | 2183 | Q_D(QSortFilterProxyModel); | ||
2192 | 2184 | QModelIndex source_parent; | ||
2193 | 2185 | if (d->indexValid(parent)) | ||
2194 | 2186 | source_parent = mapToSource(parent); | ||
2195 | 2187 | d->model->fetchMore(source_parent); | ||
2196 | 2188 | } | ||
2197 | 2189 | |||
2198 | 2190 | /*! | ||
2199 | 2191 | \reimp | ||
2200 | 2192 | */ | ||
2201 | 2193 | bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const | ||
2202 | 2194 | { | ||
2203 | 2195 | Q_D(const QSortFilterProxyModel); | ||
2204 | 2196 | QModelIndex source_parent; | ||
2205 | 2197 | if (d->indexValid(parent)) | ||
2206 | 2198 | source_parent = mapToSource(parent); | ||
2207 | 2199 | return d->model->canFetchMore(source_parent); | ||
2208 | 2200 | } | ||
2209 | 2201 | |||
2210 | 2202 | /*! | ||
2211 | 2203 | \reimp | ||
2212 | 2204 | */ | ||
2213 | 2205 | Qt::ItemFlags QSortFilterProxyModel::flags(const QModelIndex &index) const | ||
2214 | 2206 | { | ||
2215 | 2207 | Q_D(const QSortFilterProxyModel); | ||
2216 | 2208 | QModelIndex source_index; | ||
2217 | 2209 | if (d->indexValid(index)) | ||
2218 | 2210 | source_index = mapToSource(index); | ||
2219 | 2211 | return d->model->flags(source_index); | ||
2220 | 2212 | } | ||
2221 | 2213 | |||
2222 | 2214 | /*! | ||
2223 | 2215 | \reimp | ||
2224 | 2216 | */ | ||
2225 | 2217 | QModelIndex QSortFilterProxyModel::buddy(const QModelIndex &index) const | ||
2226 | 2218 | { | ||
2227 | 2219 | Q_D(const QSortFilterProxyModel); | ||
2228 | 2220 | if (!d->indexValid(index)) | ||
2229 | 2221 | return QModelIndex(); | ||
2230 | 2222 | QModelIndex source_index = mapToSource(index); | ||
2231 | 2223 | QModelIndex source_buddy = d->model->buddy(source_index); | ||
2232 | 2224 | if (source_index == source_buddy) | ||
2233 | 2225 | return index; | ||
2234 | 2226 | return mapFromSource(source_buddy); | ||
2235 | 2227 | } | ||
2236 | 2228 | |||
2237 | 2229 | /*! | ||
2238 | 2230 | \reimp | ||
2239 | 2231 | */ | ||
2240 | 2232 | QModelIndexList QSortFilterProxyModel::match(const QModelIndex &start, int role, | ||
2241 | 2233 | const QVariant &value, int hits, | ||
2242 | 2234 | Qt::MatchFlags flags) const | ||
2243 | 2235 | { | ||
2244 | 2236 | return QAbstractProxyModel::match(start, role, value, hits, flags); | ||
2245 | 2237 | } | ||
2246 | 2238 | |||
2247 | 2239 | /*! | ||
2248 | 2240 | \reimp | ||
2249 | 2241 | */ | ||
2250 | 2242 | QSize QSortFilterProxyModel::span(const QModelIndex &index) const | ||
2251 | 2243 | { | ||
2252 | 2244 | Q_D(const QSortFilterProxyModel); | ||
2253 | 2245 | QModelIndex source_index = mapToSource(index); | ||
2254 | 2246 | if (index.isValid() && !source_index.isValid()) | ||
2255 | 2247 | return QSize(); | ||
2256 | 2248 | return d->model->span(source_index); | ||
2257 | 2249 | } | ||
2258 | 2250 | |||
2259 | 2251 | /*! | ||
2260 | 2252 | \reimp | ||
2261 | 2253 | */ | ||
2262 | 2254 | void QSortFilterProxyModel::sort(int column, Qt::SortOrder order) | ||
2263 | 2255 | { | ||
2264 | 2256 | Q_D(QSortFilterProxyModel); | ||
2265 | 2257 | if (d->dynamic_sortfilter && d->proxy_sort_column == column && d->sort_order == order) | ||
2266 | 2258 | return; | ||
2267 | 2259 | d->sort_order = order; | ||
2268 | 2260 | d->proxy_sort_column = column; | ||
2269 | 2261 | d->update_source_sort_column(); | ||
2270 | 2262 | d->sort(); | ||
2271 | 2263 | } | ||
2272 | 2264 | |||
2273 | 2265 | /*! | ||
2274 | 2266 | \since 4.5 | ||
2275 | 2267 | \brief the column currently used for sorting | ||
2276 | 2268 | |||
2277 | 2269 | This returns the most recently used sort column. | ||
2278 | 2270 | */ | ||
2279 | 2271 | int QSortFilterProxyModel::sortColumn() const | ||
2280 | 2272 | { | ||
2281 | 2273 | Q_D(const QSortFilterProxyModel); | ||
2282 | 2274 | return d->proxy_sort_column; | ||
2283 | 2275 | } | ||
2284 | 2276 | |||
2285 | 2277 | /*! | ||
2286 | 2278 | \since 4.5 | ||
2287 | 2279 | \brief the order currently used for sorting | ||
2288 | 2280 | |||
2289 | 2281 | This returns the most recently used sort order. | ||
2290 | 2282 | */ | ||
2291 | 2283 | Qt::SortOrder QSortFilterProxyModel::sortOrder() const | ||
2292 | 2284 | { | ||
2293 | 2285 | Q_D(const QSortFilterProxyModel); | ||
2294 | 2286 | return d->sort_order; | ||
2295 | 2287 | } | ||
2296 | 2288 | |||
2297 | 2289 | /*! | ||
2298 | 2290 | \property QSortFilterProxyModel::filterRegExp | ||
2299 | 2291 | \brief the QRegExp used to filter the contents of the source model | ||
2300 | 2292 | |||
2301 | 2293 | Setting this property overwrites the current | ||
2302 | 2294 | \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}. | ||
2303 | 2295 | By default, the QRegExp is an empty string matching all contents. | ||
2304 | 2296 | |||
2305 | 2297 | If no QRegExp or an empty string is set, everything in the source model | ||
2306 | 2298 | will be accepted. | ||
2307 | 2299 | |||
2308 | 2300 | \sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString() | ||
2309 | 2301 | */ | ||
2310 | 2302 | QRegExp QSortFilterProxyModel::filterRegExp() const | ||
2311 | 2303 | { | ||
2312 | 2304 | Q_D(const QSortFilterProxyModel); | ||
2313 | 2305 | return d->filter_regexp; | ||
2314 | 2306 | } | ||
2315 | 2307 | |||
2316 | 2308 | void QSortFilterProxyModel::setFilterRegExp(const QRegExp ®Exp) | ||
2317 | 2309 | { | ||
2318 | 2310 | Q_D(QSortFilterProxyModel); | ||
2319 | 2311 | d->filter_regexp = regExp; | ||
2320 | 2312 | d->filter_changed(); | ||
2321 | 2313 | } | ||
2322 | 2314 | |||
2323 | 2315 | /*! | ||
2324 | 2316 | \property QSortFilterProxyModel::filterKeyColumn | ||
2325 | 2317 | \brief the column where the key used to filter the contents of the | ||
2326 | 2318 | source model is read from. | ||
2327 | 2319 | |||
2328 | 2320 | The default value is 0. If the value is -1, the keys will be read | ||
2329 | 2321 | from all columns. | ||
2330 | 2322 | */ | ||
2331 | 2323 | int QSortFilterProxyModel::filterKeyColumn() const | ||
2332 | 2324 | { | ||
2333 | 2325 | Q_D(const QSortFilterProxyModel); | ||
2334 | 2326 | return d->filter_column; | ||
2335 | 2327 | } | ||
2336 | 2328 | |||
2337 | 2329 | void QSortFilterProxyModel::setFilterKeyColumn(int column) | ||
2338 | 2330 | { | ||
2339 | 2331 | Q_D(QSortFilterProxyModel); | ||
2340 | 2332 | d->filter_column = column; | ||
2341 | 2333 | d->filter_changed(); | ||
2342 | 2334 | } | ||
2343 | 2335 | |||
2344 | 2336 | /*! | ||
2345 | 2337 | \property QSortFilterProxyModel::filterCaseSensitivity | ||
2346 | 2338 | |||
2347 | 2339 | \brief the case sensitivity of the QRegExp pattern used to filter the | ||
2348 | 2340 | contents of the source model | ||
2349 | 2341 | |||
2350 | 2342 | By default, the filter is case sensitive. | ||
2351 | 2343 | |||
2352 | 2344 | \sa filterRegExp, sortCaseSensitivity | ||
2353 | 2345 | */ | ||
2354 | 2346 | Qt::CaseSensitivity QSortFilterProxyModel::filterCaseSensitivity() const | ||
2355 | 2347 | { | ||
2356 | 2348 | Q_D(const QSortFilterProxyModel); | ||
2357 | 2349 | return d->filter_regexp.caseSensitivity(); | ||
2358 | 2350 | } | ||
2359 | 2351 | |||
2360 | 2352 | void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs) | ||
2361 | 2353 | { | ||
2362 | 2354 | Q_D(QSortFilterProxyModel); | ||
2363 | 2355 | if (cs == d->filter_regexp.caseSensitivity()) | ||
2364 | 2356 | return; | ||
2365 | 2357 | d->filter_regexp.setCaseSensitivity(cs); | ||
2366 | 2358 | d->filter_changed(); | ||
2367 | 2359 | } | ||
2368 | 2360 | |||
2369 | 2361 | /*! | ||
2370 | 2362 | \since 4.2 | ||
2371 | 2363 | \property QSortFilterProxyModel::sortCaseSensitivity | ||
2372 | 2364 | \brief the case sensitivity setting used for comparing strings when sorting | ||
2373 | 2365 | |||
2374 | 2366 | By default, sorting is case sensitive. | ||
2375 | 2367 | |||
2376 | 2368 | \sa filterCaseSensitivity, lessThan() | ||
2377 | 2369 | */ | ||
2378 | 2370 | Qt::CaseSensitivity QSortFilterProxyModel::sortCaseSensitivity() const | ||
2379 | 2371 | { | ||
2380 | 2372 | Q_D(const QSortFilterProxyModel); | ||
2381 | 2373 | return d->sort_casesensitivity; | ||
2382 | 2374 | } | ||
2383 | 2375 | |||
2384 | 2376 | void QSortFilterProxyModel::setSortCaseSensitivity(Qt::CaseSensitivity cs) | ||
2385 | 2377 | { | ||
2386 | 2378 | Q_D(QSortFilterProxyModel); | ||
2387 | 2379 | if (d->sort_casesensitivity == cs) | ||
2388 | 2380 | return; | ||
2389 | 2381 | |||
2390 | 2382 | d->sort_casesensitivity = cs; | ||
2391 | 2383 | d->sort(); | ||
2392 | 2384 | } | ||
2393 | 2385 | |||
2394 | 2386 | /*! | ||
2395 | 2387 | \since 4.3 | ||
2396 | 2388 | \property QSortFilterProxyModel::isSortLocaleAware | ||
2397 | 2389 | \brief the local aware setting used for comparing strings when sorting | ||
2398 | 2390 | |||
2399 | 2391 | By default, sorting is not local aware. | ||
2400 | 2392 | |||
2401 | 2393 | \sa sortCaseSensitivity, lessThan() | ||
2402 | 2394 | */ | ||
2403 | 2395 | bool QSortFilterProxyModel::isSortLocaleAware() const | ||
2404 | 2396 | { | ||
2405 | 2397 | Q_D(const QSortFilterProxyModel); | ||
2406 | 2398 | return d->sort_localeaware; | ||
2407 | 2399 | } | ||
2408 | 2400 | |||
2409 | 2401 | void QSortFilterProxyModel::setSortLocaleAware(bool on) | ||
2410 | 2402 | { | ||
2411 | 2403 | Q_D(QSortFilterProxyModel); | ||
2412 | 2404 | if (d->sort_localeaware == on) | ||
2413 | 2405 | return; | ||
2414 | 2406 | |||
2415 | 2407 | d->sort_localeaware = on; | ||
2416 | 2408 | d->sort(); | ||
2417 | 2409 | } | ||
2418 | 2410 | |||
2419 | 2411 | /*! | ||
2420 | 2412 | \overload | ||
2421 | 2413 | |||
2422 | 2414 | Sets the regular expression used to filter the contents | ||
2423 | 2415 | of the source model to \a pattern. | ||
2424 | 2416 | |||
2425 | 2417 | \sa setFilterCaseSensitivity(), setFilterWildcard(), setFilterFixedString(), filterRegExp() | ||
2426 | 2418 | */ | ||
2427 | 2419 | void QSortFilterProxyModel::setFilterRegExp(const QString &pattern) | ||
2428 | 2420 | { | ||
2429 | 2421 | Q_D(QSortFilterProxyModel); | ||
2430 | 2422 | d->filter_regexp.setPatternSyntax(QRegExp::RegExp); | ||
2431 | 2423 | d->filter_regexp.setPattern(pattern); | ||
2432 | 2424 | d->filter_changed(); | ||
2433 | 2425 | } | ||
2434 | 2426 | |||
2435 | 2427 | /*! | ||
2436 | 2428 | Sets the wildcard expression used to filter the contents | ||
2437 | 2429 | of the source model to the given \a pattern. | ||
2438 | 2430 | |||
2439 | 2431 | \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterFixedString(), filterRegExp() | ||
2440 | 2432 | */ | ||
2441 | 2433 | void QSortFilterProxyModel::setFilterWildcard(const QString &pattern) | ||
2442 | 2434 | { | ||
2443 | 2435 | Q_D(QSortFilterProxyModel); | ||
2444 | 2436 | d->filter_regexp.setPatternSyntax(QRegExp::Wildcard); | ||
2445 | 2437 | d->filter_regexp.setPattern(pattern); | ||
2446 | 2438 | d->filter_changed(); | ||
2447 | 2439 | } | ||
2448 | 2440 | |||
2449 | 2441 | /*! | ||
2450 | 2442 | Sets the fixed string used to filter the contents | ||
2451 | 2443 | of the source model to the given \a pattern. | ||
2452 | 2444 | |||
2453 | 2445 | \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterWildcard(), filterRegExp() | ||
2454 | 2446 | */ | ||
2455 | 2447 | void QSortFilterProxyModel::setFilterFixedString(const QString &pattern) | ||
2456 | 2448 | { | ||
2457 | 2449 | Q_D(QSortFilterProxyModel); | ||
2458 | 2450 | d->filter_regexp.setPatternSyntax(QRegExp::FixedString); | ||
2459 | 2451 | d->filter_regexp.setPattern(pattern); | ||
2460 | 2452 | d->filter_changed(); | ||
2461 | 2453 | } | ||
2462 | 2454 | |||
2463 | 2455 | /*! | ||
2464 | 2456 | \since 4.2 | ||
2465 | 2457 | \property QSortFilterProxyModel::dynamicSortFilter | ||
2466 | 2458 | \brief whether the proxy model is dynamically sorted and filtered | ||
2467 | 2459 | whenever the contents of the source model change | ||
2468 | 2460 | |||
2469 | 2461 | Note that you should not update the source model through the proxy | ||
2470 | 2462 | model when dynamicSortFilter is true. For instance, if you set the | ||
2471 | 2463 | proxy model on a QComboBox, then using functions that update the | ||
2472 | 2464 | model, e.g., \l{QComboBox::}{addItem()}, will not work as | ||
2473 | 2465 | expected. An alternative is to set dynamicSortFilter to false and | ||
2474 | 2466 | call \l{QSortFilterProxyModel::}{sort()} after adding items to the | ||
2475 | 2467 | QComboBox. | ||
2476 | 2468 | |||
2477 | 2469 | The default value is true. | ||
2478 | 2470 | */ | ||
2479 | 2471 | bool QSortFilterProxyModel::dynamicSortFilter() const | ||
2480 | 2472 | { | ||
2481 | 2473 | Q_D(const QSortFilterProxyModel); | ||
2482 | 2474 | return d->dynamic_sortfilter; | ||
2483 | 2475 | } | ||
2484 | 2476 | |||
2485 | 2477 | void QSortFilterProxyModel::setDynamicSortFilter(bool enable) | ||
2486 | 2478 | { | ||
2487 | 2479 | Q_D(QSortFilterProxyModel); | ||
2488 | 2480 | d->dynamic_sortfilter = enable; | ||
2489 | 2481 | if (enable) | ||
2490 | 2482 | d->sort(); | ||
2491 | 2483 | } | ||
2492 | 2484 | |||
2493 | 2485 | /*! | ||
2494 | 2486 | \since 4.2 | ||
2495 | 2487 | \property QSortFilterProxyModel::sortRole | ||
2496 | 2488 | \brief the item role that is used to query the source model's data when sorting items | ||
2497 | 2489 | |||
2498 | 2490 | The default value is Qt::DisplayRole. | ||
2499 | 2491 | |||
2500 | 2492 | \sa lessThan() | ||
2501 | 2493 | */ | ||
2502 | 2494 | int QSortFilterProxyModel::sortRole() const | ||
2503 | 2495 | { | ||
2504 | 2496 | Q_D(const QSortFilterProxyModel); | ||
2505 | 2497 | return d->sort_role; | ||
2506 | 2498 | } | ||
2507 | 2499 | |||
2508 | 2500 | void QSortFilterProxyModel::setSortRole(int role) | ||
2509 | 2501 | { | ||
2510 | 2502 | Q_D(QSortFilterProxyModel); | ||
2511 | 2503 | if (d->sort_role == role) | ||
2512 | 2504 | return; | ||
2513 | 2505 | d->sort_role = role; | ||
2514 | 2506 | d->sort(); | ||
2515 | 2507 | } | ||
2516 | 2508 | |||
2517 | 2509 | /*! | ||
2518 | 2510 | \since 4.2 | ||
2519 | 2511 | \property QSortFilterProxyModel::filterRole | ||
2520 | 2512 | \brief the item role that is used to query the source model's data when filtering items | ||
2521 | 2513 | |||
2522 | 2514 | The default value is Qt::DisplayRole. | ||
2523 | 2515 | |||
2524 | 2516 | \sa filterAcceptsRow() | ||
2525 | 2517 | */ | ||
2526 | 2518 | int QSortFilterProxyModel::filterRole() const | ||
2527 | 2519 | { | ||
2528 | 2520 | Q_D(const QSortFilterProxyModel); | ||
2529 | 2521 | return d->filter_role; | ||
2530 | 2522 | } | ||
2531 | 2523 | |||
2532 | 2524 | void QSortFilterProxyModel::setFilterRole(int role) | ||
2533 | 2525 | { | ||
2534 | 2526 | Q_D(QSortFilterProxyModel); | ||
2535 | 2527 | if (d->filter_role == role) | ||
2536 | 2528 | return; | ||
2537 | 2529 | d->filter_role = role; | ||
2538 | 2530 | d->filter_changed(); | ||
2539 | 2531 | } | ||
2540 | 2532 | |||
2541 | 2533 | /*! | ||
2542 | 2534 | \obsolete | ||
2543 | 2535 | |||
2544 | 2536 | This function is obsolete. Use invalidate() instead. | ||
2545 | 2537 | */ | ||
2546 | 2538 | void QSortFilterProxyModel::clear() | ||
2547 | 2539 | { | ||
2548 | 2540 | Q_D(QSortFilterProxyModel); | ||
2549 | 2541 | emit layoutAboutToBeChanged(); | ||
2550 | 2542 | d->_q_clearMapping(); | ||
2551 | 2543 | emit layoutChanged(); | ||
2552 | 2544 | } | ||
2553 | 2545 | |||
2554 | 2546 | /*! | ||
2555 | 2547 | \since 4.3 | ||
2556 | 2548 | |||
2557 | 2549 | Invalidates the current sorting and filtering. | ||
2558 | 2550 | |||
2559 | 2551 | \sa invalidateFilter() | ||
2560 | 2552 | */ | ||
2561 | 2553 | void QSortFilterProxyModel::invalidate() | ||
2562 | 2554 | { | ||
2563 | 2555 | Q_D(QSortFilterProxyModel); | ||
2564 | 2556 | emit layoutAboutToBeChanged(); | ||
2565 | 2557 | d->_q_clearMapping(); | ||
2566 | 2558 | emit layoutChanged(); | ||
2567 | 2559 | } | ||
2568 | 2560 | |||
2569 | 2561 | /*! | ||
2570 | 2562 | \obsolete | ||
2571 | 2563 | |||
2572 | 2564 | This function is obsolete. Use invalidateFilter() instead. | ||
2573 | 2565 | */ | ||
2574 | 2566 | void QSortFilterProxyModel::filterChanged() | ||
2575 | 2567 | { | ||
2576 | 2568 | Q_D(QSortFilterProxyModel); | ||
2577 | 2569 | d->filter_changed(); | ||
2578 | 2570 | } | ||
2579 | 2571 | |||
2580 | 2572 | /*! | ||
2581 | 2573 | \since 4.3 | ||
2582 | 2574 | |||
2583 | 2575 | Invalidates the current filtering. | ||
2584 | 2576 | |||
2585 | 2577 | This function should be called if you are implementing custom filtering | ||
2586 | 2578 | (e.g. filterAcceptsRow()), and your filter parameters have changed. | ||
2587 | 2579 | |||
2588 | 2580 | \sa invalidate() | ||
2589 | 2581 | */ | ||
2590 | 2582 | void QSortFilterProxyModel::invalidateFilter() | ||
2591 | 2583 | { | ||
2592 | 2584 | Q_D(QSortFilterProxyModel); | ||
2593 | 2585 | d->filter_changed(); | ||
2594 | 2586 | } | ||
2595 | 2587 | |||
2596 | 2588 | /*! | ||
2597 | 2589 | Returns true if the value of the item referred to by the given | ||
2598 | 2590 | index \a left is less than the value of the item referred to by | ||
2599 | 2591 | the given index \a right, otherwise returns false. | ||
2600 | 2592 | |||
2601 | 2593 | This function is used as the < operator when sorting, and handles | ||
2602 | 2594 | the following QVariant types: | ||
2603 | 2595 | |||
2604 | 2596 | \list | ||
2605 | 2597 | \li QVariant::Int | ||
2606 | 2598 | \li QVariant::UInt | ||
2607 | 2599 | \li QVariant::LongLong | ||
2608 | 2600 | \li QVariant::ULongLong | ||
2609 | 2601 | \li QVariant::Double | ||
2610 | 2602 | \li QVariant::Char | ||
2611 | 2603 | \li QVariant::Date | ||
2612 | 2604 | \li QVariant::Time | ||
2613 | 2605 | \li QVariant::DateTime | ||
2614 | 2606 | \li QVariant::String | ||
2615 | 2607 | \endlist | ||
2616 | 2608 | |||
2617 | 2609 | Any other type will be converted to a QString using | ||
2618 | 2610 | QVariant::toString(). | ||
2619 | 2611 | |||
2620 | 2612 | Comparison of \l{QString}s is case sensitive by default; this can | ||
2621 | 2613 | be changed using the \l {QSortFilterProxyModel::sortCaseSensitivity} | ||
2622 | 2614 | {sortCaseSensitivity} property. | ||
2623 | 2615 | |||
2624 | 2616 | By default, the Qt::DisplayRole associated with the | ||
2625 | 2617 | \l{QModelIndex}es is used for comparisons. This can be changed by | ||
2626 | 2618 | setting the \l {QSortFilterProxyModel::sortRole} {sortRole} property. | ||
2627 | 2619 | |||
2628 | 2620 | \note The indices passed in correspond to the source model. | ||
2629 | 2621 | |||
2630 | 2622 | \sa sortRole, sortCaseSensitivity, dynamicSortFilter | ||
2631 | 2623 | */ | ||
2632 | 2624 | bool QSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const | ||
2633 | 2625 | { | ||
2634 | 2626 | Q_D(const QSortFilterProxyModel); | ||
2635 | 2627 | QVariant l = (left.model() ? left.model()->data(left, d->sort_role) : QVariant()); | ||
2636 | 2628 | QVariant r = (right.model() ? right.model()->data(right, d->sort_role) : QVariant()); | ||
2637 | 2629 | switch (l.userType()) { | ||
2638 | 2630 | case QVariant::Invalid: | ||
2639 | 2631 | return (r.type() != QVariant::Invalid); | ||
2640 | 2632 | case QVariant::Int: | ||
2641 | 2633 | return l.toInt() < r.toInt(); | ||
2642 | 2634 | case QVariant::UInt: | ||
2643 | 2635 | return l.toUInt() < r.toUInt(); | ||
2644 | 2636 | case QVariant::LongLong: | ||
2645 | 2637 | return l.toLongLong() < r.toLongLong(); | ||
2646 | 2638 | case QVariant::ULongLong: | ||
2647 | 2639 | return l.toULongLong() < r.toULongLong(); | ||
2648 | 2640 | case QMetaType::Float: | ||
2649 | 2641 | return l.toFloat() < r.toFloat(); | ||
2650 | 2642 | case QVariant::Double: | ||
2651 | 2643 | return l.toDouble() < r.toDouble(); | ||
2652 | 2644 | case QVariant::Char: | ||
2653 | 2645 | return l.toChar() < r.toChar(); | ||
2654 | 2646 | case QVariant::Date: | ||
2655 | 2647 | return l.toDate() < r.toDate(); | ||
2656 | 2648 | case QVariant::Time: | ||
2657 | 2649 | return l.toTime() < r.toTime(); | ||
2658 | 2650 | case QVariant::DateTime: | ||
2659 | 2651 | return l.toDateTime() < r.toDateTime(); | ||
2660 | 2652 | case QVariant::String: | ||
2661 | 2653 | default: | ||
2662 | 2654 | if (d->sort_localeaware) | ||
2663 | 2655 | return l.toString().localeAwareCompare(r.toString()) < 0; | ||
2664 | 2656 | else | ||
2665 | 2657 | return l.toString().compare(r.toString(), d->sort_casesensitivity) < 0; | ||
2666 | 2658 | } | ||
2667 | 2659 | return false; | ||
2668 | 2660 | } | ||
2669 | 2661 | |||
2670 | 2662 | /*! | ||
2671 | 2663 | Returns true if the item in the row indicated by the given \a source_row | ||
2672 | 2664 | and \a source_parent should be included in the model; otherwise returns | ||
2673 | 2665 | false. | ||
2674 | 2666 | |||
2675 | 2667 | The default implementation returns true if the value held by the relevant item | ||
2676 | 2668 | matches the filter string, wildcard string or regular expression. | ||
2677 | 2669 | |||
2678 | 2670 | \note By default, the Qt::DisplayRole is used to determine if the row | ||
2679 | 2671 | should be accepted or not. This can be changed by setting the | ||
2680 | 2672 | \l{QSortFilterProxyModel::filterRole}{filterRole} property. | ||
2681 | 2673 | |||
2682 | 2674 | \sa filterAcceptsColumn(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard() | ||
2683 | 2675 | */ | ||
2684 | 2676 | bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const | ||
2685 | 2677 | { | ||
2686 | 2678 | Q_D(const QSortFilterProxyModel); | ||
2687 | 2679 | if (d->filter_regexp.isEmpty()) | ||
2688 | 2680 | return true; | ||
2689 | 2681 | if (d->filter_column == -1) { | ||
2690 | 2682 | int column_count = d->model->columnCount(source_parent); | ||
2691 | 2683 | for (int column = 0; column < column_count; ++column) { | ||
2692 | 2684 | QModelIndex source_index = d->model->index(source_row, column, source_parent); | ||
2693 | 2685 | QString key = d->model->data(source_index, d->filter_role).toString(); | ||
2694 | 2686 | if (key.contains(d->filter_regexp)) | ||
2695 | 2687 | return true; | ||
2696 | 2688 | } | ||
2697 | 2689 | return false; | ||
2698 | 2690 | } | ||
2699 | 2691 | QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent); | ||
2700 | 2692 | if (!source_index.isValid()) // the column may not exist | ||
2701 | 2693 | return true; | ||
2702 | 2694 | QString key = d->model->data(source_index, d->filter_role).toString(); | ||
2703 | 2695 | return key.contains(d->filter_regexp); | ||
2704 | 2696 | } | ||
2705 | 2697 | |||
2706 | 2698 | /*! | ||
2707 | 2699 | Returns true if the item in the column indicated by the given \a source_column | ||
2708 | 2700 | and \a source_parent should be included in the model; otherwise returns false. | ||
2709 | 2701 | |||
2710 | 2702 | The default implementation returns true if the value held by the relevant item | ||
2711 | 2703 | matches the filter string, wildcard string or regular expression. | ||
2712 | 2704 | |||
2713 | 2705 | \note By default, the Qt::DisplayRole is used to determine if the row | ||
2714 | 2706 | should be accepted or not. This can be changed by setting the \l | ||
2715 | 2707 | filterRole property. | ||
2716 | 2708 | |||
2717 | 2709 | \sa filterAcceptsRow(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard() | ||
2718 | 2710 | */ | ||
2719 | 2711 | bool QSortFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const | ||
2720 | 2712 | { | ||
2721 | 2713 | Q_UNUSED(source_column); | ||
2722 | 2714 | Q_UNUSED(source_parent); | ||
2723 | 2715 | return true; | ||
2724 | 2716 | } | ||
2725 | 2717 | |||
2726 | 2718 | /*! | ||
2727 | 2719 | Returns the source model index corresponding to the given \a | ||
2728 | 2720 | proxyIndex from the sorting filter model. | ||
2729 | 2721 | |||
2730 | 2722 | \sa mapFromSource() | ||
2731 | 2723 | */ | ||
2732 | 2724 | QModelIndex QSortFilterProxyModel::mapToSource(const QModelIndex &proxyIndex) const | ||
2733 | 2725 | { | ||
2734 | 2726 | Q_D(const QSortFilterProxyModel); | ||
2735 | 2727 | return d->proxy_to_source(proxyIndex); | ||
2736 | 2728 | } | ||
2737 | 2729 | |||
2738 | 2730 | /*! | ||
2739 | 2731 | Returns the model index in the QSortFilterProxyModel given the \a | ||
2740 | 2732 | sourceIndex from the source model. | ||
2741 | 2733 | |||
2742 | 2734 | \sa mapToSource() | ||
2743 | 2735 | */ | ||
2744 | 2736 | QModelIndex QSortFilterProxyModel::mapFromSource(const QModelIndex &sourceIndex) const | ||
2745 | 2737 | { | ||
2746 | 2738 | Q_D(const QSortFilterProxyModel); | ||
2747 | 2739 | return d->source_to_proxy(sourceIndex); | ||
2748 | 2740 | } | ||
2749 | 2741 | |||
2750 | 2742 | /*! | ||
2751 | 2743 | \reimp | ||
2752 | 2744 | */ | ||
2753 | 2745 | QItemSelection QSortFilterProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const | ||
2754 | 2746 | { | ||
2755 | 2747 | return QAbstractProxyModel::mapSelectionToSource(proxySelection); | ||
2756 | 2748 | } | ||
2757 | 2749 | |||
2758 | 2750 | /*! | ||
2759 | 2751 | \reimp | ||
2760 | 2752 | */ | ||
2761 | 2753 | QItemSelection QSortFilterProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const | ||
2762 | 2754 | { | ||
2763 | 2755 | return QAbstractProxyModel::mapSelectionFromSource(sourceSelection); | ||
2764 | 2756 | } | ||
2765 | 2757 | |||
2766 | 2758 | /*! | ||
2767 | 2759 | \fn QObject *QSortFilterProxyModel::parent() const | ||
2768 | 2760 | \internal | ||
2769 | 2761 | */ | ||
2770 | 2762 | |||
2771 | 2763 | QT_END_NAMESPACE | ||
2772 | 2764 | |||
2773 | 2765 | #include "moc_qsortfilterproxymodel.cpp" | ||
2774 | 2766 | |||
2775 | 2767 | #endif // QT_NO_SORTFILTERPROXYMODEL | ||
2776 | 0 | 2768 | ||
2777 | === added directory '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/tests' | |||
2778 | === added directory '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/tests/auto' | |||
2779 | === added directory '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/tests/auto/corelib' | |||
2780 | === added directory '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/tests/auto/corelib/itemmodels' | |||
2781 | === added directory '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/tests/auto/corelib/itemmodels/qsortfilterproxymodel' | |||
2782 | === added file '.pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp' | |||
2783 | --- .pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp 1970-01-01 00:00:00 +0000 | |||
2784 | +++ .pc/0001-Fix-rowsInserted-not-being-emmited-in-some-cases-in-.patch/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp 2013-10-03 10:06:38 +0000 | |||
2785 | @@ -0,0 +1,3640 @@ | |||
2786 | 1 | /**************************************************************************** | ||
2787 | 2 | ** | ||
2788 | 3 | ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). | ||
2789 | 4 | ** Contact: http://www.qt-project.org/legal | ||
2790 | 5 | ** | ||
2791 | 6 | ** This file is part of the test suite of the Qt Toolkit. | ||
2792 | 7 | ** | ||
2793 | 8 | ** $QT_BEGIN_LICENSE:LGPL$ | ||
2794 | 9 | ** Commercial License Usage | ||
2795 | 10 | ** Licensees holding valid commercial Qt licenses may use this file in | ||
2796 | 11 | ** accordance with the commercial license agreement provided with the | ||
2797 | 12 | ** Software or, alternatively, in accordance with the terms contained in | ||
2798 | 13 | ** a written agreement between you and Digia. For licensing terms and | ||
2799 | 14 | ** conditions see http://qt.digia.com/licensing. For further information | ||
2800 | 15 | ** use the contact form at http://qt.digia.com/contact-us. | ||
2801 | 16 | ** | ||
2802 | 17 | ** GNU Lesser General Public License Usage | ||
2803 | 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | ||
2804 | 19 | ** General Public License version 2.1 as published by the Free Software | ||
2805 | 20 | ** Foundation and appearing in the file LICENSE.LGPL included in the | ||
2806 | 21 | ** packaging of this file. Please review the following information to | ||
2807 | 22 | ** ensure the GNU Lesser General Public License version 2.1 requirements | ||
2808 | 23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | ||
2809 | 24 | ** | ||
2810 | 25 | ** In addition, as a special exception, Digia gives you certain additional | ||
2811 | 26 | ** rights. These rights are described in the Digia Qt LGPL Exception | ||
2812 | 27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | ||
2813 | 28 | ** | ||
2814 | 29 | ** GNU General Public License Usage | ||
2815 | 30 | ** Alternatively, this file may be used under the terms of the GNU | ||
2816 | 31 | ** General Public License version 3.0 as published by the Free Software | ||
2817 | 32 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
2818 | 33 | ** packaging of this file. Please review the following information to | ||
2819 | 34 | ** ensure the GNU General Public License version 3.0 requirements will be | ||
2820 | 35 | ** met: http://www.gnu.org/copyleft/gpl.html. | ||
2821 | 36 | ** | ||
2822 | 37 | ** | ||
2823 | 38 | ** $QT_END_LICENSE$ | ||
2824 | 39 | ** | ||
2825 | 40 | ****************************************************************************/ | ||
2826 | 41 | |||
2827 | 42 | #include <QtTest/QtTest> | ||
2828 | 43 | #include "dynamictreemodel.h" | ||
2829 | 44 | #include "modeltest.h" | ||
2830 | 45 | |||
2831 | 46 | #include <QtCore/QCoreApplication> | ||
2832 | 47 | #include <QtGui/QStandardItem> | ||
2833 | 48 | #include <QtWidgets/QTreeView> | ||
2834 | 49 | #include <QtWidgets/QTableView> | ||
2835 | 50 | |||
2836 | 51 | #include <qdebug.h> | ||
2837 | 52 | |||
2838 | 53 | typedef QList<int> IntList; | ||
2839 | 54 | typedef QPair<int, int> IntPair; | ||
2840 | 55 | typedef QList<IntPair> IntPairList; | ||
2841 | 56 | |||
2842 | 57 | class tst_QSortFilterProxyModel : public QObject | ||
2843 | 58 | { | ||
2844 | 59 | Q_OBJECT | ||
2845 | 60 | public: | ||
2846 | 61 | tst_QSortFilterProxyModel(); | ||
2847 | 62 | |||
2848 | 63 | public slots: | ||
2849 | 64 | void initTestCase(); | ||
2850 | 65 | void cleanupTestCase(); | ||
2851 | 66 | void cleanup(); | ||
2852 | 67 | |||
2853 | 68 | private slots: | ||
2854 | 69 | void getSetCheck(); | ||
2855 | 70 | void sort_data(); | ||
2856 | 71 | void sort(); | ||
2857 | 72 | void sortHierarchy_data(); | ||
2858 | 73 | void sortHierarchy(); | ||
2859 | 74 | |||
2860 | 75 | void insertRows_data(); | ||
2861 | 76 | void insertRows(); | ||
2862 | 77 | void prependRow(); | ||
2863 | 78 | void removeRows_data(); | ||
2864 | 79 | void removeRows(); | ||
2865 | 80 | void removeColumns_data(); | ||
2866 | 81 | void removeColumns(); | ||
2867 | 82 | void insertAfterSelect(); | ||
2868 | 83 | void removeAfterSelect(); | ||
2869 | 84 | void filter_data(); | ||
2870 | 85 | void filter(); | ||
2871 | 86 | void filterHierarchy_data(); | ||
2872 | 87 | void filterHierarchy(); | ||
2873 | 88 | void filterColumns_data(); | ||
2874 | 89 | void filterColumns(); | ||
2875 | 90 | |||
2876 | 91 | void filterTable(); | ||
2877 | 92 | void filterCurrent(); | ||
2878 | 93 | |||
2879 | 94 | void changeSourceLayout(); | ||
2880 | 95 | void removeSourceRows_data(); | ||
2881 | 96 | void removeSourceRows(); | ||
2882 | 97 | void insertSourceRows_data(); | ||
2883 | 98 | void insertSourceRows(); | ||
2884 | 99 | void changeFilter_data(); | ||
2885 | 100 | void changeFilter(); | ||
2886 | 101 | void changeSourceData_data(); | ||
2887 | 102 | void changeSourceData(); | ||
2888 | 103 | void sortFilterRole(); | ||
2889 | 104 | void selectionFilteredOut(); | ||
2890 | 105 | void match_data(); | ||
2891 | 106 | void match(); | ||
2892 | 107 | void insertIntoChildrenlessItem(); | ||
2893 | 108 | void invalidateMappedChildren(); | ||
2894 | 109 | void insertRowIntoFilteredParent(); | ||
2895 | 110 | void filterOutParentAndFilterInChild(); | ||
2896 | 111 | |||
2897 | 112 | void sourceInsertRows(); | ||
2898 | 113 | void sourceModelDeletion(); | ||
2899 | 114 | |||
2900 | 115 | void sortColumnTracking1(); | ||
2901 | 116 | void sortColumnTracking2(); | ||
2902 | 117 | |||
2903 | 118 | void sortStable(); | ||
2904 | 119 | |||
2905 | 120 | void hiddenColumns(); | ||
2906 | 121 | void insertRowsSort(); | ||
2907 | 122 | void staticSorting(); | ||
2908 | 123 | void dynamicSorting(); | ||
2909 | 124 | void fetchMore(); | ||
2910 | 125 | void hiddenChildren(); | ||
2911 | 126 | void mapFromToSource(); | ||
2912 | 127 | void removeRowsRecursive(); | ||
2913 | 128 | void doubleProxySelectionSetSourceModel(); | ||
2914 | 129 | void appearsAndSort(); | ||
2915 | 130 | void unnecessaryDynamicSorting(); | ||
2916 | 131 | void unnecessaryMapCreation(); | ||
2917 | 132 | void resetInvalidate_data(); | ||
2918 | 133 | void resetInvalidate(); | ||
2919 | 134 | |||
2920 | 135 | void testMultipleProxiesWithSelection(); | ||
2921 | 136 | void mapSelectionFromSource(); | ||
2922 | 137 | void filteredColumns(); | ||
2923 | 138 | void headerDataChanged(); | ||
2924 | 139 | |||
2925 | 140 | void testParentLayoutChanged(); | ||
2926 | 141 | void moveSourceRows(); | ||
2927 | 142 | |||
2928 | 143 | void hierarchyFilterInvalidation(); | ||
2929 | 144 | void simpleFilterInvalidation(); | ||
2930 | 145 | |||
2931 | 146 | protected: | ||
2932 | 147 | void buildHierarchy(const QStringList &data, QAbstractItemModel *model); | ||
2933 | 148 | void checkHierarchy(const QStringList &data, const QAbstractItemModel *model); | ||
2934 | 149 | |||
2935 | 150 | private: | ||
2936 | 151 | QStandardItemModel *m_model; | ||
2937 | 152 | QSortFilterProxyModel *m_proxy; | ||
2938 | 153 | }; | ||
2939 | 154 | |||
2940 | 155 | // Testing get/set functions | ||
2941 | 156 | void tst_QSortFilterProxyModel::getSetCheck() | ||
2942 | 157 | { | ||
2943 | 158 | QSortFilterProxyModel obj1; | ||
2944 | 159 | QCOMPARE(obj1.sourceModel(), (QAbstractItemModel *)0); | ||
2945 | 160 | // int QSortFilterProxyModel::filterKeyColumn() | ||
2946 | 161 | // void QSortFilterProxyModel::setFilterKeyColumn(int) | ||
2947 | 162 | obj1.setFilterKeyColumn(0); | ||
2948 | 163 | QCOMPARE(0, obj1.filterKeyColumn()); | ||
2949 | 164 | obj1.setFilterKeyColumn(INT_MIN); | ||
2950 | 165 | QCOMPARE(INT_MIN, obj1.filterKeyColumn()); | ||
2951 | 166 | obj1.setFilterKeyColumn(INT_MAX); | ||
2952 | 167 | QCOMPARE(INT_MAX, obj1.filterKeyColumn()); | ||
2953 | 168 | } | ||
2954 | 169 | |||
2955 | 170 | tst_QSortFilterProxyModel::tst_QSortFilterProxyModel() | ||
2956 | 171 | : m_model(0), m_proxy(0) | ||
2957 | 172 | { | ||
2958 | 173 | } | ||
2959 | 174 | |||
2960 | 175 | void tst_QSortFilterProxyModel::initTestCase() | ||
2961 | 176 | { | ||
2962 | 177 | qRegisterMetaType<IntList>("IntList"); | ||
2963 | 178 | qRegisterMetaType<IntPair>("IntPair"); | ||
2964 | 179 | qRegisterMetaType<IntPairList>("IntPairList"); | ||
2965 | 180 | m_model = new QStandardItemModel(0, 1); | ||
2966 | 181 | m_proxy = new QSortFilterProxyModel(); | ||
2967 | 182 | m_proxy->setSourceModel(m_model); | ||
2968 | 183 | } | ||
2969 | 184 | |||
2970 | 185 | void tst_QSortFilterProxyModel::cleanupTestCase() | ||
2971 | 186 | { | ||
2972 | 187 | delete m_proxy; | ||
2973 | 188 | delete m_model; | ||
2974 | 189 | } | ||
2975 | 190 | |||
2976 | 191 | void tst_QSortFilterProxyModel::cleanup() | ||
2977 | 192 | { | ||
2978 | 193 | m_proxy->setFilterRegExp(QRegExp()); | ||
2979 | 194 | m_proxy->sort(-1, Qt::AscendingOrder); | ||
2980 | 195 | m_model->clear(); | ||
2981 | 196 | m_model->insertColumns(0, 1); | ||
2982 | 197 | } | ||
2983 | 198 | |||
2984 | 199 | /* | ||
2985 | 200 | tests | ||
2986 | 201 | */ | ||
2987 | 202 | |||
2988 | 203 | void tst_QSortFilterProxyModel::sort_data() | ||
2989 | 204 | { | ||
2990 | 205 | QTest::addColumn<int>("sortOrder"); | ||
2991 | 206 | QTest::addColumn<int>("sortCaseSensitivity"); | ||
2992 | 207 | QTest::addColumn<QStringList>("initial"); | ||
2993 | 208 | QTest::addColumn<QStringList>("expected"); | ||
2994 | 209 | |||
2995 | 210 | QTest::newRow("flat descending") << static_cast<int>(Qt::DescendingOrder) | ||
2996 | 211 | << int(Qt::CaseSensitive) | ||
2997 | 212 | << (QStringList() | ||
2998 | 213 | << "delta" | ||
2999 | 214 | << "yankee" | ||
3000 | 215 | << "bravo" | ||
3001 | 216 | << "lima" | ||
3002 | 217 | << "charlie" | ||
3003 | 218 | << "juliet" | ||
3004 | 219 | << "tango" | ||
3005 | 220 | << "hotel" | ||
3006 | 221 | << "uniform" | ||
3007 | 222 | << "alpha" | ||
3008 | 223 | << "echo" | ||
3009 | 224 | << "golf" | ||
3010 | 225 | << "quebec" | ||
3011 | 226 | << "foxtrot" | ||
3012 | 227 | << "india" | ||
3013 | 228 | << "romeo" | ||
3014 | 229 | << "november" | ||
3015 | 230 | << "oskar" | ||
3016 | 231 | << "zulu" | ||
3017 | 232 | << "kilo" | ||
3018 | 233 | << "whiskey" | ||
3019 | 234 | << "mike" | ||
3020 | 235 | << "papa" | ||
3021 | 236 | << "sierra" | ||
3022 | 237 | << "xray" | ||
3023 | 238 | << "viktor") | ||
3024 | 239 | << (QStringList() | ||
3025 | 240 | << "zulu" | ||
3026 | 241 | << "yankee" | ||
3027 | 242 | << "xray" | ||
3028 | 243 | << "whiskey" | ||
3029 | 244 | << "viktor" | ||
3030 | 245 | << "uniform" | ||
3031 | 246 | << "tango" | ||
3032 | 247 | << "sierra" | ||
3033 | 248 | << "romeo" | ||
3034 | 249 | << "quebec" | ||
3035 | 250 | << "papa" | ||
3036 | 251 | << "oskar" | ||
3037 | 252 | << "november" | ||
3038 | 253 | << "mike" | ||
3039 | 254 | << "lima" | ||
3040 | 255 | << "kilo" | ||
3041 | 256 | << "juliet" | ||
3042 | 257 | << "india" | ||
3043 | 258 | << "hotel" | ||
3044 | 259 | << "golf" | ||
3045 | 260 | << "foxtrot" | ||
3046 | 261 | << "echo" | ||
3047 | 262 | << "delta" | ||
3048 | 263 | << "charlie" | ||
3049 | 264 | << "bravo" | ||
3050 | 265 | << "alpha"); | ||
3051 | 266 | QTest::newRow("flat ascending") << static_cast<int>(Qt::AscendingOrder) | ||
3052 | 267 | << int(Qt::CaseSensitive) | ||
3053 | 268 | << (QStringList() | ||
3054 | 269 | << "delta" | ||
3055 | 270 | << "yankee" | ||
3056 | 271 | << "bravo" | ||
3057 | 272 | << "lima" | ||
3058 | 273 | << "charlie" | ||
3059 | 274 | << "juliet" | ||
3060 | 275 | << "tango" | ||
3061 | 276 | << "hotel" | ||
3062 | 277 | << "uniform" | ||
3063 | 278 | << "alpha" | ||
3064 | 279 | << "echo" | ||
3065 | 280 | << "golf" | ||
3066 | 281 | << "quebec" | ||
3067 | 282 | << "foxtrot" | ||
3068 | 283 | << "india" | ||
3069 | 284 | << "romeo" | ||
3070 | 285 | << "november" | ||
3071 | 286 | << "oskar" | ||
3072 | 287 | << "zulu" | ||
3073 | 288 | << "kilo" | ||
3074 | 289 | << "whiskey" | ||
3075 | 290 | << "mike" | ||
3076 | 291 | << "papa" | ||
3077 | 292 | << "sierra" | ||
3078 | 293 | << "xray" | ||
3079 | 294 | << "viktor") | ||
3080 | 295 | << (QStringList() | ||
3081 | 296 | << "alpha" | ||
3082 | 297 | << "bravo" | ||
3083 | 298 | << "charlie" | ||
3084 | 299 | << "delta" | ||
3085 | 300 | << "echo" | ||
3086 | 301 | << "foxtrot" | ||
3087 | 302 | << "golf" | ||
3088 | 303 | << "hotel" | ||
3089 | 304 | << "india" | ||
3090 | 305 | << "juliet" | ||
3091 | 306 | << "kilo" | ||
3092 | 307 | << "lima" | ||
3093 | 308 | << "mike" | ||
3094 | 309 | << "november" | ||
3095 | 310 | << "oskar" | ||
3096 | 311 | << "papa" | ||
3097 | 312 | << "quebec" | ||
3098 | 313 | << "romeo" | ||
3099 | 314 | << "sierra" | ||
3100 | 315 | << "tango" | ||
3101 | 316 | << "uniform" | ||
3102 | 317 | << "viktor" | ||
3103 | 318 | << "whiskey" | ||
3104 | 319 | << "xray" | ||
3105 | 320 | << "yankee" | ||
3106 | 321 | << "zulu"); | ||
3107 | 322 | QTest::newRow("case insensitive") << static_cast<int>(Qt::AscendingOrder) | ||
3108 | 323 | << int(Qt::CaseInsensitive) | ||
3109 | 324 | << (QStringList() | ||
3110 | 325 | << "alpha" << "BETA" << "Gamma" << "delta") | ||
3111 | 326 | << (QStringList() | ||
3112 | 327 | << "alpha" << "BETA" << "delta" << "Gamma"); | ||
3113 | 328 | QTest::newRow("case sensitive") << static_cast<int>(Qt::AscendingOrder) | ||
3114 | 329 | << int(Qt::CaseSensitive) | ||
3115 | 330 | << (QStringList() | ||
3116 | 331 | << "alpha" << "BETA" << "Gamma" << "delta") | ||
3117 | 332 | << (QStringList() | ||
3118 | 333 | << "BETA" << "Gamma" << "alpha" << "delta"); | ||
3119 | 334 | |||
3120 | 335 | QStringList list; | ||
3121 | 336 | for (int i = 10000; i < 20000; ++i) | ||
3122 | 337 | list.append(QString("Number: %1").arg(i)); | ||
3123 | 338 | QTest::newRow("large set ascending") << static_cast<int>(Qt::AscendingOrder) << int(Qt::CaseSensitive) << list << list; | ||
3124 | 339 | } | ||
3125 | 340 | |||
3126 | 341 | void tst_QSortFilterProxyModel::sort() | ||
3127 | 342 | { | ||
3128 | 343 | QFETCH(int, sortOrder); | ||
3129 | 344 | QFETCH(int, sortCaseSensitivity); | ||
3130 | 345 | QFETCH(QStringList, initial); | ||
3131 | 346 | QFETCH(QStringList, expected); | ||
3132 | 347 | |||
3133 | 348 | // prepare model | ||
3134 | 349 | QStandardItem *root = m_model->invisibleRootItem (); | ||
3135 | 350 | QList<QStandardItem *> items; | ||
3136 | 351 | for (int i = 0; i < initial.count(); ++i) { | ||
3137 | 352 | items.append(new QStandardItem(initial.at(i))); | ||
3138 | 353 | } | ||
3139 | 354 | root->insertRows(0, items); | ||
3140 | 355 | QCOMPARE(m_model->rowCount(QModelIndex()), initial.count()); | ||
3141 | 356 | QCOMPARE(m_model->columnCount(QModelIndex()), 1); | ||
3142 | 357 | |||
3143 | 358 | // make sure the proxy is unsorted | ||
3144 | 359 | QCOMPARE(m_proxy->columnCount(QModelIndex()), 1); | ||
3145 | 360 | QCOMPARE(m_proxy->rowCount(QModelIndex()), initial.count()); | ||
3146 | 361 | for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) { | ||
3147 | 362 | QModelIndex index = m_proxy->index(row, 0, QModelIndex()); | ||
3148 | 363 | QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row)); | ||
3149 | 364 | } | ||
3150 | 365 | |||
3151 | 366 | // sort | ||
3152 | 367 | m_proxy->sort(0, static_cast<Qt::SortOrder>(sortOrder)); | ||
3153 | 368 | m_proxy->setSortCaseSensitivity(static_cast<Qt::CaseSensitivity>(sortCaseSensitivity)); | ||
3154 | 369 | |||
3155 | 370 | // make sure the model is unchanged | ||
3156 | 371 | for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) { | ||
3157 | 372 | QModelIndex index = m_model->index(row, 0, QModelIndex()); | ||
3158 | 373 | QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row)); | ||
3159 | 374 | } | ||
3160 | 375 | // make sure the proxy is sorted | ||
3161 | 376 | for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) { | ||
3162 | 377 | QModelIndex index = m_proxy->index(row, 0, QModelIndex()); | ||
3163 | 378 | QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row)); | ||
3164 | 379 | } | ||
3165 | 380 | |||
3166 | 381 | // restore the unsorted order | ||
3167 | 382 | m_proxy->sort(-1); | ||
3168 | 383 | |||
3169 | 384 | // make sure the proxy is unsorted again | ||
3170 | 385 | for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) { | ||
3171 | 386 | QModelIndex index = m_proxy->index(row, 0, QModelIndex()); | ||
3172 | 387 | QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row)); | ||
3173 | 388 | } | ||
3174 | 389 | } | ||
3175 | 390 | |||
3176 | 391 | void tst_QSortFilterProxyModel::sortHierarchy_data() | ||
3177 | 392 | { | ||
3178 | 393 | QTest::addColumn<int>("sortOrder"); | ||
3179 | 394 | QTest::addColumn<QStringList>("initial"); | ||
3180 | 395 | QTest::addColumn<QStringList>("expected"); | ||
3181 | 396 | |||
3182 | 397 | QTest::newRow("flat ascending") | ||
3183 | 398 | << static_cast<int>(Qt::AscendingOrder) | ||
3184 | 399 | << (QStringList() | ||
3185 | 400 | << "c" << "f" << "d" << "e" << "a" << "b") | ||
3186 | 401 | << (QStringList() | ||
3187 | 402 | << "a" << "b" << "c" << "d" << "e" << "f"); | ||
3188 | 403 | |||
3189 | 404 | QTest::newRow("simple hierarchy") | ||
3190 | 405 | << static_cast<int>(Qt::AscendingOrder) | ||
3191 | 406 | << (QStringList() << "a" << "<" << "b" << "<" << "c" << ">" << ">") | ||
3192 | 407 | << (QStringList() << "a" << "<" << "b" << "<" << "c" << ">" << ">"); | ||
3193 | 408 | |||
3194 | 409 | QTest::newRow("hierarchical ascending") | ||
3195 | 410 | << static_cast<int>(Qt::AscendingOrder) | ||
3196 | 411 | << (QStringList() | ||
3197 | 412 | << "c" | ||
3198 | 413 | << "<" | ||
3199 | 414 | << "h" | ||
3200 | 415 | << "<" | ||
3201 | 416 | << "2" | ||
3202 | 417 | << "0" | ||
3203 | 418 | << "1" | ||
3204 | 419 | << ">" | ||
3205 | 420 | << "g" | ||
3206 | 421 | << "i" | ||
3207 | 422 | << ">" | ||
3208 | 423 | << "b" | ||
3209 | 424 | << "<" | ||
3210 | 425 | << "l" | ||
3211 | 426 | << "k" | ||
3212 | 427 | << "<" | ||
3213 | 428 | << "8" | ||
3214 | 429 | << "7" | ||
3215 | 430 | << "9" | ||
3216 | 431 | << ">" | ||
3217 | 432 | << "m" | ||
3218 | 433 | << ">" | ||
3219 | 434 | << "a" | ||
3220 | 435 | << "<" | ||
3221 | 436 | << "z" | ||
3222 | 437 | << "y" | ||
3223 | 438 | << "x" | ||
3224 | 439 | << ">") | ||
3225 | 440 | << (QStringList() | ||
3226 | 441 | << "a" | ||
3227 | 442 | << "<" | ||
3228 | 443 | << "x" | ||
3229 | 444 | << "y" | ||
3230 | 445 | << "z" | ||
3231 | 446 | << ">" | ||
3232 | 447 | << "b" | ||
3233 | 448 | << "<" | ||
3234 | 449 | << "k" | ||
3235 | 450 | << "<" | ||
3236 | 451 | << "7" | ||
3237 | 452 | << "8" | ||
3238 | 453 | << "9" | ||
3239 | 454 | << ">" | ||
3240 | 455 | << "l" | ||
3241 | 456 | << "m" | ||
3242 | 457 | << ">" | ||
3243 | 458 | << "c" | ||
3244 | 459 | << "<" | ||
3245 | 460 | << "g" | ||
3246 | 461 | << "h" | ||
3247 | 462 | << "<" | ||
3248 | 463 | << "0" | ||
3249 | 464 | << "1" | ||
3250 | 465 | << "2" | ||
3251 | 466 | << ">" | ||
3252 | 467 | << "i" | ||
3253 | 468 | << ">"); | ||
3254 | 469 | } | ||
3255 | 470 | |||
3256 | 471 | void tst_QSortFilterProxyModel::sortHierarchy() | ||
3257 | 472 | { | ||
3258 | 473 | QFETCH(int, sortOrder); | ||
3259 | 474 | QFETCH(QStringList, initial); | ||
3260 | 475 | QFETCH(QStringList, expected); | ||
3261 | 476 | |||
3262 | 477 | buildHierarchy(initial, m_model); | ||
3263 | 478 | checkHierarchy(initial, m_model); | ||
3264 | 479 | checkHierarchy(initial, m_proxy); | ||
3265 | 480 | m_proxy->sort(0, static_cast<Qt::SortOrder>(sortOrder)); | ||
3266 | 481 | checkHierarchy(initial, m_model); | ||
3267 | 482 | checkHierarchy(expected, m_proxy); | ||
3268 | 483 | } | ||
3269 | 484 | |||
3270 | 485 | void tst_QSortFilterProxyModel::insertRows_data() | ||
3271 | 486 | { | ||
3272 | 487 | QTest::addColumn<QStringList>("initial"); | ||
3273 | 488 | QTest::addColumn<QStringList>("expected"); | ||
3274 | 489 | QTest::addColumn<QStringList>("insert"); | ||
3275 | 490 | QTest::addColumn<int>("position"); | ||
3276 | 491 | |||
3277 | 492 | QTest::newRow("insert one row in the middle") | ||
3278 | 493 | << (QStringList() | ||
3279 | 494 | << "One" | ||
3280 | 495 | << "Two" | ||
3281 | 496 | << "Four" | ||
3282 | 497 | << "Five") | ||
3283 | 498 | << (QStringList() | ||
3284 | 499 | << "One" | ||
3285 | 500 | << "Two" | ||
3286 | 501 | << "Three" | ||
3287 | 502 | << "Four" | ||
3288 | 503 | << "Five") | ||
3289 | 504 | << (QStringList() | ||
3290 | 505 | << "Three") | ||
3291 | 506 | << 2; | ||
3292 | 507 | |||
3293 | 508 | QTest::newRow("insert one row in the beginning") | ||
3294 | 509 | << (QStringList() | ||
3295 | 510 | << "Two" | ||
3296 | 511 | << "Three" | ||
3297 | 512 | << "Four" | ||
3298 | 513 | << "Five") | ||
3299 | 514 | << (QStringList() | ||
3300 | 515 | << "One" | ||
3301 | 516 | << "Two" | ||
3302 | 517 | << "Three" | ||
3303 | 518 | << "Four" | ||
3304 | 519 | << "Five") | ||
3305 | 520 | << (QStringList() | ||
3306 | 521 | << "One") | ||
3307 | 522 | << 0; | ||
3308 | 523 | |||
3309 | 524 | QTest::newRow("insert one row in the end") | ||
3310 | 525 | << (QStringList() | ||
3311 | 526 | << "One" | ||
3312 | 527 | << "Two" | ||
3313 | 528 | << "Three" | ||
3314 | 529 | << "Four") | ||
3315 | 530 | << (QStringList() | ||
3316 | 531 | << "One" | ||
3317 | 532 | << "Two" | ||
3318 | 533 | << "Three" | ||
3319 | 534 | << "Four" | ||
3320 | 535 | << "Five") | ||
3321 | 536 | << (QStringList() | ||
3322 | 537 | <<"Five") | ||
3323 | 538 | << 4; | ||
3324 | 539 | } | ||
3325 | 540 | |||
3326 | 541 | void tst_QSortFilterProxyModel::insertRows() | ||
3327 | 542 | { | ||
3328 | 543 | QFETCH(QStringList, initial); | ||
3329 | 544 | QFETCH(QStringList, expected); | ||
3330 | 545 | QFETCH(QStringList, insert); | ||
3331 | 546 | QFETCH(int, position); | ||
3332 | 547 | // prepare model | ||
3333 | 548 | m_model->insertRows(0, initial.count(), QModelIndex()); | ||
3334 | 549 | //m_model->insertColumns(0, 1, QModelIndex()); | ||
3335 | 550 | QCOMPARE(m_model->columnCount(QModelIndex()), 1); | ||
3336 | 551 | QCOMPARE(m_model->rowCount(QModelIndex()), initial.count()); | ||
3337 | 552 | for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) { | ||
3338 | 553 | QModelIndex index = m_model->index(row, 0, QModelIndex()); | ||
3339 | 554 | m_model->setData(index, initial.at(row), Qt::DisplayRole); | ||
3340 | 555 | } | ||
3341 | 556 | // make sure the model correct before insert | ||
3342 | 557 | for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) { | ||
3343 | 558 | QModelIndex index = m_model->index(row, 0, QModelIndex()); | ||
3344 | 559 | QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row)); | ||
3345 | 560 | } | ||
3346 | 561 | // make sure the proxy is correct before insert | ||
3347 | 562 | for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) { | ||
3348 | 563 | QModelIndex index = m_proxy->index(row, 0, QModelIndex()); | ||
3349 | 564 | QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row)); | ||
3350 | 565 | } | ||
3351 | 566 | |||
3352 | 567 | // insert the row | ||
3353 | 568 | m_proxy->insertRows(position, insert.count(), QModelIndex()); | ||
3354 | 569 | QCOMPARE(m_model->rowCount(QModelIndex()), expected.count()); | ||
3355 | 570 | QCOMPARE(m_proxy->rowCount(QModelIndex()), expected.count()); | ||
3356 | 571 | |||
3357 | 572 | // set the data for the inserted row | ||
3358 | 573 | for (int i = 0; i < insert.count(); ++i) { | ||
3359 | 574 | QModelIndex index = m_proxy->index(position + i, 0, QModelIndex()); | ||
3360 | 575 | m_proxy->setData(index, insert.at(i), Qt::DisplayRole); | ||
3361 | 576 | } | ||
3362 | 577 | |||
3363 | 578 | // make sure the model correct after insert | ||
3364 | 579 | for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) { | ||
3365 | 580 | QModelIndex index = m_model->index(row, 0, QModelIndex()); | ||
3366 | 581 | QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), expected.at(row)); | ||
3367 | 582 | } | ||
3368 | 583 | |||
3369 | 584 | // make sure the proxy is correct after insert | ||
3370 | 585 | for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) { | ||
3371 | 586 | QModelIndex index = m_proxy->index(row, 0, QModelIndex()); | ||
3372 | 587 | QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row)); | ||
3373 | 588 | } | ||
3374 | 589 | } | ||
3375 | 590 | |||
3376 | 591 | void tst_QSortFilterProxyModel::prependRow() | ||
3377 | 592 | { | ||
3378 | 593 | //this tests that data is correctly handled by the sort filter when prepending a row | ||
3379 | 594 | QStandardItemModel model; | ||
3380 | 595 | QSortFilterProxyModel proxy; | ||
3381 | 596 | proxy.setSourceModel(&model); | ||
3382 | 597 | |||
3383 | 598 | QStandardItem item("root"); | ||
3384 | 599 | model.appendRow(&item); | ||
3385 | 600 | |||
3386 | 601 | QStandardItem sub("sub"); | ||
3387 | 602 | item.appendRow(&sub); | ||
3388 | 603 | |||
3389 | 604 | sub.appendRow(new QStandardItem("test1")); | ||
3390 | 605 | sub.appendRow(new QStandardItem("test2")); | ||
3391 | 606 | |||
3392 | 607 | QStandardItem sub2("sub2"); | ||
3393 | 608 | sub2.appendRow(new QStandardItem("sub3")); | ||
3394 | 609 | item.insertRow(0, &sub2); | ||
3395 | 610 | |||
3396 | 611 | QModelIndex index_sub2 = proxy.mapFromSource(model.indexFromItem(&sub2)); | ||
3397 | 612 | |||
3398 | 613 | QCOMPARE(sub2.rowCount(), proxy.rowCount(index_sub2)); | ||
3399 | 614 | QCOMPARE(proxy.rowCount(QModelIndex()), 1); //only the "root" item is there | ||
3400 | 615 | } | ||
3401 | 616 | |||
3402 | 617 | void tst_QSortFilterProxyModel::removeRows_data() | ||
3403 | 618 | { | ||
3404 | 619 | QTest::addColumn<QStringList>("initial"); | ||
3405 | 620 | QTest::addColumn<int>("sortOrder"); | ||
3406 | 621 | QTest::addColumn<QString>("filter"); | ||
3407 | 622 | QTest::addColumn<int>("position"); | ||
3408 | 623 | QTest::addColumn<int>("count"); | ||
3409 | 624 | QTest::addColumn<bool>("success"); | ||
3410 | 625 | QTest::addColumn<QStringList>("expectedProxy"); | ||
3411 | 626 | QTest::addColumn<QStringList>("expectedSource"); | ||
3412 | 627 | |||
3413 | 628 | QTest::newRow("remove one row in the middle [no sorting/filter]") | ||
3414 | 629 | << (QStringList() | ||
3415 | 630 | << "One" | ||
3416 | 631 | << "Two" | ||
3417 | 632 | << "Three" | ||
3418 | 633 | << "Four" | ||
3419 | 634 | << "Five") | ||
3420 | 635 | << -1 // no sorting | ||
3421 | 636 | << QString() // no filter | ||
3422 | 637 | << 2 // position | ||
3423 | 638 | << 1 // count | ||
3424 | 639 | << true // success | ||
3425 | 640 | << (QStringList() // expectedProxy | ||
3426 | 641 | << "One" | ||
3427 | 642 | << "Two" | ||
3428 | 643 | << "Four" | ||
3429 | 644 | << "Five") | ||
3430 | 645 | << (QStringList() // expectedSource | ||
3431 | 646 | << "One" | ||
3432 | 647 | << "Two" | ||
3433 | 648 | << "Four" | ||
3434 | 649 | << "Five"); | ||
3435 | 650 | |||
3436 | 651 | QTest::newRow("remove one row in the beginning [no sorting/filter]") | ||
3437 | 652 | << (QStringList() | ||
3438 | 653 | << "One" | ||
3439 | 654 | << "Two" | ||
3440 | 655 | << "Three" | ||
3441 | 656 | << "Four" | ||
3442 | 657 | << "Five") | ||
3443 | 658 | << -1 // no sorting | ||
3444 | 659 | << QString() // no filter | ||
3445 | 660 | << 0 // position | ||
3446 | 661 | << 1 // count | ||
3447 | 662 | << true // success | ||
3448 | 663 | << (QStringList() // expectedProxy | ||
3449 | 664 | << "Two" | ||
3450 | 665 | << "Three" | ||
3451 | 666 | << "Four" | ||
3452 | 667 | << "Five") | ||
3453 | 668 | << (QStringList() // expectedSource | ||
3454 | 669 | << "Two" | ||
3455 | 670 | << "Three" | ||
3456 | 671 | << "Four" | ||
3457 | 672 | << "Five"); | ||
3458 | 673 | |||
3459 | 674 | QTest::newRow("remove one row in the end [no sorting/filter]") | ||
3460 | 675 | << (QStringList() | ||
3461 | 676 | << "One" | ||
3462 | 677 | << "Two" | ||
3463 | 678 | << "Three" | ||
3464 | 679 | << "Four" | ||
3465 | 680 | << "Five") | ||
3466 | 681 | << -1 // no sorting | ||
3467 | 682 | << QString() // no filter | ||
3468 | 683 | << 4 // position | ||
3469 | 684 | << 1 // count | ||
3470 | 685 | << true // success | ||
3471 | 686 | << (QStringList() // expectedProxy | ||
3472 | 687 | << "One" | ||
3473 | 688 | << "Two" | ||
3474 | 689 | << "Three" | ||
3475 | 690 | << "Four") | ||
3476 | 691 | << (QStringList() // expectedSource | ||
3477 | 692 | << "One" | ||
3478 | 693 | << "Two" | ||
3479 | 694 | << "Three" | ||
3480 | 695 | << "Four"); | ||
3481 | 696 | |||
3482 | 697 | QTest::newRow("remove all [no sorting/filter]") | ||
3483 | 698 | << (QStringList() | ||
3484 | 699 | << "One" | ||
3485 | 700 | << "Two" | ||
3486 | 701 | << "Three" | ||
3487 | 702 | << "Four" | ||
3488 | 703 | << "Five") | ||
3489 | 704 | << -1 // no sorting | ||
3490 | 705 | << QString() // no filter | ||
3491 | 706 | << 0 // position | ||
3492 | 707 | << 5 // count | ||
3493 | 708 | << true // success | ||
3494 | 709 | << QStringList() // expectedProxy | ||
3495 | 710 | << QStringList(); // expectedSource | ||
3496 | 711 | |||
3497 | 712 | QTest::newRow("remove one row past the end [no sorting/filter]") | ||
3498 | 713 | << (QStringList() | ||
3499 | 714 | << "One" | ||
3500 | 715 | << "Two" | ||
3501 | 716 | << "Three" | ||
3502 | 717 | << "Four" | ||
3503 | 718 | << "Five") | ||
3504 | 719 | << -1 // no sorting | ||
3505 | 720 | << QString() // no filter | ||
3506 | 721 | << 5 // position | ||
3507 | 722 | << 1 // count | ||
3508 | 723 | << false // success | ||
3509 | 724 | << (QStringList() // expectedProxy | ||
3510 | 725 | << "One" | ||
3511 | 726 | << "Two" | ||
3512 | 727 | << "Three" | ||
3513 | 728 | << "Four" | ||
3514 | 729 | << "Five") | ||
3515 | 730 | << (QStringList() // expectedSource | ||
3516 | 731 | << "One" | ||
3517 | 732 | << "Two" | ||
3518 | 733 | << "Three" | ||
3519 | 734 | << "Four" | ||
3520 | 735 | << "Five"); | ||
3521 | 736 | |||
3522 | 737 | QTest::newRow("remove row -1 [no sorting/filter]") | ||
3523 | 738 | << (QStringList() | ||
3524 | 739 | << "One" | ||
3525 | 740 | << "Two" | ||
3526 | 741 | << "Three" | ||
3527 | 742 | << "Four" | ||
3528 | 743 | << "Five") | ||
3529 | 744 | << -1 // no sorting | ||
3530 | 745 | << QString() // no filter | ||
3531 | 746 | << -1 // position | ||
3532 | 747 | << 1 // count | ||
3533 | 748 | << false // success | ||
3534 | 749 | << (QStringList() // expectedProxy | ||
3535 | 750 | << "One" | ||
3536 | 751 | << "Two" | ||
3537 | 752 | << "Three" | ||
3538 | 753 | << "Four" | ||
3539 | 754 | << "Five") | ||
3540 | 755 | << (QStringList() // expectedSource | ||
3541 | 756 | << "One" | ||
3542 | 757 | << "Two" | ||
3543 | 758 | << "Three" | ||
3544 | 759 | << "Four" | ||
3545 | 760 | << "Five"); | ||
3546 | 761 | |||
3547 | 762 | QTest::newRow("remove three rows in the middle [no sorting/filter]") | ||
3548 | 763 | << (QStringList() | ||
3549 | 764 | << "One" | ||
3550 | 765 | << "Two" | ||
3551 | 766 | << "Three" | ||
3552 | 767 | << "Four" | ||
3553 | 768 | << "Five") | ||
3554 | 769 | << -1 // no sorting | ||
3555 | 770 | << QString() // no filter | ||
3556 | 771 | << 1 // position | ||
3557 | 772 | << 3 // count | ||
3558 | 773 | << true // success | ||
3559 | 774 | << (QStringList() // expectedProxy | ||
3560 | 775 | << "One" | ||
3561 | 776 | << "Five") | ||
3562 | 777 | << (QStringList() // expectedSource | ||
3563 | 778 | << "One" | ||
3564 | 779 | << "Five"); | ||
3565 | 780 | |||
3566 | 781 | QTest::newRow("remove one row in the middle [ascending sorting, no filter]") | ||
3567 | 782 | << (QStringList() | ||
3568 | 783 | << "1" | ||
3569 | 784 | << "5" | ||
3570 | 785 | << "2" | ||
3571 | 786 | << "4" | ||
3572 | 787 | << "3") | ||
3573 | 788 | << static_cast<int>(Qt::AscendingOrder) | ||
3574 | 789 | << QString() // no filter | ||
3575 | 790 | << 2 // position | ||
3576 | 791 | << 1 // count | ||
3577 | 792 | << true // success | ||
3578 | 793 | << (QStringList() // expectedProxy | ||
3579 | 794 | << "1" | ||
3580 | 795 | << "2" | ||
3581 | 796 | << "4" | ||
3582 | 797 | << "5") | ||
3583 | 798 | << (QStringList() // expectedSource | ||
3584 | 799 | << "1" | ||
3585 | 800 | << "5" | ||
3586 | 801 | << "2" | ||
3587 | 802 | << "4"); | ||
3588 | 803 | |||
3589 | 804 | QTest::newRow("remove two rows in the middle [ascending sorting, no filter]") | ||
3590 | 805 | << (QStringList() | ||
3591 | 806 | << "1" | ||
3592 | 807 | << "5" | ||
3593 | 808 | << "2" | ||
3594 | 809 | << "4" | ||
3595 | 810 | << "3") | ||
3596 | 811 | << static_cast<int>(Qt::AscendingOrder) | ||
3597 | 812 | << QString() // no filter | ||
3598 | 813 | << 2 // position | ||
3599 | 814 | << 2 // count | ||
3600 | 815 | << true // success | ||
3601 | 816 | << (QStringList() // expectedProxy | ||
3602 | 817 | << "1" | ||
3603 | 818 | << "2" | ||
3604 | 819 | << "5") | ||
3605 | 820 | << (QStringList() // expectedSource | ||
3606 | 821 | << "1" | ||
3607 | 822 | << "5" | ||
3608 | 823 | << "2"); | ||
3609 | 824 | |||
3610 | 825 | QTest::newRow("remove two rows in the middle [descending sorting, no filter]") | ||
3611 | 826 | << (QStringList() | ||
3612 | 827 | << "1" | ||
3613 | 828 | << "5" | ||
3614 | 829 | << "2" | ||
3615 | 830 | << "4" | ||
3616 | 831 | << "3") | ||
3617 | 832 | << static_cast<int>(Qt::DescendingOrder) | ||
3618 | 833 | << QString() // no filter | ||
3619 | 834 | << 2 // position | ||
3620 | 835 | << 2 // count | ||
3621 | 836 | << true // success | ||
3622 | 837 | << (QStringList() // expectedProxy | ||
3623 | 838 | << "5" | ||
3624 | 839 | << "4" | ||
3625 | 840 | << "1") | ||
3626 | 841 | << (QStringList() // expectedSource | ||
3627 | 842 | << "1" | ||
3628 | 843 | << "5" | ||
3629 | 844 | << "4"); | ||
3630 | 845 | |||
3631 | 846 | QTest::newRow("remove one row in the middle [no sorting, filter=5|2|3]") | ||
3632 | 847 | << (QStringList() | ||
3633 | 848 | << "1" | ||
3634 | 849 | << "5" | ||
3635 | 850 | << "2" | ||
3636 | 851 | << "4" | ||
3637 | 852 | << "3") | ||
3638 | 853 | << -1 // no sorting | ||
3639 | 854 | << QString("5|2|3") | ||
3640 | 855 | << 1 // position | ||
3641 | 856 | << 1 // count | ||
3642 | 857 | << true // success | ||
3643 | 858 | << (QStringList() // expectedProxy | ||
3644 | 859 | << "5" | ||
3645 | 860 | << "3") | ||
3646 | 861 | << (QStringList() // expectedSource | ||
3647 | 862 | << "1" | ||
3648 | 863 | << "5" | ||
3649 | 864 | << "4" | ||
3650 | 865 | << "3"); | ||
3651 | 866 | |||
3652 | 867 | QTest::newRow("remove all [ascending sorting, no filter]") | ||
3653 | 868 | << (QStringList() | ||
3654 | 869 | << "1" | ||
3655 | 870 | << "5" | ||
3656 | 871 | << "2" | ||
3657 | 872 | << "4" | ||
3658 | 873 | << "3") | ||
3659 | 874 | << static_cast<int>(Qt::AscendingOrder) | ||
3660 | 875 | << QString() // no filter | ||
3661 | 876 | << 0 // position | ||
3662 | 877 | << 5 // count | ||
3663 | 878 | << true // success | ||
3664 | 879 | << QStringList() // expectedProxy | ||
3665 | 880 | << QStringList(); // expectedSource | ||
3666 | 881 | } | ||
3667 | 882 | |||
3668 | 883 | void tst_QSortFilterProxyModel::removeRows() | ||
3669 | 884 | { | ||
3670 | 885 | QFETCH(QStringList, initial); | ||
3671 | 886 | QFETCH(int, sortOrder); | ||
3672 | 887 | QFETCH(QString, filter); | ||
3673 | 888 | QFETCH(int, position); | ||
3674 | 889 | QFETCH(int, count); | ||
3675 | 890 | QFETCH(bool, success); | ||
3676 | 891 | QFETCH(QStringList, expectedProxy); | ||
3677 | 892 | QFETCH(QStringList, expectedSource); | ||
3678 | 893 | |||
3679 | 894 | QStandardItemModel model; | ||
3680 | 895 | QSortFilterProxyModel proxy; | ||
3681 | 896 | proxy.setSourceModel(&model); | ||
3682 | 897 | |||
3683 | 898 | // prepare model | ||
3684 | 899 | foreach (QString s, initial) | ||
3685 | 900 | model.appendRow(new QStandardItem(s)); | ||
3686 | 901 | |||
3687 | 902 | if (sortOrder != -1) | ||
3688 | 903 | proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder)); | ||
3689 | 904 | if (!filter.isEmpty()) | ||
3690 | 905 | proxy.setFilterRegExp(QRegExp(filter)); | ||
3691 | 906 | |||
3692 | 907 | // remove the rows | ||
3693 | 908 | QCOMPARE(proxy.removeRows(position, count, QModelIndex()), success); | ||
3694 | 909 | QCOMPARE(model.rowCount(QModelIndex()), expectedSource.count()); | ||
3695 | 910 | QCOMPARE(proxy.rowCount(QModelIndex()), expectedProxy.count()); | ||
3696 | 911 | |||
3697 | 912 | // make sure the model is correct after remove | ||
3698 | 913 | for (int row = 0; row < model.rowCount(QModelIndex()); ++row) | ||
3699 | 914 | QCOMPARE(model.item(row)->text(), expectedSource.at(row)); | ||
3700 | 915 | |||
3701 | 916 | // make sure the proxy is correct after remove | ||
3702 | 917 | for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) { | ||
3703 | 918 | QModelIndex index = proxy.index(row, 0, QModelIndex()); | ||
3704 | 919 | QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expectedProxy.at(row)); | ||
3705 | 920 | } | ||
3706 | 921 | } | ||
3707 | 922 | |||
3708 | 923 | class MyFilteredColumnProxyModel : public QSortFilterProxyModel | ||
3709 | 924 | { | ||
3710 | 925 | Q_OBJECT | ||
3711 | 926 | public: | ||
3712 | 927 | MyFilteredColumnProxyModel(QObject *parent = 0) | ||
3713 | 928 | : QSortFilterProxyModel(parent) { } | ||
3714 | 929 | protected: | ||
3715 | 930 | bool filterAcceptsColumn(int sourceColumn, const QModelIndex &) const | ||
3716 | 931 | { | ||
3717 | 932 | QString key = sourceModel()->headerData(sourceColumn, Qt::Horizontal).toString(); | ||
3718 | 933 | return key.contains(filterRegExp()); | ||
3719 | 934 | } | ||
3720 | 935 | }; | ||
3721 | 936 | |||
3722 | 937 | void tst_QSortFilterProxyModel::removeColumns_data() | ||
3723 | 938 | { | ||
3724 | 939 | QTest::addColumn<QStringList>("initial"); | ||
3725 | 940 | QTest::addColumn<QString>("filter"); | ||
3726 | 941 | QTest::addColumn<int>("position"); | ||
3727 | 942 | QTest::addColumn<int>("count"); | ||
3728 | 943 | QTest::addColumn<bool>("success"); | ||
3729 | 944 | QTest::addColumn<QStringList>("expectedProxy"); | ||
3730 | 945 | QTest::addColumn<QStringList>("expectedSource"); | ||
3731 | 946 | |||
3732 | 947 | QTest::newRow("remove one column in the middle [no filter]") | ||
3733 | 948 | << (QStringList() | ||
3734 | 949 | << "1" | ||
3735 | 950 | << "2" | ||
3736 | 951 | << "3" | ||
3737 | 952 | << "4" | ||
3738 | 953 | << "5") | ||
3739 | 954 | << QString() // no filter | ||
3740 | 955 | << 2 // position | ||
3741 | 956 | << 1 // count | ||
3742 | 957 | << true // success | ||
3743 | 958 | << (QStringList() // expectedProxy | ||
3744 | 959 | << "1" | ||
3745 | 960 | << "2" | ||
3746 | 961 | << "4" | ||
3747 | 962 | << "5") | ||
3748 | 963 | << (QStringList() // expectedSource | ||
3749 | 964 | << "1" | ||
3750 | 965 | << "2" | ||
3751 | 966 | << "4" | ||
3752 | 967 | << "5"); | ||
3753 | 968 | |||
3754 | 969 | QTest::newRow("remove one column in the end [no filter]") | ||
3755 | 970 | << (QStringList() | ||
3756 | 971 | << "1" | ||
3757 | 972 | << "2" | ||
3758 | 973 | << "3" | ||
3759 | 974 | << "4" | ||
3760 | 975 | << "5") | ||
3761 | 976 | << QString() // no filter | ||
3762 | 977 | << 4 // position | ||
3763 | 978 | << 1 // count | ||
3764 | 979 | << true // success | ||
3765 | 980 | << (QStringList() // expectedProxy | ||
3766 | 981 | << "1" | ||
3767 | 982 | << "2" | ||
3768 | 983 | << "3" | ||
3769 | 984 | << "4") | ||
3770 | 985 | << (QStringList() // expectedSource | ||
3771 | 986 | << "1" | ||
3772 | 987 | << "2" | ||
3773 | 988 | << "3" | ||
3774 | 989 | << "4"); | ||
3775 | 990 | |||
3776 | 991 | QTest::newRow("remove one column past the end [no filter]") | ||
3777 | 992 | << (QStringList() | ||
3778 | 993 | << "1" | ||
3779 | 994 | << "2" | ||
3780 | 995 | << "3" | ||
3781 | 996 | << "4" | ||
3782 | 997 | << "5") | ||
3783 | 998 | << QString() // no filter | ||
3784 | 999 | << 5 // position | ||
3785 | 1000 | << 1 // count | ||
3786 | 1001 | << false // success | ||
3787 | 1002 | << (QStringList() // expectedProxy | ||
3788 | 1003 | << "1" | ||
3789 | 1004 | << "2" | ||
3790 | 1005 | << "3" | ||
3791 | 1006 | << "4" | ||
3792 | 1007 | << "5") | ||
3793 | 1008 | << (QStringList() // expectedSource | ||
3794 | 1009 | << "1" | ||
3795 | 1010 | << "2" | ||
3796 | 1011 | << "3" | ||
3797 | 1012 | << "4" | ||
3798 | 1013 | << "5"); | ||
3799 | 1014 | |||
3800 | 1015 | QTest::newRow("remove column -1 [no filter]") | ||
3801 | 1016 | << (QStringList() | ||
3802 | 1017 | << "1" | ||
3803 | 1018 | << "2" | ||
3804 | 1019 | << "3" | ||
3805 | 1020 | << "4" | ||
3806 | 1021 | << "5") | ||
3807 | 1022 | << QString() // no filter | ||
3808 | 1023 | << -1 // position | ||
3809 | 1024 | << 1 // count | ||
3810 | 1025 | << false // success | ||
3811 | 1026 | << (QStringList() // expectedProxy | ||
3812 | 1027 | << "1" | ||
3813 | 1028 | << "2" | ||
3814 | 1029 | << "3" | ||
3815 | 1030 | << "4" | ||
3816 | 1031 | << "5") | ||
3817 | 1032 | << (QStringList() // expectedSource | ||
3818 | 1033 | << "1" | ||
3819 | 1034 | << "2" | ||
3820 | 1035 | << "3" | ||
3821 | 1036 | << "4" | ||
3822 | 1037 | << "5"); | ||
3823 | 1038 | |||
3824 | 1039 | QTest::newRow("remove all columns [no filter]") | ||
3825 | 1040 | << (QStringList() | ||
3826 | 1041 | << "1" | ||
3827 | 1042 | << "2" | ||
3828 | 1043 | << "3" | ||
3829 | 1044 | << "4" | ||
3830 | 1045 | << "5") | ||
3831 | 1046 | << QString() // no filter | ||
3832 | 1047 | << 0 // position | ||
3833 | 1048 | << 5 // count | ||
3834 | 1049 | << true // success | ||
3835 | 1050 | << QStringList() // expectedProxy | ||
3836 | 1051 | << QStringList(); // expectedSource | ||
3837 | 1052 | |||
3838 | 1053 | QTest::newRow("remove one column in the middle [filter=1|3|5]") | ||
3839 | 1054 | << (QStringList() | ||
3840 | 1055 | << "1" | ||
3841 | 1056 | << "2" | ||
3842 | 1057 | << "3" | ||
3843 | 1058 | << "4" | ||
3844 | 1059 | << "5") | ||
3845 | 1060 | << QString("1|3|5") | ||
3846 | 1061 | << 1 // position | ||
3847 | 1062 | << 1 // count | ||
3848 | 1063 | << true // success | ||
3849 | 1064 | << (QStringList() // expectedProxy | ||
3850 | 1065 | << "1" | ||
3851 | 1066 | << "5") | ||
3852 | 1067 | << (QStringList() // expectedSource | ||
3853 | 1068 | << "1" | ||
3854 | 1069 | << "2" | ||
3855 | 1070 | << "4" | ||
3856 | 1071 | << "5"); | ||
3857 | 1072 | |||
3858 | 1073 | QTest::newRow("remove one column in the end [filter=1|3|5]") | ||
3859 | 1074 | << (QStringList() | ||
3860 | 1075 | << "1" | ||
3861 | 1076 | << "2" | ||
3862 | 1077 | << "3" | ||
3863 | 1078 | << "4" | ||
3864 | 1079 | << "5") | ||
3865 | 1080 | << QString("1|3|5") | ||
3866 | 1081 | << 2 // position | ||
3867 | 1082 | << 1 // count | ||
3868 | 1083 | << true // success | ||
3869 | 1084 | << (QStringList() // expectedProxy | ||
3870 | 1085 | << "1" | ||
3871 | 1086 | << "3") | ||
3872 | 1087 | << (QStringList() // expectedSource | ||
3873 | 1088 | << "1" | ||
3874 | 1089 | << "2" | ||
3875 | 1090 | << "3" | ||
3876 | 1091 | << "4"); | ||
3877 | 1092 | |||
3878 | 1093 | QTest::newRow("remove one column past the end [filter=1|3|5]") | ||
3879 | 1094 | << (QStringList() | ||
3880 | 1095 | << "1" | ||
3881 | 1096 | << "2" | ||
3882 | 1097 | << "3" | ||
3883 | 1098 | << "4" | ||
3884 | 1099 | << "5") | ||
3885 | 1100 | << QString("1|3|5") | ||
3886 | 1101 | << 3 // position | ||
3887 | 1102 | << 1 // count | ||
3888 | 1103 | << false // success | ||
3889 | 1104 | << (QStringList() // expectedProxy | ||
3890 | 1105 | << "1" | ||
3891 | 1106 | << "3" | ||
3892 | 1107 | << "5") | ||
3893 | 1108 | << (QStringList() // expectedSource | ||
3894 | 1109 | << "1" | ||
3895 | 1110 | << "2" | ||
3896 | 1111 | << "3" | ||
3897 | 1112 | << "4" | ||
3898 | 1113 | << "5"); | ||
3899 | 1114 | |||
3900 | 1115 | QTest::newRow("remove all columns [filter=1|3|5]") | ||
3901 | 1116 | << (QStringList() | ||
3902 | 1117 | << "1" | ||
3903 | 1118 | << "2" | ||
3904 | 1119 | << "3" | ||
3905 | 1120 | << "4" | ||
3906 | 1121 | << "5") | ||
3907 | 1122 | << QString("1|3|5") | ||
3908 | 1123 | << 0 // position | ||
3909 | 1124 | << 3 // count | ||
3910 | 1125 | << true // success | ||
3911 | 1126 | << QStringList() // expectedProxy | ||
3912 | 1127 | << (QStringList() // expectedSource | ||
3913 | 1128 | << "2" | ||
3914 | 1129 | << "4"); | ||
3915 | 1130 | } | ||
3916 | 1131 | |||
3917 | 1132 | void tst_QSortFilterProxyModel::removeColumns() | ||
3918 | 1133 | { | ||
3919 | 1134 | QFETCH(QStringList, initial); | ||
3920 | 1135 | QFETCH(QString, filter); | ||
3921 | 1136 | QFETCH(int, position); | ||
3922 | 1137 | QFETCH(int, count); | ||
3923 | 1138 | QFETCH(bool, success); | ||
3924 | 1139 | QFETCH(QStringList, expectedProxy); | ||
3925 | 1140 | QFETCH(QStringList, expectedSource); | ||
3926 | 1141 | |||
3927 | 1142 | QStandardItemModel model; | ||
3928 | 1143 | MyFilteredColumnProxyModel proxy; | ||
3929 | 1144 | proxy.setSourceModel(&model); | ||
3930 | 1145 | if (!filter.isEmpty()) | ||
3931 | 1146 | proxy.setFilterRegExp(QRegExp(filter)); | ||
3932 | 1147 | |||
3933 | 1148 | // prepare model | ||
3934 | 1149 | model.setHorizontalHeaderLabels(initial); | ||
3935 | 1150 | |||
3936 | 1151 | // remove the columns | ||
3937 | 1152 | QCOMPARE(proxy.removeColumns(position, count, QModelIndex()), success); | ||
3938 | 1153 | QCOMPARE(model.columnCount(QModelIndex()), expectedSource.count()); | ||
3939 | 1154 | QCOMPARE(proxy.columnCount(QModelIndex()), expectedProxy.count()); | ||
3940 | 1155 | |||
3941 | 1156 | // make sure the model is correct after remove | ||
3942 | 1157 | for (int col = 0; col < model.columnCount(QModelIndex()); ++col) | ||
3943 | 1158 | QCOMPARE(model.horizontalHeaderItem(col)->text(), expectedSource.at(col)); | ||
3944 | 1159 | |||
3945 | 1160 | // make sure the proxy is correct after remove | ||
3946 | 1161 | for (int col = 0; col < proxy.columnCount(QModelIndex()); ++col) { | ||
3947 | 1162 | QCOMPARE(proxy.headerData(col, Qt::Horizontal, Qt::DisplayRole).toString(), | ||
3948 | 1163 | expectedProxy.at(col)); | ||
3949 | 1164 | } | ||
3950 | 1165 | } | ||
3951 | 1166 | |||
3952 | 1167 | void tst_QSortFilterProxyModel::filterColumns_data() | ||
3953 | 1168 | { | ||
3954 | 1169 | QTest::addColumn<QString>("pattern"); | ||
3955 | 1170 | QTest::addColumn<QStringList>("initial"); | ||
3956 | 1171 | QTest::addColumn<bool>("data"); | ||
3957 | 1172 | |||
3958 | 1173 | QTest::newRow("all") << "a" | ||
3959 | 1174 | << (QStringList() | ||
3960 | 1175 | << "delta" | ||
3961 | 1176 | << "yankee" | ||
3962 | 1177 | << "bravo" | ||
3963 | 1178 | << "lima") | ||
3964 | 1179 | << true; | ||
3965 | 1180 | |||
3966 | 1181 | QTest::newRow("some") << "lie" | ||
3967 | 1182 | << (QStringList() | ||
3968 | 1183 | << "charlie" | ||
3969 | 1184 | << "juliet" | ||
3970 | 1185 | << "tango" | ||
3971 | 1186 | << "hotel") | ||
3972 | 1187 | << true; | ||
3973 | 1188 | |||
3974 | 1189 | QTest::newRow("nothing") << "zoo" | ||
3975 | 1190 | << (QStringList() | ||
3976 | 1191 | << "foxtrot" | ||
3977 | 1192 | << "uniform" | ||
3978 | 1193 | << "alpha" | ||
3979 | 1194 | << "golf") | ||
3980 | 1195 | << false; | ||
3981 | 1196 | } | ||
3982 | 1197 | |||
3983 | 1198 | void tst_QSortFilterProxyModel::filterColumns() | ||
3984 | 1199 | { | ||
3985 | 1200 | QFETCH(QString, pattern); | ||
3986 | 1201 | QFETCH(QStringList, initial); | ||
3987 | 1202 | QFETCH(bool, data); | ||
3988 | 1203 | // prepare model | ||
3989 | 1204 | m_model->setColumnCount(initial.count()); | ||
3990 | 1205 | m_model->setRowCount(1); | ||
3991 | 1206 | QCOMPARE(m_model->columnCount(QModelIndex()), initial.count()); | ||
3992 | 1207 | QCOMPARE(m_model->rowCount(QModelIndex()), 1); | ||
3993 | 1208 | // set data | ||
3994 | 1209 | QCOMPARE(m_model->rowCount(QModelIndex()), 1); | ||
3995 | 1210 | for (int col = 0; col < m_model->columnCount(QModelIndex()); ++col) { | ||
3996 | 1211 | QModelIndex index = m_model->index(0, col, QModelIndex()); | ||
3997 | 1212 | m_model->setData(index, initial.at(col), Qt::DisplayRole); | ||
3998 | 1213 | } | ||
3999 | 1214 | m_proxy->setFilterRegExp(pattern); | ||
4000 | 1215 | m_proxy->setFilterKeyColumn(-1); | ||
4001 | 1216 | // make sure the model is unchanged | ||
4002 | 1217 | for (int col = 0; col < m_model->columnCount(QModelIndex()); ++col) { | ||
4003 | 1218 | QModelIndex index = m_model->index(0, col, QModelIndex()); | ||
4004 | 1219 | QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(col)); | ||
4005 | 1220 | } | ||
4006 | 1221 | // make sure the proxy is filtered | ||
4007 | 1222 | QModelIndex index = m_proxy->index(0, 0, QModelIndex()); | ||
4008 | 1223 | QCOMPARE(index.isValid(), data); | ||
4009 | 1224 | } | ||
4010 | 1225 | |||
4011 | 1226 | void tst_QSortFilterProxyModel::filter_data() | ||
4012 | 1227 | { | ||
4013 | 1228 | QTest::addColumn<QString>("pattern"); | ||
4014 | 1229 | QTest::addColumn<QStringList>("initial"); | ||
4015 | 1230 | QTest::addColumn<QStringList>("expected"); | ||
4016 | 1231 | |||
4017 | 1232 | QTest::newRow("flat") << "e" | ||
4018 | 1233 | << (QStringList() | ||
4019 | 1234 | << "delta" | ||
4020 | 1235 | << "yankee" | ||
4021 | 1236 | << "bravo" | ||
4022 | 1237 | << "lima" | ||
4023 | 1238 | << "charlie" | ||
4024 | 1239 | << "juliet" | ||
4025 | 1240 | << "tango" | ||
4026 | 1241 | << "hotel" | ||
4027 | 1242 | << "uniform" | ||
4028 | 1243 | << "alpha" | ||
4029 | 1244 | << "echo" | ||
4030 | 1245 | << "golf" | ||
4031 | 1246 | << "quebec" | ||
4032 | 1247 | << "foxtrot" | ||
4033 | 1248 | << "india" | ||
4034 | 1249 | << "romeo" | ||
4035 | 1250 | << "november" | ||
4036 | 1251 | << "oskar" | ||
4037 | 1252 | << "zulu" | ||
4038 | 1253 | << "kilo" | ||
4039 | 1254 | << "whiskey" | ||
4040 | 1255 | << "mike" | ||
4041 | 1256 | << "papa" | ||
4042 | 1257 | << "sierra" | ||
4043 | 1258 | << "xray" | ||
4044 | 1259 | << "viktor") | ||
4045 | 1260 | << (QStringList() | ||
4046 | 1261 | << "delta" | ||
4047 | 1262 | << "yankee" | ||
4048 | 1263 | << "charlie" | ||
4049 | 1264 | << "juliet" | ||
4050 | 1265 | << "hotel" | ||
4051 | 1266 | << "echo" | ||
4052 | 1267 | << "quebec" | ||
4053 | 1268 | << "romeo" | ||
4054 | 1269 | << "november" | ||
4055 | 1270 | << "whiskey" | ||
4056 | 1271 | << "mike" | ||
4057 | 1272 | << "sierra"); | ||
4058 | 1273 | } | ||
4059 | 1274 | |||
4060 | 1275 | void tst_QSortFilterProxyModel::filter() | ||
4061 | 1276 | { | ||
4062 | 1277 | QFETCH(QString, pattern); | ||
4063 | 1278 | QFETCH(QStringList, initial); | ||
4064 | 1279 | QFETCH(QStringList, expected); | ||
4065 | 1280 | // prepare model | ||
4066 | 1281 | QVERIFY(m_model->insertRows(0, initial.count(), QModelIndex())); | ||
4067 | 1282 | QCOMPARE(m_model->rowCount(QModelIndex()), initial.count()); | ||
4068 | 1283 | // set data | ||
4069 | 1284 | QCOMPARE(m_model->columnCount(QModelIndex()), 1); | ||
4070 | 1285 | for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) { | ||
4071 | 1286 | QModelIndex index = m_model->index(row, 0, QModelIndex()); | ||
4072 | 1287 | m_model->setData(index, initial.at(row), Qt::DisplayRole); | ||
4073 | 1288 | } | ||
4074 | 1289 | m_proxy->setFilterRegExp(pattern); | ||
4075 | 1290 | // make sure the proxy is unfiltered | ||
4076 | 1291 | QCOMPARE(m_proxy->columnCount(QModelIndex()), 1); | ||
4077 | 1292 | QCOMPARE(m_proxy->rowCount(QModelIndex()), expected.count()); | ||
4078 | 1293 | // make sure the model is unchanged | ||
4079 | 1294 | for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) { | ||
4080 | 1295 | QModelIndex index = m_model->index(row, 0, QModelIndex()); | ||
4081 | 1296 | QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row)); | ||
4082 | 1297 | } | ||
4083 | 1298 | // make sure the proxy is filtered | ||
4084 | 1299 | for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) { | ||
4085 | 1300 | QModelIndex index = m_proxy->index(row, 0, QModelIndex()); | ||
4086 | 1301 | QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row)); | ||
4087 | 1302 | } | ||
4088 | 1303 | } | ||
4089 | 1304 | |||
4090 | 1305 | void tst_QSortFilterProxyModel::filterHierarchy_data() | ||
4091 | 1306 | { | ||
4092 | 1307 | QTest::addColumn<QString>("pattern"); | ||
4093 | 1308 | QTest::addColumn<QStringList>("initial"); | ||
4094 | 1309 | QTest::addColumn<QStringList>("expected"); | ||
4095 | 1310 | |||
4096 | 1311 | QTest::newRow("flat") << ".*oo" | ||
4097 | 1312 | << (QStringList() | ||
4098 | 1313 | << "foo" << "boo" << "baz" << "moo" << "laa" << "haa") | ||
4099 | 1314 | << (QStringList() | ||
4100 | 1315 | << "foo" << "boo" << "moo"); | ||
4101 | 1316 | |||
4102 | 1317 | QTest::newRow("simple hierarchy") << "b.*z" | ||
4103 | 1318 | << (QStringList() << "baz" << "<" << "boz" << "<" << "moo" << ">" << ">") | ||
4104 | 1319 | << (QStringList() << "baz" << "<" << "boz" << ">"); | ||
4105 | 1320 | } | ||
4106 | 1321 | |||
4107 | 1322 | void tst_QSortFilterProxyModel::filterHierarchy() | ||
4108 | 1323 | { | ||
4109 | 1324 | QFETCH(QString, pattern); | ||
4110 | 1325 | QFETCH(QStringList, initial); | ||
4111 | 1326 | QFETCH(QStringList, expected); | ||
4112 | 1327 | buildHierarchy(initial, m_model); | ||
4113 | 1328 | m_proxy->setFilterRegExp(pattern); | ||
4114 | 1329 | checkHierarchy(initial, m_model); | ||
4115 | 1330 | checkHierarchy(expected, m_proxy); | ||
4116 | 1331 | } | ||
4117 | 1332 | |||
4118 | 1333 | void tst_QSortFilterProxyModel::buildHierarchy(const QStringList &l, QAbstractItemModel *m) | ||
4119 | 1334 | { | ||
4120 | 1335 | int ind = 0; | ||
4121 | 1336 | int row = 0; | ||
4122 | 1337 | QStack<int> row_stack; | ||
4123 | 1338 | QModelIndex parent; | ||
4124 | 1339 | QStack<QModelIndex> parent_stack; | ||
4125 | 1340 | for (int i = 0; i < l.count(); ++i) { | ||
4126 | 1341 | QString token = l.at(i); | ||
4127 | 1342 | if (token == "<") { // start table | ||
4128 | 1343 | ++ind; | ||
4129 | 1344 | parent_stack.push(parent); | ||
4130 | 1345 | row_stack.push(row); | ||
4131 | 1346 | parent = m->index(row - 1, 0, parent); | ||
4132 | 1347 | row = 0; | ||
4133 | 1348 | QVERIFY(m->insertColumns(0, 1, parent)); // add column | ||
4134 | 1349 | } else if (token == ">") { // end table | ||
4135 | 1350 | --ind; | ||
4136 | 1351 | parent = parent_stack.pop(); | ||
4137 | 1352 | row = row_stack.pop(); | ||
4138 | 1353 | } else { // append row | ||
4139 | 1354 | QVERIFY(m->insertRows(row, 1, parent)); | ||
4140 | 1355 | QModelIndex index = m->index(row, 0, parent); | ||
4141 | 1356 | QVERIFY(index.isValid()); | ||
4142 | 1357 | m->setData(index, token, Qt::DisplayRole); | ||
4143 | 1358 | ++row; | ||
4144 | 1359 | } | ||
4145 | 1360 | } | ||
4146 | 1361 | } | ||
4147 | 1362 | |||
4148 | 1363 | void tst_QSortFilterProxyModel::checkHierarchy(const QStringList &l, const QAbstractItemModel *m) | ||
4149 | 1364 | { | ||
4150 | 1365 | int row = 0; | ||
4151 | 1366 | int indent = 0; | ||
4152 | 1367 | QStack<int> row_stack; | ||
4153 | 1368 | QModelIndex parent; | ||
4154 | 1369 | QStack<QModelIndex> parent_stack; | ||
4155 | 1370 | for (int i = 0; i < l.count(); ++i) { | ||
4156 | 1371 | QString token = l.at(i); | ||
4157 | 1372 | if (token == "<") { // start table | ||
4158 | 1373 | ++indent; | ||
4159 | 1374 | parent_stack.push(parent); | ||
4160 | 1375 | row_stack.push(row); | ||
4161 | 1376 | parent = m->index(row - 1, 0, parent); | ||
4162 | 1377 | QVERIFY(parent.isValid()); | ||
4163 | 1378 | row = 0; | ||
4164 | 1379 | } else if (token == ">") { // end table | ||
4165 | 1380 | --indent; | ||
4166 | 1381 | parent = parent_stack.pop(); | ||
4167 | 1382 | row = row_stack.pop(); | ||
4168 | 1383 | } else { // compare row | ||
4169 | 1384 | QModelIndex index = m->index(row, 0, parent); | ||
4170 | 1385 | QVERIFY(index.isValid()); | ||
4171 | 1386 | QString str = m->data(index, Qt::DisplayRole).toString(); | ||
4172 | 1387 | QCOMPARE(str, token); | ||
4173 | 1388 | ++row; | ||
4174 | 1389 | } | ||
4175 | 1390 | } | ||
4176 | 1391 | } | ||
4177 | 1392 | |||
4178 | 1393 | class TestModel: public QAbstractTableModel | ||
4179 | 1394 | { | ||
4180 | 1395 | public: | ||
4181 | 1396 | int rowCount(const QModelIndex &) const { return 10000; } | ||
4182 | 1397 | int columnCount(const QModelIndex &) const { return 1; } | ||
4183 | 1398 | QVariant data(const QModelIndex &index, int role) const | ||
4184 | 1399 | { | ||
4185 | 1400 | if (role != Qt::DisplayRole) | ||
4186 | 1401 | return QVariant(); | ||
4187 | 1402 | return QString::number(index.row()); | ||
4188 | 1403 | } | ||
4189 | 1404 | }; | ||
4190 | 1405 | |||
4191 | 1406 | void tst_QSortFilterProxyModel::filterTable() | ||
4192 | 1407 | { | ||
4193 | 1408 | TestModel model; | ||
4194 | 1409 | QSortFilterProxyModel filter; | ||
4195 | 1410 | filter.setSourceModel(&model); | ||
4196 | 1411 | filter.setFilterRegExp("9"); | ||
4197 | 1412 | |||
4198 | 1413 | for (int i = 0; i < filter.rowCount(); ++i) | ||
4199 | 1414 | QVERIFY(filter.data(filter.index(i, 0)).toString().contains("9")); | ||
4200 | 1415 | } | ||
4201 | 1416 | |||
4202 | 1417 | void tst_QSortFilterProxyModel::insertAfterSelect() | ||
4203 | 1418 | { | ||
4204 | 1419 | QStandardItemModel model(10, 2); | ||
4205 | 1420 | for (int i = 0; i<10;i++) | ||
4206 | 1421 | model.setData(model.index(i, 0), QVariant(i)); | ||
4207 | 1422 | QSortFilterProxyModel filter; | ||
4208 | 1423 | filter.setSourceModel(&model); | ||
4209 | 1424 | QTreeView view; | ||
4210 | 1425 | view.setModel(&filter); | ||
4211 | 1426 | view.show(); | ||
4212 | 1427 | QModelIndex firstIndex = filter.mapFromSource(model.index(0, 0, QModelIndex())); | ||
4213 | 1428 | QCOMPARE(firstIndex.model(), (const QAbstractItemModel *)view.model()); | ||
4214 | 1429 | QVERIFY(firstIndex.isValid()); | ||
4215 | 1430 | int itemOffset = view.visualRect(firstIndex).width() / 2; | ||
4216 | 1431 | QPoint p(itemOffset, 1); | ||
4217 | 1432 | QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p); | ||
4218 | 1433 | QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); | ||
4219 | 1434 | model.insertRows(5, 1, QModelIndex()); | ||
4220 | 1435 | QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); // Should still have a selection | ||
4221 | 1436 | } | ||
4222 | 1437 | |||
4223 | 1438 | void tst_QSortFilterProxyModel::removeAfterSelect() | ||
4224 | 1439 | { | ||
4225 | 1440 | QStandardItemModel model(10, 2); | ||
4226 | 1441 | for (int i = 0; i<10;i++) | ||
4227 | 1442 | model.setData(model.index(i, 0), QVariant(i)); | ||
4228 | 1443 | QSortFilterProxyModel filter; | ||
4229 | 1444 | filter.setSourceModel(&model); | ||
4230 | 1445 | QTreeView view; | ||
4231 | 1446 | view.setModel(&filter); | ||
4232 | 1447 | view.show(); | ||
4233 | 1448 | QModelIndex firstIndex = filter.mapFromSource(model.index(0, 0, QModelIndex())); | ||
4234 | 1449 | QCOMPARE(firstIndex.model(), (const QAbstractItemModel *)view.model()); | ||
4235 | 1450 | QVERIFY(firstIndex.isValid()); | ||
4236 | 1451 | int itemOffset = view.visualRect(firstIndex).width() / 2; | ||
4237 | 1452 | QPoint p(itemOffset, 1); | ||
4238 | 1453 | QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p); | ||
4239 | 1454 | QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); | ||
4240 | 1455 | model.removeRows(5, 1, QModelIndex()); | ||
4241 | 1456 | QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); // Should still have a selection | ||
4242 | 1457 | } | ||
4243 | 1458 | |||
4244 | 1459 | void tst_QSortFilterProxyModel::filterCurrent() | ||
4245 | 1460 | { | ||
4246 | 1461 | QStandardItemModel model(2, 1); | ||
4247 | 1462 | model.setData(model.index(0, 0), QString("AAA")); | ||
4248 | 1463 | model.setData(model.index(1, 0), QString("BBB")); | ||
4249 | 1464 | QSortFilterProxyModel proxy; | ||
4250 | 1465 | proxy.setSourceModel(&model); | ||
4251 | 1466 | QTreeView view; | ||
4252 | 1467 | |||
4253 | 1468 | view.show(); | ||
4254 | 1469 | view.setModel(&proxy); | ||
4255 | 1470 | QSignalSpy spy(view.selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex))); | ||
4256 | 1471 | QVERIFY(spy.isValid()); | ||
4257 | 1472 | |||
4258 | 1473 | view.setCurrentIndex(proxy.index(0, 0)); | ||
4259 | 1474 | QCOMPARE(spy.count(), 1); | ||
4260 | 1475 | proxy.setFilterRegExp(QRegExp("^B")); | ||
4261 | 1476 | QCOMPARE(spy.count(), 2); | ||
4262 | 1477 | } | ||
4263 | 1478 | |||
4264 | 1479 | void tst_QSortFilterProxyModel::changeSourceLayout() | ||
4265 | 1480 | { | ||
4266 | 1481 | QStandardItemModel model(2, 1); | ||
4267 | 1482 | model.setData(model.index(0, 0), QString("b")); | ||
4268 | 1483 | model.setData(model.index(1, 0), QString("a")); | ||
4269 | 1484 | QSortFilterProxyModel proxy; | ||
4270 | 1485 | proxy.setSourceModel(&model); | ||
4271 | 1486 | |||
4272 | 1487 | QList<QPersistentModelIndex> persistentSourceIndexes; | ||
4273 | 1488 | QList<QPersistentModelIndex> persistentProxyIndexes; | ||
4274 | 1489 | for (int row = 0; row < model.rowCount(); ++row) { | ||
4275 | 1490 | persistentSourceIndexes.append(model.index(row, 0)); | ||
4276 | 1491 | persistentProxyIndexes.append(proxy.index(row, 0)); | ||
4277 | 1492 | } | ||
4278 | 1493 | |||
4279 | 1494 | // change layout of source model | ||
4280 | 1495 | model.sort(0, Qt::AscendingOrder); | ||
4281 | 1496 | |||
4282 | 1497 | for (int row = 0; row < model.rowCount(); ++row) { | ||
4283 | 1498 | QCOMPARE(persistentProxyIndexes.at(row).row(), | ||
4284 | 1499 | persistentSourceIndexes.at(row).row()); | ||
4285 | 1500 | } | ||
4286 | 1501 | } | ||
4287 | 1502 | |||
4288 | 1503 | void tst_QSortFilterProxyModel::removeSourceRows_data() | ||
4289 | 1504 | { | ||
4290 | 1505 | QTest::addColumn<QStringList>("sourceItems"); | ||
4291 | 1506 | QTest::addColumn<int>("start"); | ||
4292 | 1507 | QTest::addColumn<int>("count"); | ||
4293 | 1508 | QTest::addColumn<int>("sortOrder"); | ||
4294 | 1509 | QTest::addColumn<IntPairList>("expectedRemovedProxyIntervals"); | ||
4295 | 1510 | QTest::addColumn<QStringList>("expectedProxyItems"); | ||
4296 | 1511 | |||
4297 | 1512 | QTest::newRow("remove one, no sorting") | ||
4298 | 1513 | << (QStringList() << "a" << "b") // sourceItems | ||
4299 | 1514 | << 0 // start | ||
4300 | 1515 | << 1 // count | ||
4301 | 1516 | << -1 // sortOrder (no sorting) | ||
4302 | 1517 | << (IntPairList() << IntPair(0, 0)) // expectedRemovedIntervals | ||
4303 | 1518 | << (QStringList() << "b") // expectedProxyItems | ||
4304 | 1519 | ; | ||
4305 | 1520 | QTest::newRow("remove one, ascending sort (same order)") | ||
4306 | 1521 | << (QStringList() << "a" << "b") // sourceItems | ||
4307 | 1522 | << 0 // start | ||
4308 | 1523 | << 1 // count | ||
4309 | 1524 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4310 | 1525 | << (IntPairList() << IntPair(0, 0)) // expectedRemovedIntervals | ||
4311 | 1526 | << (QStringList() << "b") // expectedProxyItems | ||
4312 | 1527 | ; | ||
4313 | 1528 | QTest::newRow("remove one, ascending sort (reverse order)") | ||
4314 | 1529 | << (QStringList() << "b" << "a") // sourceItems | ||
4315 | 1530 | << 0 // start | ||
4316 | 1531 | << 1 // count | ||
4317 | 1532 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4318 | 1533 | << (IntPairList() << IntPair(1, 1)) // expectedRemovedIntervals | ||
4319 | 1534 | << (QStringList() << "a") // expectedProxyItems | ||
4320 | 1535 | ; | ||
4321 | 1536 | QTest::newRow("remove two, multiple proxy intervals") | ||
4322 | 1537 | << (QStringList() << "c" << "d" << "a" << "b") // sourceItems | ||
4323 | 1538 | << 1 // start | ||
4324 | 1539 | << 2 // count | ||
4325 | 1540 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4326 | 1541 | << (IntPairList() << IntPair(3, 3) << IntPair(0, 0)) // expectedRemovedIntervals | ||
4327 | 1542 | << (QStringList() << "b" << "c") // expectedProxyItems | ||
4328 | 1543 | ; | ||
4329 | 1544 | QTest::newRow("remove three, multiple proxy intervals") | ||
4330 | 1545 | << (QStringList() << "b" << "d" << "f" << "a" << "c" << "e") // sourceItems | ||
4331 | 1546 | << 3 // start | ||
4332 | 1547 | << 3 // count | ||
4333 | 1548 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4334 | 1549 | << (IntPairList() << IntPair(4, 4) << IntPair(2, 2) << IntPair(0, 0)) // expectedRemovedIntervals | ||
4335 | 1550 | << (QStringList() << "b" << "d" << "f") // expectedProxyItems | ||
4336 | 1551 | ; | ||
4337 | 1552 | QTest::newRow("remove all, single proxy intervals") | ||
4338 | 1553 | << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems | ||
4339 | 1554 | << 0 // start | ||
4340 | 1555 | << 6 // count | ||
4341 | 1556 | << static_cast<int>(Qt::DescendingOrder) // sortOrder | ||
4342 | 1557 | << (IntPairList() << IntPair(0, 5)) // expectedRemovedIntervals | ||
4343 | 1558 | << QStringList() // expectedProxyItems | ||
4344 | 1559 | ; | ||
4345 | 1560 | } | ||
4346 | 1561 | |||
4347 | 1562 | // Check that correct proxy model rows are removed when rows are removed | ||
4348 | 1563 | // from the source model | ||
4349 | 1564 | void tst_QSortFilterProxyModel::removeSourceRows() | ||
4350 | 1565 | { | ||
4351 | 1566 | QFETCH(QStringList, sourceItems); | ||
4352 | 1567 | QFETCH(int, start); | ||
4353 | 1568 | QFETCH(int, count); | ||
4354 | 1569 | QFETCH(int, sortOrder); | ||
4355 | 1570 | QFETCH(IntPairList, expectedRemovedProxyIntervals); | ||
4356 | 1571 | QFETCH(QStringList, expectedProxyItems); | ||
4357 | 1572 | |||
4358 | 1573 | QStandardItemModel model; | ||
4359 | 1574 | QSortFilterProxyModel proxy; | ||
4360 | 1575 | |||
4361 | 1576 | proxy.setSourceModel(&model); | ||
4362 | 1577 | model.insertColumns(0, 1); | ||
4363 | 1578 | model.insertRows(0, sourceItems.count()); | ||
4364 | 1579 | |||
4365 | 1580 | for (int i = 0; i < sourceItems.count(); ++i) { | ||
4366 | 1581 | QModelIndex sindex = model.index(i, 0, QModelIndex()); | ||
4367 | 1582 | model.setData(sindex, sourceItems.at(i), Qt::DisplayRole); | ||
4368 | 1583 | QModelIndex pindex = proxy.index(i, 0, QModelIndex()); | ||
4369 | 1584 | QCOMPARE(proxy.data(pindex, Qt::DisplayRole), model.data(sindex, Qt::DisplayRole)); | ||
4370 | 1585 | } | ||
4371 | 1586 | |||
4372 | 1587 | if (sortOrder != -1) | ||
4373 | 1588 | proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder)); | ||
4374 | 1589 | (void)proxy.rowCount(QModelIndex()); // force mapping | ||
4375 | 1590 | |||
4376 | 1591 | QSignalSpy removeSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex,int,int))); | ||
4377 | 1592 | QSignalSpy insertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex,int,int))); | ||
4378 | 1593 | QSignalSpy aboutToRemoveSpy(&proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); | ||
4379 | 1594 | QSignalSpy aboutToInsertSpy(&proxy, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); | ||
4380 | 1595 | |||
4381 | 1596 | QVERIFY(removeSpy.isValid()); | ||
4382 | 1597 | QVERIFY(insertSpy.isValid()); | ||
4383 | 1598 | QVERIFY(aboutToRemoveSpy.isValid()); | ||
4384 | 1599 | QVERIFY(aboutToInsertSpy.isValid()); | ||
4385 | 1600 | |||
4386 | 1601 | model.removeRows(start, count, QModelIndex()); | ||
4387 | 1602 | |||
4388 | 1603 | QCOMPARE(aboutToRemoveSpy.count(), expectedRemovedProxyIntervals.count()); | ||
4389 | 1604 | for (int i = 0; i < aboutToRemoveSpy.count(); ++i) { | ||
4390 | 1605 | QList<QVariant> args = aboutToRemoveSpy.at(i); | ||
4391 | 1606 | QVERIFY(args.at(1).type() == QVariant::Int); | ||
4392 | 1607 | QVERIFY(args.at(2).type() == QVariant::Int); | ||
4393 | 1608 | QCOMPARE(args.at(1).toInt(), expectedRemovedProxyIntervals.at(i).first); | ||
4394 | 1609 | QCOMPARE(args.at(2).toInt(), expectedRemovedProxyIntervals.at(i).second); | ||
4395 | 1610 | } | ||
4396 | 1611 | QCOMPARE(removeSpy.count(), expectedRemovedProxyIntervals.count()); | ||
4397 | 1612 | for (int i = 0; i < removeSpy.count(); ++i) { | ||
4398 | 1613 | QList<QVariant> args = removeSpy.at(i); | ||
4399 | 1614 | QVERIFY(args.at(1).type() == QVariant::Int); | ||
4400 | 1615 | QVERIFY(args.at(2).type() == QVariant::Int); | ||
4401 | 1616 | QCOMPARE(args.at(1).toInt(), expectedRemovedProxyIntervals.at(i).first); | ||
4402 | 1617 | QCOMPARE(args.at(2).toInt(), expectedRemovedProxyIntervals.at(i).second); | ||
4403 | 1618 | } | ||
4404 | 1619 | |||
4405 | 1620 | QCOMPARE(insertSpy.count(), 0); | ||
4406 | 1621 | QCOMPARE(aboutToInsertSpy.count(), 0); | ||
4407 | 1622 | |||
4408 | 1623 | QCOMPARE(proxy.rowCount(QModelIndex()), expectedProxyItems.count()); | ||
4409 | 1624 | for (int i = 0; i < expectedProxyItems.count(); ++i) { | ||
4410 | 1625 | QModelIndex pindex = proxy.index(i, 0, QModelIndex()); | ||
4411 | 1626 | QCOMPARE(proxy.data(pindex, Qt::DisplayRole).toString(), expectedProxyItems.at(i)); | ||
4412 | 1627 | } | ||
4413 | 1628 | } | ||
4414 | 1629 | |||
4415 | 1630 | void tst_QSortFilterProxyModel::insertSourceRows_data() | ||
4416 | 1631 | { | ||
4417 | 1632 | QTest::addColumn<QStringList>("sourceItems"); | ||
4418 | 1633 | QTest::addColumn<int>("start"); | ||
4419 | 1634 | QTest::addColumn<QStringList>("newItems"); | ||
4420 | 1635 | QTest::addColumn<int>("sortOrder"); | ||
4421 | 1636 | QTest::addColumn<QStringList>("proxyItems"); | ||
4422 | 1637 | |||
4423 | 1638 | QTest::newRow("insert (1)") | ||
4424 | 1639 | << (QStringList() << "c" << "b") // sourceItems | ||
4425 | 1640 | << 1 // start | ||
4426 | 1641 | << (QStringList() << "a") // newItems | ||
4427 | 1642 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4428 | 1643 | << (QStringList() << "a" << "b" << "c") // proxyItems | ||
4429 | 1644 | ; | ||
4430 | 1645 | |||
4431 | 1646 | QTest::newRow("insert (2)") | ||
4432 | 1647 | << (QStringList() << "d" << "b" << "c") // sourceItems | ||
4433 | 1648 | << 3 // start | ||
4434 | 1649 | << (QStringList() << "a") // newItems | ||
4435 | 1650 | << static_cast<int>(Qt::DescendingOrder) // sortOrder | ||
4436 | 1651 | << (QStringList() << "d" << "c" << "b" << "a") // proxyItems | ||
4437 | 1652 | ; | ||
4438 | 1653 | } | ||
4439 | 1654 | |||
4440 | 1655 | // Check that rows are inserted at correct position in proxy model when | ||
4441 | 1656 | // rows are inserted into the source model | ||
4442 | 1657 | void tst_QSortFilterProxyModel::insertSourceRows() | ||
4443 | 1658 | { | ||
4444 | 1659 | QFETCH(QStringList, sourceItems); | ||
4445 | 1660 | QFETCH(int, start); | ||
4446 | 1661 | QFETCH(QStringList, newItems); | ||
4447 | 1662 | QFETCH(int, sortOrder); | ||
4448 | 1663 | QFETCH(QStringList, proxyItems); | ||
4449 | 1664 | |||
4450 | 1665 | QStandardItemModel model; | ||
4451 | 1666 | QSortFilterProxyModel proxy; | ||
4452 | 1667 | proxy.setDynamicSortFilter(true); | ||
4453 | 1668 | |||
4454 | 1669 | proxy.setSourceModel(&model); | ||
4455 | 1670 | model.insertColumns(0, 1); | ||
4456 | 1671 | model.insertRows(0, sourceItems.count()); | ||
4457 | 1672 | |||
4458 | 1673 | for (int i = 0; i < sourceItems.count(); ++i) { | ||
4459 | 1674 | QModelIndex index = model.index(i, 0, QModelIndex()); | ||
4460 | 1675 | model.setData(index, sourceItems.at(i), Qt::DisplayRole); | ||
4461 | 1676 | } | ||
4462 | 1677 | |||
4463 | 1678 | proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder)); | ||
4464 | 1679 | (void)proxy.rowCount(QModelIndex()); // force mapping | ||
4465 | 1680 | |||
4466 | 1681 | model.insertRows(start, newItems.size(), QModelIndex()); | ||
4467 | 1682 | |||
4468 | 1683 | QCOMPARE(proxy.rowCount(QModelIndex()), proxyItems.count()); | ||
4469 | 1684 | for (int i = 0; i < newItems.count(); ++i) { | ||
4470 | 1685 | QModelIndex index = model.index(start + i, 0, QModelIndex()); | ||
4471 | 1686 | model.setData(index, newItems.at(i), Qt::DisplayRole); | ||
4472 | 1687 | } | ||
4473 | 1688 | |||
4474 | 1689 | for (int i = 0; i < proxyItems.count(); ++i) { | ||
4475 | 1690 | QModelIndex index = proxy.index(i, 0, QModelIndex()); | ||
4476 | 1691 | QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), proxyItems.at(i)); | ||
4477 | 1692 | } | ||
4478 | 1693 | } | ||
4479 | 1694 | |||
4480 | 1695 | void tst_QSortFilterProxyModel::changeFilter_data() | ||
4481 | 1696 | { | ||
4482 | 1697 | QTest::addColumn<QStringList>("sourceItems"); | ||
4483 | 1698 | QTest::addColumn<int>("sortOrder"); | ||
4484 | 1699 | QTest::addColumn<QString>("initialFilter"); | ||
4485 | 1700 | QTest::addColumn<IntPairList>("initialRemoveIntervals"); | ||
4486 | 1701 | QTest::addColumn<QStringList>("initialProxyItems"); | ||
4487 | 1702 | QTest::addColumn<QString>("finalFilter"); | ||
4488 | 1703 | QTest::addColumn<IntPairList>("finalRemoveIntervals"); | ||
4489 | 1704 | QTest::addColumn<IntPairList>("insertIntervals"); | ||
4490 | 1705 | QTest::addColumn<QStringList>("finalProxyItems"); | ||
4491 | 1706 | |||
4492 | 1707 | QTest::newRow("filter (1)") | ||
4493 | 1708 | << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems | ||
4494 | 1709 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4495 | 1710 | << "a|b|c" // initialFilter | ||
4496 | 1711 | << (IntPairList() << IntPair(3, 5)) // initialRemoveIntervals | ||
4497 | 1712 | << (QStringList() << "a" << "b" << "c") // initialProxyItems | ||
4498 | 1713 | << "b|d|f" // finalFilter | ||
4499 | 1714 | << (IntPairList() << IntPair(2, 2) << IntPair(0, 0)) // finalRemoveIntervals | ||
4500 | 1715 | << (IntPairList() << IntPair(1, 2)) // insertIntervals | ||
4501 | 1716 | << (QStringList() << "b" << "d" << "f") // finalProxyItems | ||
4502 | 1717 | ; | ||
4503 | 1718 | |||
4504 | 1719 | QTest::newRow("filter (2)") | ||
4505 | 1720 | << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems | ||
4506 | 1721 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4507 | 1722 | << "a|c|e" // initialFilter | ||
4508 | 1723 | << (IntPairList() << IntPair(5, 5) << IntPair(3, 3) << IntPair(1, 1)) // initialRemoveIntervals | ||
4509 | 1724 | << (QStringList() << "a" << "c" << "e") // initialProxyItems | ||
4510 | 1725 | << "" // finalFilter | ||
4511 | 1726 | << IntPairList() // finalRemoveIntervals | ||
4512 | 1727 | << (IntPairList() << IntPair(3, 3) << IntPair(2, 2) << IntPair(1, 1)) // insertIntervals | ||
4513 | 1728 | << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // finalProxyItems | ||
4514 | 1729 | ; | ||
4515 | 1730 | |||
4516 | 1731 | QTest::newRow("filter (3)") | ||
4517 | 1732 | << (QStringList() << "a" << "b" << "c") // sourceItems | ||
4518 | 1733 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4519 | 1734 | << "a" // initialFilter | ||
4520 | 1735 | << (IntPairList() << IntPair(1, 2)) // initialRemoveIntervals | ||
4521 | 1736 | << (QStringList() << "a") // initialProxyItems | ||
4522 | 1737 | << "a" // finalFilter | ||
4523 | 1738 | << IntPairList() // finalRemoveIntervals | ||
4524 | 1739 | << IntPairList() // insertIntervals | ||
4525 | 1740 | << (QStringList() << "a") // finalProxyItems | ||
4526 | 1741 | ; | ||
4527 | 1742 | } | ||
4528 | 1743 | |||
4529 | 1744 | // Check that rows are added/removed when filter changes | ||
4530 | 1745 | void tst_QSortFilterProxyModel::changeFilter() | ||
4531 | 1746 | { | ||
4532 | 1747 | QFETCH(QStringList, sourceItems); | ||
4533 | 1748 | QFETCH(int, sortOrder); | ||
4534 | 1749 | QFETCH(QString, initialFilter); | ||
4535 | 1750 | QFETCH(IntPairList, initialRemoveIntervals); | ||
4536 | 1751 | QFETCH(QStringList, initialProxyItems); | ||
4537 | 1752 | QFETCH(QString, finalFilter); | ||
4538 | 1753 | QFETCH(IntPairList, finalRemoveIntervals); | ||
4539 | 1754 | QFETCH(IntPairList, insertIntervals); | ||
4540 | 1755 | QFETCH(QStringList, finalProxyItems); | ||
4541 | 1756 | |||
4542 | 1757 | QStandardItemModel model; | ||
4543 | 1758 | QSortFilterProxyModel proxy; | ||
4544 | 1759 | |||
4545 | 1760 | proxy.setSourceModel(&model); | ||
4546 | 1761 | model.insertColumns(0, 1); | ||
4547 | 1762 | model.insertRows(0, sourceItems.count()); | ||
4548 | 1763 | |||
4549 | 1764 | for (int i = 0; i < sourceItems.count(); ++i) { | ||
4550 | 1765 | QModelIndex index = model.index(i, 0, QModelIndex()); | ||
4551 | 1766 | model.setData(index, sourceItems.at(i), Qt::DisplayRole); | ||
4552 | 1767 | } | ||
4553 | 1768 | |||
4554 | 1769 | proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder)); | ||
4555 | 1770 | (void)proxy.rowCount(QModelIndex()); // force mapping | ||
4556 | 1771 | |||
4557 | 1772 | QSignalSpy initialRemoveSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex,int,int))); | ||
4558 | 1773 | QSignalSpy initialInsertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex,int,int))); | ||
4559 | 1774 | |||
4560 | 1775 | QVERIFY(initialRemoveSpy.isValid()); | ||
4561 | 1776 | QVERIFY(initialInsertSpy.isValid()); | ||
4562 | 1777 | |||
4563 | 1778 | proxy.setFilterRegExp(initialFilter); | ||
4564 | 1779 | |||
4565 | 1780 | QCOMPARE(initialRemoveSpy.count(), initialRemoveIntervals.count()); | ||
4566 | 1781 | QCOMPARE(initialInsertSpy.count(), 0); | ||
4567 | 1782 | for (int i = 0; i < initialRemoveSpy.count(); ++i) { | ||
4568 | 1783 | QList<QVariant> args = initialRemoveSpy.at(i); | ||
4569 | 1784 | QVERIFY(args.at(1).type() == QVariant::Int); | ||
4570 | 1785 | QVERIFY(args.at(2).type() == QVariant::Int); | ||
4571 | 1786 | QCOMPARE(args.at(1).toInt(), initialRemoveIntervals.at(i).first); | ||
4572 | 1787 | QCOMPARE(args.at(2).toInt(), initialRemoveIntervals.at(i).second); | ||
4573 | 1788 | } | ||
4574 | 1789 | |||
4575 | 1790 | QCOMPARE(proxy.rowCount(QModelIndex()), initialProxyItems.count()); | ||
4576 | 1791 | for (int i = 0; i < initialProxyItems.count(); ++i) { | ||
4577 | 1792 | QModelIndex index = proxy.index(i, 0, QModelIndex()); | ||
4578 | 1793 | QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), initialProxyItems.at(i)); | ||
4579 | 1794 | } | ||
4580 | 1795 | |||
4581 | 1796 | QSignalSpy finalRemoveSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex,int,int))); | ||
4582 | 1797 | QSignalSpy finalInsertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex,int,int))); | ||
4583 | 1798 | |||
4584 | 1799 | QVERIFY(finalRemoveSpy.isValid()); | ||
4585 | 1800 | QVERIFY(finalInsertSpy.isValid()); | ||
4586 | 1801 | |||
4587 | 1802 | proxy.setFilterRegExp(finalFilter); | ||
4588 | 1803 | |||
4589 | 1804 | QCOMPARE(finalRemoveSpy.count(), finalRemoveIntervals.count()); | ||
4590 | 1805 | for (int i = 0; i < finalRemoveSpy.count(); ++i) { | ||
4591 | 1806 | QList<QVariant> args = finalRemoveSpy.at(i); | ||
4592 | 1807 | QVERIFY(args.at(1).type() == QVariant::Int); | ||
4593 | 1808 | QVERIFY(args.at(2).type() == QVariant::Int); | ||
4594 | 1809 | QCOMPARE(args.at(1).toInt(), finalRemoveIntervals.at(i).first); | ||
4595 | 1810 | QCOMPARE(args.at(2).toInt(), finalRemoveIntervals.at(i).second); | ||
4596 | 1811 | } | ||
4597 | 1812 | |||
4598 | 1813 | #ifdef Q_OS_IRIX | ||
4599 | 1814 | QEXPECT_FAIL("filter (2)", "Not reliable on IRIX", Abort); | ||
4600 | 1815 | #endif | ||
4601 | 1816 | QCOMPARE(finalInsertSpy.count(), insertIntervals.count()); | ||
4602 | 1817 | for (int i = 0; i < finalInsertSpy.count(); ++i) { | ||
4603 | 1818 | QList<QVariant> args = finalInsertSpy.at(i); | ||
4604 | 1819 | QVERIFY(args.at(1).type() == QVariant::Int); | ||
4605 | 1820 | QVERIFY(args.at(2).type() == QVariant::Int); | ||
4606 | 1821 | QCOMPARE(args.at(1).toInt(), insertIntervals.at(i).first); | ||
4607 | 1822 | QCOMPARE(args.at(2).toInt(), insertIntervals.at(i).second); | ||
4608 | 1823 | } | ||
4609 | 1824 | |||
4610 | 1825 | QCOMPARE(proxy.rowCount(QModelIndex()), finalProxyItems.count()); | ||
4611 | 1826 | for (int i = 0; i < finalProxyItems.count(); ++i) { | ||
4612 | 1827 | QModelIndex index = proxy.index(i, 0, QModelIndex()); | ||
4613 | 1828 | QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), finalProxyItems.at(i)); | ||
4614 | 1829 | } | ||
4615 | 1830 | } | ||
4616 | 1831 | |||
4617 | 1832 | void tst_QSortFilterProxyModel::changeSourceData_data() | ||
4618 | 1833 | { | ||
4619 | 1834 | QTest::addColumn<QStringList>("sourceItems"); | ||
4620 | 1835 | QTest::addColumn<int>("sortOrder"); | ||
4621 | 1836 | QTest::addColumn<QString>("filter"); | ||
4622 | 1837 | QTest::addColumn<bool>("dynamic"); | ||
4623 | 1838 | QTest::addColumn<int>("row"); | ||
4624 | 1839 | QTest::addColumn<QString>("newValue"); | ||
4625 | 1840 | QTest::addColumn<IntPairList>("removeIntervals"); | ||
4626 | 1841 | QTest::addColumn<IntPairList>("insertIntervals"); | ||
4627 | 1842 | QTest::addColumn<QStringList>("proxyItems"); | ||
4628 | 1843 | |||
4629 | 1844 | QTest::newRow("changeSourceData (1)") | ||
4630 | 1845 | << (QStringList() << "c" << "b" << "a") // sourceItems | ||
4631 | 1846 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4632 | 1847 | << "" // filter | ||
4633 | 1848 | << true // dynamic | ||
4634 | 1849 | << 2 // row | ||
4635 | 1850 | << "z" // newValue | ||
4636 | 1851 | << IntPairList() // removeIntervals | ||
4637 | 1852 | << IntPairList() // insertIntervals | ||
4638 | 1853 | << (QStringList() << "b" << "c" << "z") // proxyItems | ||
4639 | 1854 | ; | ||
4640 | 1855 | |||
4641 | 1856 | QTest::newRow("changeSourceData (2)") | ||
4642 | 1857 | << (QStringList() << "b" << "c" << "z") // sourceItems | ||
4643 | 1858 | << static_cast<int>(Qt::DescendingOrder) // sortOrder | ||
4644 | 1859 | << "" // filter | ||
4645 | 1860 | << true // dynamic | ||
4646 | 1861 | << 1 // row | ||
4647 | 1862 | << "a" // newValue | ||
4648 | 1863 | << IntPairList() // removeIntervals | ||
4649 | 1864 | << IntPairList() // insertIntervals | ||
4650 | 1865 | << (QStringList() << "z" << "b" << "a") // proxyItems | ||
4651 | 1866 | ; | ||
4652 | 1867 | |||
4653 | 1868 | QTest::newRow("changeSourceData (3)") | ||
4654 | 1869 | << (QStringList() << "a" << "b") // sourceItems | ||
4655 | 1870 | << static_cast<int>(Qt::DescendingOrder) // sortOrder | ||
4656 | 1871 | << "" // filter | ||
4657 | 1872 | << true // dynamic | ||
4658 | 1873 | << 0 // row | ||
4659 | 1874 | << "a" // newValue | ||
4660 | 1875 | << IntPairList() // removeIntervals | ||
4661 | 1876 | << IntPairList() // insertIntervals | ||
4662 | 1877 | << (QStringList() << "b" << "a") // proxyItems | ||
4663 | 1878 | ; | ||
4664 | 1879 | |||
4665 | 1880 | QTest::newRow("changeSourceData (4)") | ||
4666 | 1881 | << (QStringList() << "a" << "b" << "c" << "d") // sourceItems | ||
4667 | 1882 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4668 | 1883 | << "a|c" // filter | ||
4669 | 1884 | << true // dynamic | ||
4670 | 1885 | << 1 // row | ||
4671 | 1886 | << "x" // newValue | ||
4672 | 1887 | << IntPairList() // removeIntervals | ||
4673 | 1888 | << IntPairList() // insertIntervals | ||
4674 | 1889 | << (QStringList() << "a" << "c") // proxyItems | ||
4675 | 1890 | ; | ||
4676 | 1891 | |||
4677 | 1892 | QTest::newRow("changeSourceData (5)") | ||
4678 | 1893 | << (QStringList() << "a" << "b" << "c" << "d") // sourceItems | ||
4679 | 1894 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4680 | 1895 | << "a|c|x" // filter | ||
4681 | 1896 | << true // dynamic | ||
4682 | 1897 | << 1 // row | ||
4683 | 1898 | << "x" // newValue | ||
4684 | 1899 | << IntPairList() // removeIntervals | ||
4685 | 1900 | << (IntPairList() << IntPair(2, 2)) // insertIntervals | ||
4686 | 1901 | << (QStringList() << "a" << "c" << "x") // proxyItems | ||
4687 | 1902 | ; | ||
4688 | 1903 | |||
4689 | 1904 | QTest::newRow("changeSourceData (6)") | ||
4690 | 1905 | << (QStringList() << "c" << "b" << "a") // sourceItems | ||
4691 | 1906 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4692 | 1907 | << "" // filter | ||
4693 | 1908 | << false // dynamic | ||
4694 | 1909 | << 2 // row | ||
4695 | 1910 | << "x" // newValue | ||
4696 | 1911 | << IntPairList() // removeIntervals | ||
4697 | 1912 | << IntPairList() // insertIntervals | ||
4698 | 1913 | << (QStringList() << "x" << "b" << "c") // proxyItems | ||
4699 | 1914 | ; | ||
4700 | 1915 | } | ||
4701 | 1916 | |||
4702 | 1917 | void tst_QSortFilterProxyModel::changeSourceData() | ||
4703 | 1918 | { | ||
4704 | 1919 | QFETCH(QStringList, sourceItems); | ||
4705 | 1920 | QFETCH(int, sortOrder); | ||
4706 | 1921 | QFETCH(QString, filter); | ||
4707 | 1922 | QFETCH(bool, dynamic); | ||
4708 | 1923 | QFETCH(int, row); | ||
4709 | 1924 | QFETCH(QString, newValue); | ||
4710 | 1925 | QFETCH(IntPairList, removeIntervals); | ||
4711 | 1926 | QFETCH(IntPairList, insertIntervals); | ||
4712 | 1927 | QFETCH(QStringList, proxyItems); | ||
4713 | 1928 | |||
4714 | 1929 | QStandardItemModel model; | ||
4715 | 1930 | QSortFilterProxyModel proxy; | ||
4716 | 1931 | |||
4717 | 1932 | proxy.setDynamicSortFilter(dynamic); | ||
4718 | 1933 | proxy.setSourceModel(&model); | ||
4719 | 1934 | model.insertColumns(0, 1); | ||
4720 | 1935 | model.insertRows(0, sourceItems.count()); | ||
4721 | 1936 | |||
4722 | 1937 | for (int i = 0; i < sourceItems.count(); ++i) { | ||
4723 | 1938 | QModelIndex index = model.index(i, 0, QModelIndex()); | ||
4724 | 1939 | model.setData(index, sourceItems.at(i), Qt::DisplayRole); | ||
4725 | 1940 | } | ||
4726 | 1941 | |||
4727 | 1942 | proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder)); | ||
4728 | 1943 | (void)proxy.rowCount(QModelIndex()); // force mapping | ||
4729 | 1944 | |||
4730 | 1945 | proxy.setFilterRegExp(filter); | ||
4731 | 1946 | |||
4732 | 1947 | QSignalSpy removeSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex,int,int))); | ||
4733 | 1948 | QSignalSpy insertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex,int,int))); | ||
4734 | 1949 | |||
4735 | 1950 | QVERIFY(removeSpy.isValid()); | ||
4736 | 1951 | QVERIFY(insertSpy.isValid()); | ||
4737 | 1952 | |||
4738 | 1953 | { | ||
4739 | 1954 | QModelIndex index = model.index(row, 0, QModelIndex()); | ||
4740 | 1955 | model.setData(index, newValue, Qt::DisplayRole); | ||
4741 | 1956 | } | ||
4742 | 1957 | |||
4743 | 1958 | QCOMPARE(removeSpy.count(), removeIntervals.count()); | ||
4744 | 1959 | for (int i = 0; i < removeSpy.count(); ++i) { | ||
4745 | 1960 | QList<QVariant> args = removeSpy.at(i); | ||
4746 | 1961 | QVERIFY(args.at(1).type() == QVariant::Int); | ||
4747 | 1962 | QVERIFY(args.at(2).type() == QVariant::Int); | ||
4748 | 1963 | QCOMPARE(args.at(1).toInt(), removeIntervals.at(i).first); | ||
4749 | 1964 | QCOMPARE(args.at(2).toInt(), removeIntervals.at(i).second); | ||
4750 | 1965 | } | ||
4751 | 1966 | |||
4752 | 1967 | QCOMPARE(insertSpy.count(), insertIntervals.count()); | ||
4753 | 1968 | for (int i = 0; i < insertSpy.count(); ++i) { | ||
4754 | 1969 | QList<QVariant> args = insertSpy.at(i); | ||
4755 | 1970 | QVERIFY(args.at(1).type() == QVariant::Int); | ||
4756 | 1971 | QVERIFY(args.at(2).type() == QVariant::Int); | ||
4757 | 1972 | QCOMPARE(args.at(1).toInt(), insertIntervals.at(i).first); | ||
4758 | 1973 | QCOMPARE(args.at(2).toInt(), insertIntervals.at(i).second); | ||
4759 | 1974 | } | ||
4760 | 1975 | |||
4761 | 1976 | QCOMPARE(proxy.rowCount(QModelIndex()), proxyItems.count()); | ||
4762 | 1977 | for (int i = 0; i < proxyItems.count(); ++i) { | ||
4763 | 1978 | QModelIndex index = proxy.index(i, 0, QModelIndex()); | ||
4764 | 1979 | QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), proxyItems.at(i)); | ||
4765 | 1980 | } | ||
4766 | 1981 | } | ||
4767 | 1982 | |||
4768 | 1983 | void tst_QSortFilterProxyModel::sortFilterRole() | ||
4769 | 1984 | { | ||
4770 | 1985 | QStandardItemModel model; | ||
4771 | 1986 | QSortFilterProxyModel proxy; | ||
4772 | 1987 | proxy.setSourceModel(&model); | ||
4773 | 1988 | model.insertColumns(0, 1); | ||
4774 | 1989 | |||
4775 | 1990 | QList<QPair<QVariant, QVariant> > sourceItems; | ||
4776 | 1991 | sourceItems = QList<QPair<QVariant, QVariant> >() | ||
4777 | 1992 | << QPair<QVariant, QVariant>("b", 3) | ||
4778 | 1993 | << QPair<QVariant, QVariant>("c", 2) | ||
4779 | 1994 | << QPair<QVariant, QVariant>("a", 1); | ||
4780 | 1995 | |||
4781 | 1996 | QList<int> orderedItems; | ||
4782 | 1997 | orderedItems = QList<int>() | ||
4783 | 1998 | << 2 << 1; | ||
4784 | 1999 | |||
4785 | 2000 | model.insertRows(0, sourceItems.count()); | ||
4786 | 2001 | for (int i = 0; i < sourceItems.count(); ++i) { | ||
4787 | 2002 | QModelIndex index = model.index(i, 0, QModelIndex()); | ||
4788 | 2003 | model.setData(index, sourceItems.at(i).first, Qt::DisplayRole); | ||
4789 | 2004 | model.setData(index, sourceItems.at(i).second, Qt::UserRole); | ||
4790 | 2005 | } | ||
4791 | 2006 | |||
4792 | 2007 | proxy.setFilterRegExp("2"); | ||
4793 | 2008 | QCOMPARE(proxy.rowCount(), 0); // Qt::DisplayRole is default role | ||
4794 | 2009 | |||
4795 | 2010 | proxy.setFilterRole(Qt::UserRole); | ||
4796 | 2011 | QCOMPARE(proxy.rowCount(), 1); | ||
4797 | 2012 | |||
4798 | 2013 | proxy.setFilterRole(Qt::DisplayRole); | ||
4799 | 2014 | QCOMPARE(proxy.rowCount(), 0); | ||
4800 | 2015 | |||
4801 | 2016 | proxy.setFilterRegExp("1|2|3"); | ||
4802 | 2017 | QCOMPARE(proxy.rowCount(), 0); | ||
4803 | 2018 | |||
4804 | 2019 | proxy.setFilterRole(Qt::UserRole); | ||
4805 | 2020 | QCOMPARE(proxy.rowCount(), 3); | ||
4806 | 2021 | |||
4807 | 2022 | proxy.sort(0, Qt::AscendingOrder); | ||
4808 | 2023 | QCOMPARE(proxy.rowCount(), 3); | ||
4809 | 2024 | |||
4810 | 2025 | proxy.setSortRole(Qt::UserRole); | ||
4811 | 2026 | proxy.setFilterRole(Qt::DisplayRole); | ||
4812 | 2027 | proxy.setFilterRegExp("a|c"); | ||
4813 | 2028 | QCOMPARE(proxy.rowCount(), orderedItems.count()); | ||
4814 | 2029 | for (int i = 0; i < proxy.rowCount(); ++i) { | ||
4815 | 2030 | QModelIndex index = proxy.index(i, 0, QModelIndex()); | ||
4816 | 2031 | QCOMPARE(proxy.data(index, Qt::DisplayRole), sourceItems.at(orderedItems.at(i)).first); | ||
4817 | 2032 | } | ||
4818 | 2033 | } | ||
4819 | 2034 | |||
4820 | 2035 | void tst_QSortFilterProxyModel::selectionFilteredOut() | ||
4821 | 2036 | { | ||
4822 | 2037 | QStandardItemModel model(2, 1); | ||
4823 | 2038 | model.setData(model.index(0, 0), QString("AAA")); | ||
4824 | 2039 | model.setData(model.index(1, 0), QString("BBB")); | ||
4825 | 2040 | QSortFilterProxyModel proxy; | ||
4826 | 2041 | proxy.setSourceModel(&model); | ||
4827 | 2042 | QTreeView view; | ||
4828 | 2043 | |||
4829 | 2044 | view.show(); | ||
4830 | 2045 | view.setModel(&proxy); | ||
4831 | 2046 | QSignalSpy spy(view.selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex))); | ||
4832 | 2047 | QVERIFY(spy.isValid()); | ||
4833 | 2048 | |||
4834 | 2049 | view.setCurrentIndex(proxy.index(0, 0)); | ||
4835 | 2050 | QCOMPARE(spy.count(), 1); | ||
4836 | 2051 | proxy.setFilterRegExp(QRegExp("^B")); | ||
4837 | 2052 | QCOMPARE(spy.count(), 2); | ||
4838 | 2053 | } | ||
4839 | 2054 | |||
4840 | 2055 | void tst_QSortFilterProxyModel::match_data() | ||
4841 | 2056 | { | ||
4842 | 2057 | QTest::addColumn<QStringList>("sourceItems"); | ||
4843 | 2058 | QTest::addColumn<int>("sortOrder"); | ||
4844 | 2059 | QTest::addColumn<QString>("filter"); | ||
4845 | 2060 | QTest::addColumn<int>("proxyStartRow"); | ||
4846 | 2061 | QTest::addColumn<QString>("what"); | ||
4847 | 2062 | QTest::addColumn<int>("matchFlags"); | ||
4848 | 2063 | QTest::addColumn<IntList>("expectedProxyItems"); | ||
4849 | 2064 | QTest::newRow("1") | ||
4850 | 2065 | << (QStringList() << "a") // sourceItems | ||
4851 | 2066 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4852 | 2067 | << "" // filter | ||
4853 | 2068 | << 0 // proxyStartRow | ||
4854 | 2069 | << "a" // what | ||
4855 | 2070 | << static_cast<int>(Qt::MatchExactly) // matchFlags | ||
4856 | 2071 | << (IntList() << 0); // expectedProxyItems | ||
4857 | 2072 | QTest::newRow("2") | ||
4858 | 2073 | << (QStringList() << "a" << "b") // sourceItems | ||
4859 | 2074 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4860 | 2075 | << "" // filter | ||
4861 | 2076 | << 0 // proxyStartRow | ||
4862 | 2077 | << "b" // what | ||
4863 | 2078 | << static_cast<int>(Qt::MatchExactly) // matchFlags | ||
4864 | 2079 | << (IntList() << 1); // expectedProxyItems | ||
4865 | 2080 | QTest::newRow("3") | ||
4866 | 2081 | << (QStringList() << "a" << "b") // sourceItems | ||
4867 | 2082 | << static_cast<int>(Qt::DescendingOrder) // sortOrder | ||
4868 | 2083 | << "" // filter | ||
4869 | 2084 | << 0 // proxyStartRow | ||
4870 | 2085 | << "a" // what | ||
4871 | 2086 | << static_cast<int>(Qt::MatchExactly) // matchFlags | ||
4872 | 2087 | << (IntList() << 1); // expectedProxyItems | ||
4873 | 2088 | QTest::newRow("4") | ||
4874 | 2089 | << (QStringList() << "b" << "d" << "a" << "c") // sourceItems | ||
4875 | 2090 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4876 | 2091 | << "" // filter | ||
4877 | 2092 | << 1 // proxyStartRow | ||
4878 | 2093 | << "a" // what | ||
4879 | 2094 | << static_cast<int>(Qt::MatchExactly) // matchFlags | ||
4880 | 2095 | << IntList(); // expectedProxyItems | ||
4881 | 2096 | QTest::newRow("5") | ||
4882 | 2097 | << (QStringList() << "b" << "d" << "a" << "c") // sourceItems | ||
4883 | 2098 | << static_cast<int>(Qt::AscendingOrder) // sortOrder | ||
4884 | 2099 | << "a|b" // filter | ||
4885 | 2100 | << 0 // proxyStartRow | ||
4886 | 2101 | << "c" // what | ||
4887 | 2102 | << static_cast<int>(Qt::MatchExactly) // matchFlags | ||
4888 | 2103 | << IntList(); // expectedProxyItems | ||
4889 | 2104 | QTest::newRow("6") | ||
4890 | 2105 | << (QStringList() << "b" << "d" << "a" << "c") // sourceItems | ||
4891 | 2106 | << static_cast<int>(Qt::DescendingOrder) // sortOrder | ||
4892 | 2107 | << "a|b" // filter | ||
4893 | 2108 | << 0 // proxyStartRow | ||
4894 | 2109 | << "b" // what | ||
4895 | 2110 | << static_cast<int>(Qt::MatchExactly) // matchFlags | ||
4896 | 2111 | << (IntList() << 0); // expectedProxyItems | ||
4897 | 2112 | } | ||
4898 | 2113 | |||
4899 | 2114 | void tst_QSortFilterProxyModel::match() | ||
4900 | 2115 | { | ||
4901 | 2116 | QFETCH(QStringList, sourceItems); | ||
4902 | 2117 | QFETCH(int, sortOrder); | ||
4903 | 2118 | QFETCH(QString, filter); | ||
4904 | 2119 | QFETCH(int, proxyStartRow); | ||
4905 | 2120 | QFETCH(QString, what); | ||
4906 | 2121 | QFETCH(int, matchFlags); | ||
4907 | 2122 | QFETCH(IntList, expectedProxyItems); | ||
4908 | 2123 | |||
4909 | 2124 | QStandardItemModel model; | ||
4910 | 2125 | QSortFilterProxyModel proxy; | ||
4911 | 2126 | |||
4912 | 2127 | proxy.setSourceModel(&model); | ||
4913 | 2128 | model.insertColumns(0, 1); | ||
4914 | 2129 | model.insertRows(0, sourceItems.count()); | ||
4915 | 2130 | |||
4916 | 2131 | for (int i = 0; i < sourceItems.count(); ++i) { | ||
4917 | 2132 | QModelIndex index = model.index(i, 0, QModelIndex()); | ||
4918 | 2133 | model.setData(index, sourceItems.at(i), Qt::DisplayRole); | ||
4919 | 2134 | } | ||
4920 | 2135 | |||
4921 | 2136 | proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder)); | ||
4922 | 2137 | proxy.setFilterRegExp(filter); | ||
4923 | 2138 | |||
4924 | 2139 | QModelIndex startIndex = proxy.index(proxyStartRow, 0); | ||
4925 | 2140 | QModelIndexList indexes = proxy.match(startIndex, Qt::DisplayRole, what, | ||
4926 | 2141 | expectedProxyItems.count(), | ||
4927 | 2142 | Qt::MatchFlags(matchFlags)); | ||
4928 | 2143 | QCOMPARE(indexes.count(), expectedProxyItems.count()); | ||
4929 | 2144 | for (int i = 0; i < indexes.count(); ++i) | ||
4930 | 2145 | QCOMPARE(indexes.at(i).row(), expectedProxyItems.at(i)); | ||
4931 | 2146 | } | ||
4932 | 2147 | |||
4933 | 2148 | void tst_QSortFilterProxyModel::insertIntoChildrenlessItem() | ||
4934 | 2149 | { | ||
4935 | 2150 | QStandardItemModel model; | ||
4936 | 2151 | QStandardItem *itemA = new QStandardItem("a"); | ||
4937 | 2152 | model.appendRow(itemA); | ||
4938 | 2153 | QStandardItem *itemB = new QStandardItem("b"); | ||
4939 | 2154 | model.appendRow(itemB); | ||
4940 | 2155 | QStandardItem *itemC = new QStandardItem("c"); | ||
4941 | 2156 | model.appendRow(itemC); | ||
4942 | 2157 | |||
4943 | 2158 | QSortFilterProxyModel proxy; | ||
4944 | 2159 | proxy.setSourceModel(&model); | ||
4945 | 2160 | |||
4946 | 2161 | QSignalSpy colsInsertedSpy(&proxy, SIGNAL(columnsInserted(QModelIndex,int,int))); | ||
4947 | 2162 | QSignalSpy rowsInsertedSpy(&proxy, SIGNAL(rowsInserted(QModelIndex,int,int))); | ||
4948 | 2163 | |||
4949 | 2164 | QVERIFY(colsInsertedSpy.isValid()); | ||
4950 | 2165 | QVERIFY(rowsInsertedSpy.isValid()); | ||
4951 | 2166 | |||
4952 | 2167 | (void)proxy.rowCount(QModelIndex()); // force mapping of "a", "b", "c" | ||
4953 | 2168 | QCOMPARE(colsInsertedSpy.count(), 0); | ||
4954 | 2169 | QCOMPARE(rowsInsertedSpy.count(), 0); | ||
4955 | 2170 | |||
4956 | 2171 | // now add a child to itemB ==> should get insert notification from the proxy | ||
4957 | 2172 | itemB->appendRow(new QStandardItem("a.0")); | ||
4958 | 2173 | QCOMPARE(colsInsertedSpy.count(), 1); | ||
4959 | 2174 | QCOMPARE(rowsInsertedSpy.count(), 1); | ||
4960 | 2175 | |||
4961 | 2176 | QVariantList args = colsInsertedSpy.takeFirst(); | ||
4962 | 2177 | QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), proxy.mapFromSource(itemB->index())); | ||
4963 | 2178 | QCOMPARE(qvariant_cast<int>(args.at(1)), 0); | ||
4964 | 2179 | QCOMPARE(qvariant_cast<int>(args.at(2)), 0); | ||
4965 | 2180 | |||
4966 | 2181 | args = rowsInsertedSpy.takeFirst(); | ||
4967 | 2182 | QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), proxy.mapFromSource(itemB->index())); | ||
4968 | 2183 | QCOMPARE(qvariant_cast<int>(args.at(1)), 0); | ||
4969 | 2184 | QCOMPARE(qvariant_cast<int>(args.at(2)), 0); | ||
4970 | 2185 | } | ||
4971 | 2186 | |||
4972 | 2187 | void tst_QSortFilterProxyModel::invalidateMappedChildren() | ||
4973 | 2188 | { | ||
4974 | 2189 | QStandardItemModel model; | ||
4975 | 2190 | |||
4976 | 2191 | QSortFilterProxyModel proxy; | ||
4977 | 2192 | proxy.setSourceModel(&model); | ||
4978 | 2193 | |||
4979 | 2194 | QStandardItem *itemA = new QStandardItem("a"); | ||
4980 | 2195 | model.appendRow(itemA); | ||
4981 | 2196 | QStandardItem *itemB = new QStandardItem("b"); | ||
4982 | 2197 | itemA->appendRow(itemB); | ||
4983 | 2198 | |||
4984 | 2199 | QStandardItem *itemC = new QStandardItem("c"); | ||
4985 | 2200 | itemB->appendRow(itemC); | ||
4986 | 2201 | itemC->appendRow(new QStandardItem("d")); | ||
4987 | 2202 | |||
4988 | 2203 | // force mappings | ||
4989 | 2204 | (void)proxy.hasChildren(QModelIndex()); | ||
4990 | 2205 | (void)proxy.hasChildren(proxy.mapFromSource(itemA->index())); | ||
4991 | 2206 | (void)proxy.hasChildren(proxy.mapFromSource(itemB->index())); | ||
4992 | 2207 | (void)proxy.hasChildren(proxy.mapFromSource(itemC->index())); | ||
4993 | 2208 | |||
4994 | 2209 | itemB->removeRow(0); // should invalidate mapping of itemC | ||
4995 | 2210 | itemC = new QStandardItem("c"); | ||
4996 | 2211 | itemA->appendRow(itemC); | ||
4997 | 2212 | itemC->appendRow(new QStandardItem("d")); | ||
4998 | 2213 | |||
4999 | 2214 | itemA->removeRow(1); // should invalidate mapping of itemC | ||
5000 | 2215 | itemC = new QStandardItem("c"); |
The diff has been truncated for viewing.
the update with the patch has been uploaded