Qt 4.8
qsortfilterproxymodel.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qsortfilterproxymodel.h"
43 
44 #ifndef QT_NO_SORTFILTERPROXYMODEL
45 
46 #include "qitemselectionmodel.h"
47 #include <qsize.h>
48 #include <qdebug.h>
49 #include <qdatetime.h>
50 #include <qpair.h>
51 #include <qstringlist.h>
52 #include <private/qabstractitemmodel_p.h>
53 #include <private/qabstractproxymodel_p.h>
54 
56 
58 
59 static inline QSet<int> qVectorToSet(const QVector<int> &vector)
60 {
61  QSet<int> set;
62  set.reserve(vector.size());
63  for(int i=0; i < vector.size(); ++i)
64  set << vector.at(i);
65  return set;
66 }
67 
69 {
70 public:
71  inline QSortFilterProxyModelLessThan(int column, const QModelIndex &parent,
72  const QAbstractItemModel *source,
73  const QSortFilterProxyModel *proxy)
74  : sort_column(column), source_parent(parent), source_model(source), proxy_model(proxy) {}
75 
76  inline bool operator()(int r1, int r2) const
77  {
80  return proxy_model->lessThan(i1, i2);
81  }
82 
83 private:
88 };
89 
91 {
92 public:
93  inline QSortFilterProxyModelGreaterThan(int column, const QModelIndex &parent,
94  const QAbstractItemModel *source,
95  const QSortFilterProxyModel *proxy)
96  : sort_column(column), source_parent(parent),
97  source_model(source), proxy_model(proxy) {}
98 
99  inline bool operator()(int r1, int r2) const
100  {
103  return proxy_model->lessThan(i2, i1);
104  }
105 
106 private:
111 };
112 
113 
114 //this struct is used to store what are the rows that are removed
115 //between a call to rowsAboutToBeRemoved and rowsRemoved
116 //it avoids readding rows to the mapping that are currently being removed
118 {
119  QRowsRemoval(const QModelIndex &parent_source, int start, int end) : parent_source(parent_source), start(start), end(end)
120  {
121  }
122 
123  QRowsRemoval() : start(-1), end(-1)
124  {
125  }
126 
127  bool contains(QModelIndex parent, int row)
128  {
129  do {
130  if (parent == parent_source)
131  return row >= start && row <= end;
132  row = parent.row();
133  parent = parent.parent();
134  } while (row >= 0);
135  return false;
136  }
137 private:
139  int start;
140  int end;
141 };
142 
144 {
146 
147 public:
148  struct Mapping {
155  };
156 
158 
165 
169 
172 
174 
176  const QModelIndex &source_parent) const;
177  QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const;
178  QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const;
179  bool can_create_mapping(const QModelIndex &source_parent) const;
180 
181  void remove_from_mapping(const QModelIndex &source_parent);
182 
184  const QModelIndex &proxy_index) const
185  {
186  Q_ASSERT(proxy_index.isValid());
187  Q_ASSERT(proxy_index.model() == q_func());
188  const void *p = proxy_index.internalPointer();
189  Q_ASSERT(p);
191  static_cast<const Mapping*>(p)->map_iter;
192  Q_ASSERT(it != source_index_mapping.constEnd());
193  Q_ASSERT(it.value());
194  return it;
195  }
196 
197  inline QModelIndex create_index(int row, int column,
199  {
200  return q_func()->createIndex(row, column, *it);
201  }
202 
203  void _q_sourceDataChanged(const QModelIndex &source_top_left,
204  const QModelIndex &source_bottom_right);
205  void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end);
206 
207  void _q_sourceAboutToBeReset();
208  void _q_sourceReset();
209 
210  void _q_sourceLayoutAboutToBeChanged();
211  void _q_sourceLayoutChanged();
212 
213  void _q_sourceRowsAboutToBeInserted(const QModelIndex &source_parent,
214  int start, int end);
215  void _q_sourceRowsInserted(const QModelIndex &source_parent,
216  int start, int end);
217  void _q_sourceRowsAboutToBeRemoved(const QModelIndex &source_parent,
218  int start, int end);
219  void _q_sourceRowsRemoved(const QModelIndex &source_parent,
220  int start, int end);
221  void _q_sourceColumnsAboutToBeInserted(const QModelIndex &source_parent,
222  int start, int end);
223  void _q_sourceColumnsInserted(const QModelIndex &source_parent,
224  int start, int end);
225  void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &source_parent,
226  int start, int end);
227  void _q_sourceColumnsRemoved(const QModelIndex &source_parent,
228  int start, int end);
229 
230  void _q_clearMapping();
231 
232  void sort();
233  bool update_source_sort_column();
234  void sort_source_rows(QVector<int> &source_rows,
235  const QModelIndex &source_parent) const;
236  QVector<QPair<int, QVector<int > > > proxy_intervals_for_source_items_to_add(
237  const QVector<int> &proxy_to_source, const QVector<int> &source_items,
238  const QModelIndex &source_parent, Qt::Orientation orient) const;
239  QVector<QPair<int, int > > proxy_intervals_for_source_items(
240  const QVector<int> &source_to_proxy, const QVector<int> &source_items) const;
241  void insert_source_items(
242  QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
243  const QVector<int> &source_items, const QModelIndex &source_parent,
244  Qt::Orientation orient, bool emit_signal = true);
245  void remove_source_items(
246  QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
247  const QVector<int> &source_items, const QModelIndex &source_parent,
248  Qt::Orientation orient, bool emit_signal = true);
249  void remove_proxy_interval(
250  QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
251  int proxy_start, int proxy_end, const QModelIndex &proxy_parent,
252  Qt::Orientation orient, bool emit_signal = true);
253  void build_source_to_proxy_mapping(
254  const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const;
255  void source_items_inserted(const QModelIndex &source_parent,
256  int start, int end, Qt::Orientation orient);
257  void source_items_about_to_be_removed(const QModelIndex &source_parent,
258  int start, int end, Qt::Orientation orient);
259  void source_items_removed(const QModelIndex &source_parent,
260  int start, int end, Qt::Orientation orient);
261  void proxy_item_range(
262  const QVector<int> &source_to_proxy, const QVector<int> &source_items,
263  int &proxy_low, int &proxy_high) const;
264 
265  QModelIndexPairList store_persistent_indexes();
266  void update_persistent_indexes(const QModelIndexPairList &source_indexes);
267 
268  void filter_changed(const QModelIndex &source_parent = QModelIndex());
269  QSet<int> handle_filter_changed(
270  QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
271  const QModelIndex &source_parent, Qt::Orientation orient);
272 
273  void updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
274  Qt::Orientation orient, int start, int end, int delta_item_count, bool remove);
275 
276  virtual void _q_sourceModelDestroyed();
277 };
278 
280 
282 {
284  _q_clearMapping();
285 }
286 
288 {
289  if (Mapping *m = source_index_mapping.take(source_parent)) {
290  for (int i = 0; i < m->mapped_children.size(); ++i)
291  remove_from_mapping(m->mapped_children.at(i));
292  delete m;
293  }
294 }
295 
297 {
298  // store the persistent indexes
299  QModelIndexPairList source_indexes = store_persistent_indexes();
300 
301  qDeleteAll(source_index_mapping);
302  source_index_mapping.clear();
303  if (dynamic_sortfilter && update_source_sort_column()) {
304  //update_source_sort_column might have created wrong mapping so we have to clear it again
305  qDeleteAll(source_index_mapping);
306  source_index_mapping.clear();
307  }
308 
309  // update the persistent indexes
310  update_persistent_indexes(source_indexes);
311 }
312 
314  const QModelIndex &source_parent) const
315 {
316  Q_Q(const QSortFilterProxyModel);
317 
318  IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
319  if (it != source_index_mapping.constEnd()) // was mapped already
320  return it;
321 
322  Mapping *m = new Mapping;
323 
324  int source_rows = model->rowCount(source_parent);
325  m->source_rows.reserve(source_rows);
326  for (int i = 0; i < source_rows; ++i) {
327  if (q->filterAcceptsRow(i, source_parent))
328  m->source_rows.append(i);
329  }
330  int source_cols = model->columnCount(source_parent);
331  m->source_columns.reserve(source_cols);
332  for (int i = 0; i < source_cols; ++i) {
333  if (q->filterAcceptsColumn(i, source_parent))
334  m->source_columns.append(i);
335  }
336 
337  sort_source_rows(m->source_rows, source_parent);
338  m->proxy_rows.resize(source_rows);
339  build_source_to_proxy_mapping(m->source_rows, m->proxy_rows);
340  m->proxy_columns.resize(source_cols);
341  build_source_to_proxy_mapping(m->source_columns, m->proxy_columns);
342 
343  it = IndexMap::const_iterator(source_index_mapping.insert(source_parent, m));
344  m->map_iter = it;
345 
346  if (source_parent.isValid()) {
347  QModelIndex source_grand_parent = source_parent.parent();
348  IndexMap::const_iterator it2 = create_mapping(source_grand_parent);
349  Q_ASSERT(it2 != source_index_mapping.constEnd());
350  it2.value()->mapped_children.append(source_parent);
351  }
352 
353  Q_ASSERT(it != source_index_mapping.constEnd());
354  Q_ASSERT(it.value());
355 
356  return it;
357 }
358 
360 {
361  if (!proxy_index.isValid())
362  return QModelIndex(); // for now; we may want to be able to set a root index later
363  if (proxy_index.model() != q_func()) {
364  qWarning() << "QSortFilterProxyModel: index from wrong model passed to mapToSource";
365  Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapToSource");
366  return QModelIndex();
367  }
368  IndexMap::const_iterator it = index_to_iterator(proxy_index);
369  Mapping *m = it.value();
370  if ((proxy_index.row() >= m->source_rows.size()) || (proxy_index.column() >= m->source_columns.size()))
371  return QModelIndex();
372  int source_row = m->source_rows.at(proxy_index.row());
373  int source_col = m->source_columns.at(proxy_index.column());
374  return model->index(source_row, source_col, it.key());
375 }
376 
378 {
379  if (!source_index.isValid())
380  return QModelIndex(); // for now; we may want to be able to set a root index later
381  if (source_index.model() != model) {
382  qWarning() << "QSortFilterProxyModel: index from wrong model passed to mapFromSource";
383  Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapFromSource");
384  return QModelIndex();
385  }
386  QModelIndex source_parent = source_index.parent();
387  IndexMap::const_iterator it = create_mapping(source_parent);
388  Mapping *m = it.value();
389  if ((source_index.row() >= m->proxy_rows.size()) || (source_index.column() >= m->proxy_columns.size()))
390  return QModelIndex();
391  int proxy_row = m->proxy_rows.at(source_index.row());
392  int proxy_column = m->proxy_columns.at(source_index.column());
393  if (proxy_row == -1 || proxy_column == -1)
394  return QModelIndex();
395  return create_index(proxy_row, proxy_column, it);
396 }
397 
399 {
400  if (source_parent.isValid()) {
401  QModelIndex source_grand_parent = source_parent.parent();
402  IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent);
403  if (it == source_index_mapping.constEnd()) {
404  // Don't care, since we don't have mapping for the grand parent
405  return false;
406  }
407  Mapping *gm = it.value();
408  if (gm->proxy_rows.at(source_parent.row()) == -1 ||
409  gm->proxy_columns.at(source_parent.column()) == -1) {
410  // Don't care, since parent is filtered
411  return false;
412  }
413  }
414  return true;
415 }
416 
426 {
428  emit q->layoutAboutToBeChanged();
429  QModelIndexPairList source_indexes = store_persistent_indexes();
430  IndexMap::const_iterator it = source_index_mapping.constBegin();
431  for (; it != source_index_mapping.constEnd(); ++it) {
432  QModelIndex source_parent = it.key();
433  Mapping *m = it.value();
434  sort_source_rows(m->source_rows, source_parent);
435  build_source_to_proxy_mapping(m->source_rows, m->proxy_rows);
436  }
437  update_persistent_indexes(source_indexes);
438  emit q->layoutChanged();
439 }
440 
448 {
450  QModelIndex proxy_index = q->index(0, proxy_sort_column, QModelIndex());
451  int old_source_sort_colum = source_sort_column;
452  source_sort_column = q->mapToSource(proxy_index).column();
453  return old_source_sort_colum != source_sort_column;
454 }
455 
456 
466  QVector<int> &source_rows, const QModelIndex &source_parent) const
467 {
468  Q_Q(const QSortFilterProxyModel);
469  if (source_sort_column >= 0) {
470  if (sort_order == Qt::AscendingOrder) {
471  QSortFilterProxyModelLessThan lt(source_sort_column, source_parent, model, q);
472  qStableSort(source_rows.begin(), source_rows.end(), lt);
473  } else {
474  QSortFilterProxyModelGreaterThan gt(source_sort_column, source_parent, model, q);
475  qStableSort(source_rows.begin(), source_rows.end(), gt);
476  }
477  } else { // restore the source model order
478  qStableSort(source_rows.begin(), source_rows.end());
479  }
480 }
481 
497  const QVector<int> &source_to_proxy, const QVector<int> &source_items) const
498 {
499  QVector<QPair<int, int> > proxy_intervals;
500  if (source_items.isEmpty())
501  return proxy_intervals;
502 
503  int source_items_index = 0;
504  while (source_items_index < source_items.size()) {
505  int first_proxy_item = source_to_proxy.at(source_items.at(source_items_index));
506  Q_ASSERT(first_proxy_item != -1);
507  int last_proxy_item = first_proxy_item;
508  ++source_items_index;
509  // Find end of interval
510  while ((source_items_index < source_items.size())
511  && (source_to_proxy.at(source_items.at(source_items_index)) == last_proxy_item + 1)) {
512  ++last_proxy_item;
513  ++source_items_index;
514  }
515  // Add interval to result
516  proxy_intervals.append(QPair<int, int>(first_proxy_item, last_proxy_item));
517  }
518  qStableSort(proxy_intervals.begin(), proxy_intervals.end());
519  return proxy_intervals;
520 }
521 
534  QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
535  const QVector<int> &source_items, const QModelIndex &source_parent,
536  Qt::Orientation orient, bool emit_signal)
537 {
539  QModelIndex proxy_parent = q->mapFromSource(source_parent);
540  if (!proxy_parent.isValid() && source_parent.isValid())
541  return; // nothing to do (already removed)
542 
543  QVector<QPair<int, int> > proxy_intervals;
544  proxy_intervals = proxy_intervals_for_source_items(source_to_proxy, source_items);
545 
546  for (int i = proxy_intervals.size()-1; i >= 0; --i) {
547  QPair<int, int> interval = proxy_intervals.at(i);
548  int proxy_start = interval.first;
549  int proxy_end = interval.second;
550  remove_proxy_interval(source_to_proxy, proxy_to_source, proxy_start, proxy_end,
551  proxy_parent, orient, emit_signal);
552  }
553 }
554 
566  QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, int proxy_start, int proxy_end,
567  const QModelIndex &proxy_parent, Qt::Orientation orient, bool emit_signal)
568 {
570  if (emit_signal) {
571  if (orient == Qt::Vertical)
572  q->beginRemoveRows(proxy_parent, proxy_start, proxy_end);
573  else
574  q->beginRemoveColumns(proxy_parent, proxy_start, proxy_end);
575  }
576 
577  // Remove items from proxy-to-source mapping
578  proxy_to_source.remove(proxy_start, proxy_end - proxy_start + 1);
579 
580  build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
581 
582  if (emit_signal) {
583  if (orient == Qt::Vertical)
584  q->endRemoveRows();
585  else
586  q->endRemoveColumns();
587  }
588 }
589 
606  const QVector<int> &proxy_to_source, const QVector<int> &source_items,
607  const QModelIndex &source_parent, Qt::Orientation orient) const
608 {
609  Q_Q(const QSortFilterProxyModel);
610  QVector<QPair<int, QVector<int> > > proxy_intervals;
611  if (source_items.isEmpty())
612  return proxy_intervals;
613 
614  int proxy_low = 0;
615  int proxy_item = 0;
616  int source_items_index = 0;
617  QVector<int> source_items_in_interval;
618  bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter);
619  while (source_items_index < source_items.size()) {
620  source_items_in_interval.clear();
621  int first_new_source_item = source_items.at(source_items_index);
622  source_items_in_interval.append(first_new_source_item);
623  ++source_items_index;
624 
625  // Find proxy item at which insertion should be started
626  int proxy_high = proxy_to_source.size() - 1;
627  QModelIndex i1 = compare ? model->index(first_new_source_item, source_sort_column, source_parent) : QModelIndex();
628  while (proxy_low <= proxy_high) {
629  proxy_item = (proxy_low + proxy_high) / 2;
630  if (compare) {
631  QModelIndex i2 = model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent);
632  if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1))
633  proxy_high = proxy_item - 1;
634  else
635  proxy_low = proxy_item + 1;
636  } else {
637  if (first_new_source_item < proxy_to_source.at(proxy_item))
638  proxy_high = proxy_item - 1;
639  else
640  proxy_low = proxy_item + 1;
641  }
642  }
643  proxy_item = proxy_low;
644 
645  // Find the sequence of new source items that should be inserted here
646  if (proxy_item >= proxy_to_source.size()) {
647  for ( ; source_items_index < source_items.size(); ++source_items_index)
648  source_items_in_interval.append(source_items.at(source_items_index));
649  } else {
650  i1 = compare ? model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent) : QModelIndex();
651  for ( ; source_items_index < source_items.size(); ++source_items_index) {
652  int new_source_item = source_items.at(source_items_index);
653  if (compare) {
654  QModelIndex i2 = model->index(new_source_item, source_sort_column, source_parent);
655  if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1))
656  break;
657  } else {
658  if (proxy_to_source.at(proxy_item) < new_source_item)
659  break;
660  }
661  source_items_in_interval.append(new_source_item);
662  }
663  }
664 
665  // Add interval to result
666  proxy_intervals.append(QPair<int, QVector<int> >(proxy_item, source_items_in_interval));
667  }
668  return proxy_intervals;
669 }
670 
683  QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
684  const QVector<int> &source_items, const QModelIndex &source_parent,
685  Qt::Orientation orient, bool emit_signal)
686 {
688  QModelIndex proxy_parent = q->mapFromSource(source_parent);
689  if (!proxy_parent.isValid() && source_parent.isValid())
690  return; // nothing to do (source_parent is not mapped)
691 
692  QVector<QPair<int, QVector<int> > > proxy_intervals;
693  proxy_intervals = proxy_intervals_for_source_items_to_add(
694  proxy_to_source, source_items, source_parent, orient);
695 
696  for (int i = proxy_intervals.size()-1; i >= 0; --i) {
697  QPair<int, QVector<int> > interval = proxy_intervals.at(i);
698  int proxy_start = interval.first;
699  QVector<int> source_items = interval.second;
700  int proxy_end = proxy_start + source_items.size() - 1;
701 
702  if (emit_signal) {
703  if (orient == Qt::Vertical)
704  q->beginInsertRows(proxy_parent, proxy_start, proxy_end);
705  else
706  q->beginInsertColumns(proxy_parent, proxy_start, proxy_end);
707  }
708 
709  for (int i = 0; i < source_items.size(); ++i)
710  proxy_to_source.insert(proxy_start + i, source_items.at(i));
711 
712  build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
713 
714  if (emit_signal) {
715  if (orient == Qt::Vertical)
716  q->endInsertRows();
717  else
718  q->endInsertColumns();
719  }
720  }
721 }
722 
739  const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
740 {
742  if ((start < 0) || (end < 0))
743  return;
744  IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
745  if (it == source_index_mapping.constEnd()) {
746  if (!can_create_mapping(source_parent))
747  return;
748  it = create_mapping(source_parent);
749  Mapping *m = it.value();
750  QModelIndex proxy_parent = q->mapFromSource(source_parent);
751  if (m->source_rows.count() > 0) {
752  q->beginInsertRows(proxy_parent, 0, m->source_rows.count() - 1);
753  q->endInsertRows();
754  }
755  if (m->source_columns.count() > 0) {
756  q->beginInsertColumns(proxy_parent, 0, m->source_columns.count() - 1);
757  q->endInsertColumns();
758  }
759  return;
760  }
761 
762  Mapping *m = it.value();
763  QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
764  QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
765 
766  int delta_item_count = end - start + 1;
767  int old_item_count = source_to_proxy.size();
768 
769  updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, false);
770 
771  // Expand source-to-proxy mapping to account for new items
772  if (start < 0 || start > source_to_proxy.size()) {
773  qWarning("QSortFilterProxyModel: invalid inserted rows reported by source model");
774  remove_from_mapping(source_parent);
775  return;
776  }
777  source_to_proxy.insert(start, delta_item_count, -1);
778 
779  if (start < old_item_count) {
780  // Adjust existing "stale" indexes in proxy-to-source mapping
781  int proxy_count = proxy_to_source.size();
782  for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
783  int source_item = proxy_to_source.at(proxy_item);
784  if (source_item >= start)
785  proxy_to_source.replace(proxy_item, source_item + delta_item_count);
786  }
787  build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
788  }
789 
790  // Figure out which items to add to mapping based on filter
791  QVector<int> source_items;
792  for (int i = start; i <= end; ++i) {
793  if ((orient == Qt::Vertical)
794  ? q->filterAcceptsRow(i, source_parent)
795  : q->filterAcceptsColumn(i, source_parent)) {
796  source_items.append(i);
797  }
798  }
799 
800  if (model->rowCount(source_parent) == delta_item_count) {
801  // Items were inserted where there were none before.
802  // If it was new rows make sure to create mappings for columns so that a
803  // valid mapping can be retrieved later and vice-versa.
804 
805  QVector<int> &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns;
806  QVector<int> &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns;
807 
808  if (orthogonal_source_to_proxy.isEmpty()) {
809  const int ortho_end = (orient == Qt::Horizontal) ? model->rowCount(source_parent) : model->columnCount(source_parent);
810 
811  orthogonal_source_to_proxy.resize(ortho_end);
812 
813  for (int ortho_item = 0; ortho_item < ortho_end; ++ortho_item) {
814  if ((orient == Qt::Horizontal) ? q->filterAcceptsRow(ortho_item, source_parent)
815  : q->filterAcceptsColumn(ortho_item, source_parent)) {
816  orthogonal_proxy_to_source.append(ortho_item);
817  }
818  }
819  if (orient == Qt::Horizontal) {
820  // We're reacting to columnsInserted, but we've just inserted new rows. Sort them.
821  sort_source_rows(orthogonal_proxy_to_source, source_parent);
822  }
823  build_source_to_proxy_mapping(orthogonal_proxy_to_source, orthogonal_source_to_proxy);
824  }
825  }
826 
827  // Sort and insert the items
828  if (orient == Qt::Vertical) // Only sort rows
829  sort_source_rows(source_items, source_parent);
830  insert_source_items(source_to_proxy, proxy_to_source, source_items, source_parent, orient);
831 }
832 
843  const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
844 {
845  if ((start < 0) || (end < 0))
846  return;
847  IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
848  if (it == source_index_mapping.constEnd()) {
849  // Don't care, since we don't have mapping for this index
850  return;
851  }
852 
853  Mapping *m = it.value();
854  QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
855  QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
856 
857  // figure out which items to remove
858  QVector<int> source_items_to_remove;
859  int proxy_count = proxy_to_source.size();
860  for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
861  int source_item = proxy_to_source.at(proxy_item);
862  if ((source_item >= start) && (source_item <= end))
863  source_items_to_remove.append(source_item);
864  }
865 
866  remove_source_items(source_to_proxy, proxy_to_source, source_items_to_remove,
867  source_parent, orient);
868 }
869 
879  const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
880 {
881  if ((start < 0) || (end < 0))
882  return;
883  IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
884  if (it == source_index_mapping.constEnd()) {
885  // Don't care, since we don't have mapping for this index
886  return;
887  }
888 
889  Mapping *m = it.value();
890  QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
891  QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
892 
893  if (end >= source_to_proxy.size())
894  end = source_to_proxy.size() - 1;
895 
896  // Shrink the source-to-proxy mapping to reflect the new item count
897  int delta_item_count = end - start + 1;
898  source_to_proxy.remove(start, delta_item_count);
899 
900  int proxy_count = proxy_to_source.size();
901  if (proxy_count > source_to_proxy.size()) {
902  // mapping is in an inconsistent state -- redo the whole mapping
903  qWarning("QSortFilterProxyModel: inconsistent changes reported by source model");
904  remove_from_mapping(source_parent);
906  q->reset();
907  return;
908  }
909 
910  // Adjust "stale" indexes in proxy-to-source mapping
911  for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
912  int source_item = proxy_to_source.at(proxy_item);
913  if (source_item >= start) {
914  Q_ASSERT(source_item - delta_item_count >= 0);
915  proxy_to_source.replace(proxy_item, source_item - delta_item_count);
916  }
917  }
918  build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
919 
920  updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, true);
921 
922 }
923 
924 
930  Qt::Orientation orient, int start, int end, int delta_item_count, bool remove)
931 {
932  // see if any mapped children should be (re)moved
933  QVector<QPair<QModelIndex, Mapping*> > moved_source_index_mappings;
934  QVector<QModelIndex>::iterator it2 = parent_mapping->mapped_children.begin();
935  for ( ; it2 != parent_mapping->mapped_children.end();) {
936  const QModelIndex source_child_index = *it2;
937  const int pos = (orient == Qt::Vertical)
938  ? source_child_index.row()
939  : source_child_index.column();
940  if (pos < start) {
941  // not affected
942  ++it2;
943  } else if (remove && pos <= end) {
944  // in the removed interval
945  it2 = parent_mapping->mapped_children.erase(it2);
946  remove_from_mapping(source_child_index);
947  } else {
948  // below the removed items -- recompute the index
949  QModelIndex new_index;
950  const int newpos = remove ? pos - delta_item_count : pos + delta_item_count;
951  if (orient == Qt::Vertical) {
952  new_index = model->index(newpos,
953  source_child_index.column(),
954  source_parent);
955  } else {
956  new_index = model->index(source_child_index.row(),
957  newpos,
958  source_parent);
959  }
960  *it2 = new_index;
961  ++it2;
962 
963  // update mapping
964  Mapping *cm = source_index_mapping.take(source_child_index);
965  Q_ASSERT(cm);
966  // we do not reinsert right away, because the new index might be identical with another, old index
967  moved_source_index_mappings.append(QPair<QModelIndex, Mapping*>(new_index, cm));
968  }
969  }
970 
971  // reinsert moved, mapped indexes
972  QVector<QPair<QModelIndex, Mapping*> >::iterator it = moved_source_index_mappings.begin();
973  for (; it != moved_source_index_mappings.end(); ++it) {
974 #ifdef QT_STRICT_ITERATORS
975  source_index_mapping.insert((*it).first, (*it).second);
976  (*it).second->map_iter = source_index_mapping.constFind((*it).first);
977 #else
978  (*it).second->map_iter = source_index_mapping.insert((*it).first, (*it).second);
979 #endif
980  }
981 }
982 
987  const QVector<int> &source_to_proxy, const QVector<int> &source_items,
988  int &proxy_low, int &proxy_high) const
989 {
990  proxy_low = INT_MAX;
991  proxy_high = INT_MIN;
992  for (int i = 0; i < source_items.count(); ++i) {
993  int proxy_item = source_to_proxy.at(source_items.at(i));
994  Q_ASSERT(proxy_item != -1);
995  if (proxy_item < proxy_low)
996  proxy_low = proxy_item;
997  if (proxy_item > proxy_high)
998  proxy_high = proxy_item;
999  }
1000 }
1001 
1006  const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const
1007 {
1008  source_to_proxy.fill(-1);
1009  int proxy_count = proxy_to_source.size();
1010  for (int i = 0; i < proxy_count; ++i)
1011  source_to_proxy[proxy_to_source.at(i)] = i;
1012 }
1013 
1024 {
1026  QModelIndexPairList source_indexes;
1027  foreach (QPersistentModelIndexData *data, persistent.indexes) {
1028  QModelIndex proxy_index = data->index;
1029  QModelIndex source_index = q->mapToSource(proxy_index);
1030  source_indexes.append(qMakePair(proxy_index, QPersistentModelIndex(source_index)));
1031  }
1032  return source_indexes;
1033 }
1034 
1045  const QModelIndexPairList &source_indexes)
1046 {
1048  QModelIndexList from, to;
1049  for (int i = 0; i < source_indexes.count(); ++i) {
1050  QModelIndex source_index = source_indexes.at(i).second;
1051  QModelIndex old_proxy_index = source_indexes.at(i).first;
1052  create_mapping(source_index.parent());
1053  QModelIndex proxy_index = q->mapFromSource(source_index);
1054  from << old_proxy_index;
1055  to << proxy_index;
1056  }
1057  q->changePersistentIndexList(from, to);
1058 }
1059 
1060 
1071 {
1072  IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
1073  if (it == source_index_mapping.constEnd())
1074  return;
1075  Mapping *m = it.value();
1076  QSet<int> rows_removed = handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical);
1077  QSet<int> columns_removed = handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal);
1078 
1079  // We need to iterate over a copy of m->mapped_children because otherwise it may be changed by other code, invalidating
1080  // the iterator it2.
1081  // The m->mapped_children vector can be appended to with indexes which are no longer filtered
1082  // out (in create_mapping) when this function recurses for child indexes.
1083  const QVector<QModelIndex> mappedChildren = m->mapped_children;
1084  QVector<int> indexesToRemove;
1085  for (int i = 0; i < mappedChildren.size(); ++i) {
1086  const QModelIndex source_child_index = mappedChildren.at(i);
1087  if (rows_removed.contains(source_child_index.row()) || columns_removed.contains(source_child_index.column())) {
1088  indexesToRemove.push_back(i);
1089  remove_from_mapping(source_child_index);
1090  } else {
1091  filter_changed(source_child_index);
1092  }
1093  }
1094  QVector<int>::const_iterator removeIt = indexesToRemove.constEnd();
1095  const QVector<int>::const_iterator removeBegin = indexesToRemove.constBegin();
1096 
1097  // We can't just remove these items from mappedChildren while iterating above and then
1098  // do something like m->mapped_children = mappedChildren, because mapped_children might
1099  // be appended to in create_mapping, and we would lose those new items.
1100  // Because they are always appended in create_mapping, we can still remove them by
1101  // position here.
1102  while (removeIt != removeBegin) {
1103  --removeIt;
1104  m->mapped_children.remove(*removeIt);
1105  }
1106 }
1107 
1113  QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
1114  const QModelIndex &source_parent, Qt::Orientation orient)
1115 {
1117  // Figure out which mapped items to remove
1118  QVector<int> source_items_remove;
1119  for (int i = 0; i < proxy_to_source.count(); ++i) {
1120  const int source_item = proxy_to_source.at(i);
1121  if ((orient == Qt::Vertical)
1122  ? !q->filterAcceptsRow(source_item, source_parent)
1123  : !q->filterAcceptsColumn(source_item, source_parent)) {
1124  // This source item does not satisfy the filter, so it must be removed
1125  source_items_remove.append(source_item);
1126  }
1127  }
1128  // Figure out which non-mapped items to insert
1129  QVector<int> source_items_insert;
1130  int source_count = source_to_proxy.size();
1131  for (int source_item = 0; source_item < source_count; ++source_item) {
1132  if (source_to_proxy.at(source_item) == -1) {
1133  if ((orient == Qt::Vertical)
1134  ? q->filterAcceptsRow(source_item, source_parent)
1135  : q->filterAcceptsColumn(source_item, source_parent)) {
1136  // This source item satisfies the filter, so it must be added
1137  source_items_insert.append(source_item);
1138  }
1139  }
1140  }
1141  if (!source_items_remove.isEmpty() || !source_items_insert.isEmpty()) {
1142  // Do item removal and insertion
1143  remove_source_items(source_to_proxy, proxy_to_source,
1144  source_items_remove, source_parent, orient);
1145  if (orient == Qt::Vertical)
1146  sort_source_rows(source_items_insert, source_parent);
1147  insert_source_items(source_to_proxy, proxy_to_source,
1148  source_items_insert, source_parent, orient);
1149  }
1150  return qVectorToSet(source_items_remove);
1151 }
1152 
1154  const QModelIndex &source_bottom_right)
1155 {
1157  if (!source_top_left.isValid() || !source_bottom_right.isValid())
1158  return;
1159  QModelIndex source_parent = source_top_left.parent();
1160  IndexMap::const_iterator it = source_index_mapping.find(source_parent);
1161  if (it == source_index_mapping.constEnd()) {
1162  // Don't care, since we don't have mapping for this index
1163  return;
1164  }
1165  Mapping *m = it.value();
1166 
1167  // Figure out how the source changes affect us
1168  QVector<int> source_rows_remove;
1169  QVector<int> source_rows_insert;
1170  QVector<int> source_rows_change;
1171  QVector<int> source_rows_resort;
1172  int end = qMin(source_bottom_right.row(), m->proxy_rows.count() - 1);
1173  for (int source_row = source_top_left.row(); source_row <= end; ++source_row) {
1174  if (dynamic_sortfilter) {
1175  if (m->proxy_rows.at(source_row) != -1) {
1176  if (!q->filterAcceptsRow(source_row, source_parent)) {
1177  // This source row no longer satisfies the filter, so it must be removed
1178  source_rows_remove.append(source_row);
1179  } else if (source_sort_column >= source_top_left.column() && source_sort_column <= source_bottom_right.column()) {
1180  // This source row has changed in a way that may affect sorted order
1181  source_rows_resort.append(source_row);
1182  } else {
1183  // This row has simply changed, without affecting filtering nor sorting
1184  source_rows_change.append(source_row);
1185  }
1186  } else {
1187  if (!itemsBeingRemoved.contains(source_parent, source_row) && q->filterAcceptsRow(source_row, source_parent)) {
1188  // This source row now satisfies the filter, so it must be added
1189  source_rows_insert.append(source_row);
1190  }
1191  }
1192  } else {
1193  if (m->proxy_rows.at(source_row) != -1)
1194  source_rows_change.append(source_row);
1195  }
1196  }
1197 
1198  if (!source_rows_remove.isEmpty()) {
1199  remove_source_items(m->proxy_rows, m->source_rows,
1200  source_rows_remove, source_parent, Qt::Vertical);
1201  QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove);
1203  while (it != m->mapped_children.begin()) {
1204  --it;
1205  const QModelIndex source_child_index = *it;
1206  if (source_rows_remove_set.contains(source_child_index.row())) {
1207  it = m->mapped_children.erase(it);
1208  remove_from_mapping(source_child_index);
1209  }
1210  }
1211  }
1212 
1213  if (!source_rows_resort.isEmpty()) {
1214  // Re-sort the rows
1215  emit q->layoutAboutToBeChanged();
1216  QModelIndexPairList source_indexes = store_persistent_indexes();
1217  remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
1218  source_parent, Qt::Vertical, false);
1219  sort_source_rows(source_rows_resort, source_parent);
1220  insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
1221  source_parent, Qt::Vertical, false);
1222  update_persistent_indexes(source_indexes);
1223  emit q->layoutChanged();
1224  // Make sure we also emit dataChanged for the rows
1225  source_rows_change += source_rows_resort;
1226  }
1227 
1228  if (!source_rows_change.isEmpty()) {
1229  // Find the proxy row range
1230  int proxy_start_row;
1231  int proxy_end_row;
1232  proxy_item_range(m->proxy_rows, source_rows_change,
1233  proxy_start_row, proxy_end_row);
1234  // ### Find the proxy column range also
1235  if (proxy_end_row >= 0) {
1236  // the row was accepted, but some columns might still be filtered out
1237  int source_left_column = source_top_left.column();
1238  while (source_left_column < source_bottom_right.column()
1239  && m->proxy_columns.at(source_left_column) == -1)
1240  ++source_left_column;
1241  const QModelIndex proxy_top_left = create_index(
1242  proxy_start_row, m->proxy_columns.at(source_left_column), it);
1243  int source_right_column = source_bottom_right.column();
1244  while (source_right_column > source_top_left.column()
1245  && m->proxy_columns.at(source_right_column) == -1)
1246  --source_right_column;
1247  const QModelIndex proxy_bottom_right = create_index(
1248  proxy_end_row, m->proxy_columns.at(source_right_column), it);
1249  emit q->dataChanged(proxy_top_left, proxy_bottom_right);
1250  }
1251  }
1252 
1253  if (!source_rows_insert.isEmpty()) {
1254  sort_source_rows(source_rows_insert, source_parent);
1255  insert_source_items(m->proxy_rows, m->source_rows,
1256  source_rows_insert, source_parent, Qt::Vertical);
1257  }
1258 }
1259 
1261  int start, int end)
1262 {
1264  Mapping *m = create_mapping(QModelIndex()).value();
1265  int proxy_start = (orientation == Qt::Vertical
1266  ? m->proxy_rows.at(start)
1267  : m->proxy_columns.at(start));
1268  int proxy_end = (orientation == Qt::Vertical
1269  ? m->proxy_rows.at(end)
1270  : m->proxy_columns.at(end));
1271  emit q->headerDataChanged(orientation, proxy_start, proxy_end);
1272 }
1273 
1275 {
1277  q->beginResetModel();
1278 }
1279 
1281 {
1283  invalidatePersistentIndexes();
1284  _q_clearMapping();
1285  // All internal structures are deleted in clear()
1286  q->endResetModel();
1287  update_source_sort_column();
1288  if (dynamic_sortfilter)
1289  sort();
1290 }
1291 
1293 {
1295  saved_persistent_indexes.clear();
1296  emit q->layoutAboutToBeChanged();
1297  if (persistent.indexes.isEmpty())
1298  return;
1299 
1300  saved_persistent_indexes = store_persistent_indexes();
1301 }
1302 
1304 {
1306 
1307  qDeleteAll(source_index_mapping);
1308  source_index_mapping.clear();
1309 
1310  update_persistent_indexes(saved_persistent_indexes);
1311  saved_persistent_indexes.clear();
1312 
1313  if (dynamic_sortfilter && update_source_sort_column()) {
1314  //update_source_sort_column might have created wrong mapping so we have to clear it again
1315  qDeleteAll(source_index_mapping);
1316  source_index_mapping.clear();
1317  }
1318 
1319  emit q->layoutChanged();
1320 }
1321 
1323  const QModelIndex &source_parent, int start, int end)
1324 {
1325  Q_UNUSED(start);
1326  Q_UNUSED(end);
1327  //Force the creation of a mapping now, even if its empty.
1328  //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items
1329  if (can_create_mapping(source_parent))
1330  create_mapping(source_parent);
1331 }
1332 
1334  const QModelIndex &source_parent, int start, int end)
1335 {
1336  source_items_inserted(source_parent, start, end, Qt::Vertical);
1337  if (update_source_sort_column() && dynamic_sortfilter) //previous call to update_source_sort_column may fail if the model has no column.
1338  sort(); // now it should succeed so we need to make sure to sort again
1339 }
1340 
1342  const QModelIndex &source_parent, int start, int end)
1343 {
1344  itemsBeingRemoved = QRowsRemoval(source_parent, start, end);
1345  source_items_about_to_be_removed(source_parent, start, end,
1346  Qt::Vertical);
1347 }
1348 
1350  const QModelIndex &source_parent, int start, int end)
1351 {
1352  itemsBeingRemoved = QRowsRemoval();
1353  source_items_removed(source_parent, start, end, Qt::Vertical);
1354 }
1355 
1357  const QModelIndex &source_parent, int start, int end)
1358 {
1359  Q_UNUSED(start);
1360  Q_UNUSED(end);
1361  //Force the creation of a mapping now, even if its empty.
1362  //We need it because the proxy can be acessed at the moment it emits columnsAboutToBeInserted in insert_source_items
1363  if (can_create_mapping(source_parent))
1364  create_mapping(source_parent);
1365 }
1366 
1368  const QModelIndex &source_parent, int start, int end)
1369 {
1370  Q_Q(const QSortFilterProxyModel);
1371  source_items_inserted(source_parent, start, end, Qt::Horizontal);
1372 
1373  if (source_parent.isValid())
1374  return; //we sort according to the root column only
1375  if (source_sort_column == -1) {
1376  //we update the source_sort_column depending on the proxy_sort_column
1377  if (update_source_sort_column() && dynamic_sortfilter)
1378  sort();
1379  } else {
1380  if (start <= source_sort_column)
1381  source_sort_column += end - start + 1;
1382 
1383  proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
1384  }
1385 }
1386 
1388  const QModelIndex &source_parent, int start, int end)
1389 {
1390  source_items_about_to_be_removed(source_parent, start, end,
1391  Qt::Horizontal);
1392 }
1393 
1395  const QModelIndex &source_parent, int start, int end)
1396 {
1397  Q_Q(const QSortFilterProxyModel);
1398  source_items_removed(source_parent, start, end, Qt::Horizontal);
1399 
1400  if (source_parent.isValid())
1401  return; //we sort according to the root column only
1402  if (start <= source_sort_column) {
1403  if (end < source_sort_column)
1404  source_sort_column -= end - start + 1;
1405  else
1406  source_sort_column = -1;
1407  }
1408 
1409  proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
1410 }
1411 
1571 {
1573  d->proxy_sort_column = d->source_sort_column = -1;
1574  d->sort_order = Qt::AscendingOrder;
1575  d->sort_casesensitivity = Qt::CaseSensitive;
1576  d->sort_role = Qt::DisplayRole;
1577  d->sort_localeaware = false;
1578  d->filter_column = 0;
1579  d->filter_role = Qt::DisplayRole;
1580  d->dynamic_sortfilter = false;
1581  connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping()));
1582 }
1583 
1588 {
1590  qDeleteAll(d->source_index_mapping);
1591  d->source_index_mapping.clear();
1592 }
1593 
1598 {
1600 
1601  beginResetModel();
1602 
1604  this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex)));
1605 
1607  this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
1608 
1610  this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
1611 
1612  disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1613  this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
1614 
1616  this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
1617 
1618  disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1619  this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
1620 
1622  this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
1623 
1624  disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1625  this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
1626 
1628  this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
1629 
1630  disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1631  this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
1632 
1634  this, SLOT(_q_sourceLayoutAboutToBeChanged()));
1635 
1636  disconnect(d->model, SIGNAL(layoutChanged()),
1637  this, SLOT(_q_sourceLayoutChanged()));
1638 
1639  disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
1640  disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
1641 
1643 
1645  this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex)));
1646 
1647  connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
1648  this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
1649 
1650  connect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
1651  this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
1652 
1653  connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1654  this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
1655 
1657  this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
1658 
1659  connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1660  this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
1661 
1662  connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
1663  this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
1664 
1665  connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1666  this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
1667 
1669  this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
1670 
1671  connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1672  this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
1673 
1675  this, SLOT(_q_sourceLayoutAboutToBeChanged()));
1676 
1677  connect(d->model, SIGNAL(layoutChanged()),
1678  this, SLOT(_q_sourceLayoutChanged()));
1679 
1680  connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
1681  connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
1682 
1683  d->_q_clearMapping();
1684  endResetModel();
1685  if (d->update_source_sort_column() && d->dynamic_sortfilter)
1686  d->sort();
1687 }
1688 
1693 {
1694  Q_D(const QSortFilterProxyModel);
1695  if (row < 0 || column < 0)
1696  return QModelIndex();
1697 
1698  QModelIndex source_parent = mapToSource(parent); // parent is already mapped at this point
1699  IndexMap::const_iterator it = d->create_mapping(source_parent); // but make sure that the children are mapped
1700  if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column)
1701  return QModelIndex();
1702 
1703  return d->create_index(row, column, it);
1704 }
1705 
1710 {
1711  Q_D(const QSortFilterProxyModel);
1712  if (!d->indexValid(child))
1713  return QModelIndex();
1714  IndexMap::const_iterator it = d->index_to_iterator(child);
1715  Q_ASSERT(it != d->source_index_mapping.constEnd());
1716  QModelIndex source_parent = it.key();
1717  QModelIndex proxy_parent = mapFromSource(source_parent);
1718  return proxy_parent;
1719 }
1720 
1725 {
1726  Q_D(const QSortFilterProxyModel);
1727  QModelIndex source_parent = mapToSource(parent);
1728  if (parent.isValid() && !source_parent.isValid())
1729  return 0;
1730  IndexMap::const_iterator it = d->create_mapping(source_parent);
1731  return it.value()->source_rows.count();
1732 }
1733 
1738 {
1739  Q_D(const QSortFilterProxyModel);
1740  QModelIndex source_parent = mapToSource(parent);
1741  if (parent.isValid() && !source_parent.isValid())
1742  return 0;
1743  IndexMap::const_iterator it = d->create_mapping(source_parent);
1744  return it.value()->source_columns.count();
1745 }
1746 
1751 {
1752  Q_D(const QSortFilterProxyModel);
1753  QModelIndex source_parent = mapToSource(parent);
1754  if (parent.isValid() && !source_parent.isValid())
1755  return false;
1756  if (!d->model->hasChildren(source_parent))
1757  return false;
1758 
1759  if (d->model->canFetchMore(source_parent))
1760  return true; //we assume we might have children that can be fetched
1761 
1762  QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1763  return m->source_rows.count() != 0 && m->source_columns.count() != 0;
1764 }
1765 
1770 {
1771  Q_D(const QSortFilterProxyModel);
1772  QModelIndex source_index = mapToSource(index);
1773  if (index.isValid() && !source_index.isValid())
1774  return QVariant();
1775  return d->model->data(source_index, role);
1776 }
1777 
1781 bool QSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
1782 {
1784  QModelIndex source_index = mapToSource(index);
1785  if (index.isValid() && !source_index.isValid())
1786  return false;
1787  return d->model->setData(source_index, value, role);
1788 }
1789 
1793 QVariant QSortFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
1794 {
1795  Q_D(const QSortFilterProxyModel);
1796  IndexMap::const_iterator it = d->create_mapping(QModelIndex());
1797  if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
1798  return QAbstractProxyModel::headerData(section, orientation, role);
1799  int source_section;
1800  if (orientation == Qt::Vertical) {
1801  if (section < 0 || section >= it.value()->source_rows.count())
1802  return QVariant();
1803  source_section = it.value()->source_rows.at(section);
1804  } else {
1805  if (section < 0 || section >= it.value()->source_columns.count())
1806  return QVariant();
1807  source_section = it.value()->source_columns.at(section);
1808  }
1809  return d->model->headerData(source_section, orientation, role);
1810 }
1811 
1816  const QVariant &value, int role)
1817 {
1819  IndexMap::const_iterator it = d->create_mapping(QModelIndex());
1820  if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
1821  return QAbstractProxyModel::setHeaderData(section, orientation, value, role);
1822  int source_section;
1823  if (orientation == Qt::Vertical) {
1824  if (section < 0 || section >= it.value()->source_rows.count())
1825  return false;
1826  source_section = it.value()->source_rows.at(section);
1827  } else {
1828  if (section < 0 || section >= it.value()->source_columns.count())
1829  return false;
1830  source_section = it.value()->source_columns.at(section);
1831  }
1832  return d->model->setHeaderData(source_section, orientation, value, role);
1833 }
1834 
1839 {
1840  Q_D(const QSortFilterProxyModel);
1841  QModelIndexList source_indexes;
1842  for (int i = 0; i < indexes.count(); ++i)
1843  source_indexes << mapToSource(indexes.at(i));
1844  return d->model->mimeData(source_indexes);
1845 }
1846 
1851 {
1852  Q_D(const QSortFilterProxyModel);
1853  return d->model->mimeTypes();
1854 }
1855 
1860 {
1861  Q_D(const QSortFilterProxyModel);
1862  return d->model->supportedDropActions();
1863 }
1864 
1869  int row, int column, const QModelIndex &parent)
1870 {
1872  if ((row == -1) && (column == -1))
1873  return d->model->dropMimeData(data, action, -1, -1, mapToSource(parent));
1874  int source_destination_row = -1;
1875  int source_destination_column = -1;
1876  QModelIndex source_parent;
1877  if (row == rowCount(parent)) {
1878  source_parent = mapToSource(parent);
1879  source_destination_row = d->model->rowCount(source_parent);
1880  } else {
1881  QModelIndex proxy_index = index(row, column, parent);
1882  QModelIndex source_index = mapToSource(proxy_index);
1883  source_destination_row = source_index.row();
1884  source_destination_column = source_index.column();
1885  source_parent = source_index.parent();
1886  }
1887  return d->model->dropMimeData(data, action, source_destination_row,
1888  source_destination_column, source_parent);
1889 }
1890 
1894 bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &parent)
1895 {
1897  if (row < 0 || count <= 0)
1898  return false;
1899  QModelIndex source_parent = mapToSource(parent);
1900  if (parent.isValid() && !source_parent.isValid())
1901  return false;
1902  QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1903  if (row > m->source_rows.count())
1904  return false;
1905  int source_row = (row >= m->source_rows.count()
1906  ? m->source_rows.count()
1907  : m->source_rows.at(row));
1908  return d->model->insertRows(source_row, count, source_parent);
1909 }
1910 
1914 bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelIndex &parent)
1915 {
1917  if (column < 0|| count <= 0)
1918  return false;
1919  QModelIndex source_parent = mapToSource(parent);
1920  if (parent.isValid() && !source_parent.isValid())
1921  return false;
1922  QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1923  if (column > m->source_columns.count())
1924  return false;
1925  int source_column = (column >= m->source_columns.count()
1926  ? m->source_columns.count()
1927  : m->source_columns.at(column));
1928  return d->model->insertColumns(source_column, count, source_parent);
1929 }
1930 
1934 bool QSortFilterProxyModel::removeRows(int row, int count, const QModelIndex &parent)
1935 {
1937  if (row < 0 || count <= 0)
1938  return false;
1939  QModelIndex source_parent = mapToSource(parent);
1940  if (parent.isValid() && !source_parent.isValid())
1941  return false;
1942  QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1943  if (row + count > m->source_rows.count())
1944  return false;
1945  if ((count == 1)
1946  || ((d->source_sort_column < 0) && (m->proxy_rows.count() == m->source_rows.count()))) {
1947  int source_row = m->source_rows.at(row);
1948  return d->model->removeRows(source_row, count, source_parent);
1949  }
1950  // remove corresponding source intervals
1951  // ### if this proves to be slow, we can switch to single-row removal
1952  QVector<int> rows;
1953  for (int i = row; i < row + count; ++i)
1954  rows.append(m->source_rows.at(i));
1955  qSort(rows.begin(), rows.end());
1956 
1957  int pos = rows.count() - 1;
1958  bool ok = true;
1959  while (pos >= 0) {
1960  const int source_end = rows.at(pos--);
1961  int source_start = source_end;
1962  while ((pos >= 0) && (rows.at(pos) == (source_start - 1))) {
1963  --source_start;
1964  --pos;
1965  }
1966  ok = ok && d->model->removeRows(source_start, source_end - source_start + 1,
1967  source_parent);
1968  }
1969  return ok;
1970 }
1971 
1975 bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelIndex &parent)
1976 {
1978  if (column < 0 || count <= 0)
1979  return false;
1980  QModelIndex source_parent = mapToSource(parent);
1981  if (parent.isValid() && !source_parent.isValid())
1982  return false;
1983  QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1984  if (column + count > m->source_columns.count())
1985  return false;
1986  if ((count == 1) || (m->proxy_columns.count() == m->source_columns.count())) {
1987  int source_column = m->source_columns.at(column);
1988  return d->model->removeColumns(source_column, count, source_parent);
1989  }
1990  // remove corresponding source intervals
1991  QVector<int> columns;
1992  for (int i = column; i < column + count; ++i)
1993  columns.append(m->source_columns.at(i));
1994 
1995  int pos = columns.count() - 1;
1996  bool ok = true;
1997  while (pos >= 0) {
1998  const int source_end = columns.at(pos--);
1999  int source_start = source_end;
2000  while ((pos >= 0) && (columns.at(pos) == (source_start - 1))) {
2001  --source_start;
2002  --pos;
2003  }
2004  ok = ok && d->model->removeColumns(source_start, source_end - source_start + 1,
2005  source_parent);
2006  }
2007  return ok;
2008 }
2009 
2014 {
2016  QModelIndex source_parent;
2017  if (d->indexValid(parent))
2018  source_parent = mapToSource(parent);
2019  d->model->fetchMore(source_parent);
2020 }
2021 
2026 {
2027  Q_D(const QSortFilterProxyModel);
2028  QModelIndex source_parent;
2029  if (d->indexValid(parent))
2030  source_parent = mapToSource(parent);
2031  return d->model->canFetchMore(source_parent);
2032 }
2033 
2038 {
2039  Q_D(const QSortFilterProxyModel);
2040  QModelIndex source_index;
2041  if (d->indexValid(index))
2042  source_index = mapToSource(index);
2043  return d->model->flags(source_index);
2044 }
2045 
2050 {
2051  Q_D(const QSortFilterProxyModel);
2052  if (!d->indexValid(index))
2053  return QModelIndex();
2054  QModelIndex source_index = mapToSource(index);
2055  QModelIndex source_buddy = d->model->buddy(source_index);
2056  if (source_index == source_buddy)
2057  return index;
2058  return mapFromSource(source_buddy);
2059 }
2060 
2065  const QVariant &value, int hits,
2066  Qt::MatchFlags flags) const
2067 {
2068  return QAbstractProxyModel::match(start, role, value, hits, flags);
2069 }
2070 
2075 {
2076  Q_D(const QSortFilterProxyModel);
2077  QModelIndex source_index = mapToSource(index);
2078  if (index.isValid() && !source_index.isValid())
2079  return QSize();
2080  return d->model->span(source_index);
2081 }
2082 
2087 {
2089  if (d->dynamic_sortfilter && d->proxy_sort_column == column && d->sort_order == order)
2090  return;
2091  d->sort_order = order;
2092  d->proxy_sort_column = column;
2093  d->update_source_sort_column();
2094  d->sort();
2095 }
2096 
2107 {
2108  Q_D(const QSortFilterProxyModel);
2109  return d->proxy_sort_column;
2110 }
2111 
2122 {
2123  Q_D(const QSortFilterProxyModel);
2124  return d->sort_order;
2125 }
2126 
2144 {
2145  Q_D(const QSortFilterProxyModel);
2146  return d->filter_regexp;
2147 }
2148 
2150 {
2152  d->filter_regexp = regExp;
2153  d->filter_changed();
2154 }
2155 
2168 {
2169  Q_D(const QSortFilterProxyModel);
2170  return d->filter_column;
2171 }
2172 
2174 {
2176  d->filter_column = column;
2177  d->filter_changed();
2178 }
2179 
2194 {
2195  Q_D(const QSortFilterProxyModel);
2196  return d->filter_regexp.caseSensitivity();
2197 }
2198 
2200 {
2202  if (cs == d->filter_regexp.caseSensitivity())
2203  return;
2204  d->filter_regexp.setCaseSensitivity(cs);
2205  d->filter_changed();
2206 }
2207 
2221 {
2222  Q_D(const QSortFilterProxyModel);
2223  return d->sort_casesensitivity;
2224 }
2225 
2227 {
2229  if (d->sort_casesensitivity == cs)
2230  return;
2231 
2232  d->sort_casesensitivity = cs;
2233  d->sort();
2234 }
2235 
2249 {
2250  Q_D(const QSortFilterProxyModel);
2251  return d->sort_localeaware;
2252 }
2253 
2255 {
2257  if (d->sort_localeaware == on)
2258  return;
2259 
2260  d->sort_localeaware = on;
2261  d->sort();
2262 }
2263 
2276 {
2278  d->filter_regexp.setPatternSyntax(QRegExp::RegExp);
2279  d->filter_regexp.setPattern(pattern);
2280  d->filter_changed();
2281 }
2282 
2290 {
2292  d->filter_regexp.setPatternSyntax(QRegExp::Wildcard);
2293  d->filter_regexp.setPattern(pattern);
2294  d->filter_changed();
2295 }
2296 
2304 {
2306  d->filter_regexp.setPatternSyntax(QRegExp::FixedString);
2307  d->filter_regexp.setPattern(pattern);
2308  d->filter_changed();
2309 }
2310 
2331 {
2332  Q_D(const QSortFilterProxyModel);
2333  return d->dynamic_sortfilter;
2334 }
2335 
2337 {
2339  d->dynamic_sortfilter = enable;
2340  if (enable)
2341  d->sort();
2342 }
2343 
2357 {
2358  Q_D(const QSortFilterProxyModel);
2359  return d->sort_role;
2360 }
2361 
2363 {
2365  if (d->sort_role == role)
2366  return;
2367  d->sort_role = role;
2368  d->sort();
2369 }
2370 
2384 {
2385  Q_D(const QSortFilterProxyModel);
2386  return d->filter_role;
2387 }
2388 
2390 {
2392  if (d->filter_role == role)
2393  return;
2394  d->filter_role = role;
2395  d->filter_changed();
2396 }
2397 
2407 {
2410  d->_q_clearMapping();
2411  emit layoutChanged();
2412 }
2413 
2425 {
2428  d->_q_clearMapping();
2429  emit layoutChanged();
2430 }
2431 
2441 {
2443  d->filter_changed();
2444 }
2445 
2460 {
2462  d->filter_changed();
2463 }
2464 
2502 {
2503  Q_D(const QSortFilterProxyModel);
2504  QVariant l = (left.model() ? left.model()->data(left, d->sort_role) : QVariant());
2505  QVariant r = (right.model() ? right.model()->data(right, d->sort_role) : QVariant());
2506  switch (l.userType()) {
2507  case QVariant::Invalid:
2508  return (r.type() != QVariant::Invalid);
2509  case QVariant::Int:
2510  return l.toInt() < r.toInt();
2511  case QVariant::UInt:
2512  return l.toUInt() < r.toUInt();
2513  case QVariant::LongLong:
2514  return l.toLongLong() < r.toLongLong();
2515  case QVariant::ULongLong:
2516  return l.toULongLong() < r.toULongLong();
2517  case QMetaType::Float:
2518  return l.toFloat() < r.toFloat();
2519  case QVariant::Double:
2520  return l.toDouble() < r.toDouble();
2521  case QVariant::Char:
2522  return l.toChar() < r.toChar();
2523  case QVariant::Date:
2524  return l.toDate() < r.toDate();
2525  case QVariant::Time:
2526  return l.toTime() < r.toTime();
2527  case QVariant::DateTime:
2528  return l.toDateTime() < r.toDateTime();
2529  case QVariant::String:
2530  default:
2531  if (d->sort_localeaware)
2532  return l.toString().localeAwareCompare(r.toString()) < 0;
2533  else
2534  return l.toString().compare(r.toString(), d->sort_casesensitivity) < 0;
2535  }
2536  return false;
2537 }
2538 
2553 bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
2554 {
2555  Q_D(const QSortFilterProxyModel);
2556  if (d->filter_regexp.isEmpty())
2557  return true;
2558  if (d->filter_column == -1) {
2559  int column_count = d->model->columnCount(source_parent);
2560  for (int column = 0; column < column_count; ++column) {
2561  QModelIndex source_index = d->model->index(source_row, column, source_parent);
2562  QString key = d->model->data(source_index, d->filter_role).toString();
2563  if (key.contains(d->filter_regexp))
2564  return true;
2565  }
2566  return false;
2567  }
2568  QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
2569  if (!source_index.isValid()) // the column may not exist
2570  return true;
2571  QString key = d->model->data(source_index, d->filter_role).toString();
2572  return key.contains(d->filter_regexp);
2573 }
2574 
2587 bool QSortFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
2588 {
2589  Q_UNUSED(source_column);
2590  Q_UNUSED(source_parent);
2591  return true;
2592 }
2593 
2601 {
2602  Q_D(const QSortFilterProxyModel);
2603  return d->proxy_to_source(proxyIndex);
2604 }
2605 
2613 {
2614  Q_D(const QSortFilterProxyModel);
2615  return d->source_to_proxy(sourceIndex);
2616 }
2617 
2622 {
2623  return QAbstractProxyModel::mapSelectionToSource(proxySelection);
2624 }
2625 
2630 {
2631  return QAbstractProxyModel::mapSelectionFromSource(sourceSelection);
2632 }
2633 
2640 
2641 #include "moc_qsortfilterproxymodel.cpp"
2642 
2643 #endif // QT_NO_SORTFILTERPROXYMODEL
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
void source_items_inserted(const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
Handles source model items insertion (columnsInserted(), rowsInserted()).
QBool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.h:904
double d
Definition: qnumeric_p.h:62
virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits=1, Qt::MatchFlags flags=Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const
Returns a list of indexes for the items in the column of the start index where data stored under the ...
void * internalPointer() const
Returns a void * pointer used by the model to associate the index with the internal data structure...
QModelIndexPairList store_persistent_indexes()
Maps the persistent proxy indexes to source indexes and returns the list of source indexes...
void _q_sourceColumnsInserted(const QModelIndex &source_parent, int start, int end)
The QHash::const_iterator class provides an STL-style const iterator for QHash and QMultiHash...
Definition: qhash.h:395
bool isSortLocaleAware() const
void _q_sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end)
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QModelIndex mapToSource(const QModelIndex &proxyIndex) const
Returns the source model index corresponding to the given proxyIndex from the sorting filter model...
void _q_sourceColumnsRemoved(const QModelIndex &source_parent, int start, int end)
bool operator()(int r1, int r2) const
void proxy_item_range(const QVector< int > &source_to_proxy, const QVector< int > &source_items, int &proxy_low, int &proxy_high) const
void remove(int i)
Removes the element at index position i.
Definition: qvector.h:374
The QRegExp class provides pattern matching using regular expressions.
Definition: qregexp.h:61
QHash< QModelIndex, QSortFilterProxyModelPrivate::Mapping * > IndexMap
QVector< T > & fill(const T &t, int size=-1)
Assigns value to all items in the vector.
Definition: qvector.h:665
void setFilterWildcard(const QString &pattern)
Sets the wildcard expression used to filter the contents of the source model to the given pattern...
#define it(className, varName)
void sort_source_rows(QVector< int > &source_rows, const QModelIndex &source_parent) const
Sorts the given source_rows according to current sort column and order.
void clear()
This function is obsolete.
int count(const T &t) const
Returns the number of occurrences of value in the vector.
Definition: qvector.h:742
virtual QItemSelection mapSelectionToSource(const QItemSelection &selection) const
Returns a source selection mapped from the specified proxySelection.
void _q_sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end)
void updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping, Qt::Orientation orient, int start, int end, int delta_item_count, bool remove)
virtual QItemSelection mapSelectionFromSource(const QItemSelection &selection) const
Returns a proxy selection mapped from the specified sourceSelection.
QVariant headerData(int section, Qt::Orientation orientation, int role) const
Reimplemented Function
int rowCount(const QModelIndex &parent=QModelIndex()) const
Reimplemented Function
virtual void setSourceModel(QAbstractItemModel *sourceModel)
Sets the given sourceModel to be processed by the proxy model.
#define SLOT(a)
Definition: qobjectdefs.h:226
T1 first
Definition: qpair.h:65
void setFilterFixedString(const QString &pattern)
Sets the fixed string used to filter the contents of the source model to the given pattern...
const_iterator constEnd() const
Returns a const STL-style iterator pointing to the imaginary item after the last item in the vector...
Definition: qvector.h:252
T2 second
Definition: qpair.h:66
const QAbstractItemModel * source_model
QString toString() const
Returns the variant as a QString if the variant has type() String , Bool , ByteArray ...
Definition: qvariant.cpp:2270
QDateTime toDateTime() const
Returns the variant as a QDateTime if the variant has type() DateTime , Date , or String ; otherwise ...
Definition: qvariant.cpp:2349
QStringList mimeTypes() const
Reimplemented Function
void remove_proxy_interval(QVector< int > &source_to_proxy, QVector< int > &proxy_to_source, int proxy_start, int proxy_end, const QModelIndex &proxy_parent, Qt::Orientation orient, bool emit_signal=true)
Given source-to-proxy mapping source_to_proxy and proxy-to-source mapping proxy_to_source, removes items from proxy_start to proxy_end (inclusive) from this proxy model.
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role=Qt::EditRole)
Reimplemented Function
void columnsInserted(const QModelIndex &parent, int first, int last)
This signal is emitted after columns have been inserted into the model.
bool contains(QModelIndex parent, int row)
void build_source_to_proxy_mapping(const QVector< int > &proxy_to_source, QVector< int > &source_to_proxy) const
Qt::DropActions supportedDropActions() const
Reimplemented Function
void _q_sourceRowsInserted(const QModelIndex &source_parent, int start, int end)
int sortColumn() const
the column currently used for sorting
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
virtual bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
Returns true if the item in the column indicated by the given source_column and source_parent should ...
~QSortFilterProxyModel()
Destroys this sorting filter model.
void source_items_removed(const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
Handles source model items removal (columnsRemoved(), rowsRemoved()).
The QString class provides a Unicode character string.
Definition: qstring.h:83
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
QSize span(const QModelIndex &index) const
Reimplemented Function
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
Reimplemented Function
#define Q_D(Class)
Definition: qglobal.h:2482
QSortFilterProxyModelLessThan(int column, const QModelIndex &parent, const QAbstractItemModel *source, const QSortFilterProxyModel *proxy)
QHash< QModelIndex, Mapping * >::const_iterator index_to_iterator(const QModelIndex &proxy_index) const
void update_persistent_indexes(const QModelIndexPairList &source_indexes)
Maps source_indexes to proxy indexes and stores those as persistent indexes.
bool removeColumns(int column, int count, const QModelIndex &parent=QModelIndex())
Reimplemented Function
void endResetModel()
Completes a model reset operation.
void _q_sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right)
QModelIndex parent() const
Returns the parent of the model index, or QModelIndex() if it has no parent.
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
QSet< int > handle_filter_changed(QVector< int > &source_to_proxy, QVector< int > &proxy_to_source, const QModelIndex &source_parent, Qt::Orientation orient)
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role=Qt::EditRole)
Reimplemented Function
Qt::CaseSensitivity filterCaseSensitivity() const
void resize(int size)
Sets the size of the vector to size.
Definition: qvector.h:342
QRowsRemoval(const QModelIndex &parent_source, int start, int end)
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the vector...
Definition: qvector.h:250
#define Q_Q(Class)
Definition: qglobal.h:2483
int toInt(bool *ok=0) const
Returns the variant as an int if the variant has type() Int , Bool , ByteArray , Char ...
Definition: qvariant.cpp:2625
const QAbstractItemModel * source_model
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const =0
Returns the index of the item in the model specified by the given row, column and parent index...
void _q_sourceColumnsAboutToBeInserted(const QModelIndex &source_parent, int start, int end)
void setSortCaseSensitivity(Qt::CaseSensitivity cs)
#define SIGNAL(a)
Definition: qobjectdefs.h:227
const_iterator constBegin() const
Returns a const STL-style iterator pointing to the first item in the vector.
Definition: qvector.h:249
void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last)
This signal is emitted just before columns are inserted into the model.
Qt::CaseSensitivity sortCaseSensitivity() const
void sort()
Sorts the existing mappings.
SortOrder
Definition: qnamespace.h:189
void setFilterRegExp(const QRegExp &regExp)
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
static QSet< int > qVectorToSet(const QVector< int > &vector)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
qlonglong toLongLong(bool *ok=0) const
Returns the variant as a long long int if the variant has type() LongLong , Bool , ByteArray , Char , Double , Int , String , UInt , or ULongLong ; otherwise returns 0.
Definition: qvariant.cpp:2659
static bool compare(const QVariant::Private *a, const QVariant::Private *b)
Compares a to b.
Definition: qvariant.cpp:383
bool hasChildren(const QModelIndex &parent=QModelIndex()) const
Reimplemented Function
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
Reimplemented Function
QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const
Reimplemented Function
int filterRole() const
QModelIndexPairList saved_persistent_indexes
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const
Returns true if the value of the item referred to by the given index left is less than the value of t...
void layoutAboutToBeChanged()
This signal is emitted just before the layout of a model is changed.
void clear()
Removes all the elements from the vector and releases the memory used by the vector.
Definition: qvector.h:347
bool contains(const T &value) const
Definition: qset.h:91
static void sort(T *array, int count, LessThan lessThan)
QAbstractItemModel * sourceModel() const
Returns the model that contains the data that is available through the proxy model.
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last)
This signal is emitted just before rows are inserted into the model.
QMimeData * mimeData(const QModelIndexList &indexes) const
Reimplemented Function
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex())
Reimplemented Function
void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end)
int row() const
Returns the row this model index refers to.
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
const QAbstractItemModel * model() const
Returns a pointer to the model containing the item that this index refers to.
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Reimplemented Function
void append(const T &t)
Inserts value at the end of the vector.
Definition: qvector.h:573
void fetchMore(const QModelIndex &parent)
Reimplemented Function
void modelAboutToBeReset()
This signal is emitted when reset() is called, before the model&#39;s internal state (e.
qulonglong toULongLong(bool *ok=0) const
Returns the variant as as an unsigned long long int if the variant has type() ULongLong ...
Definition: qvariant.cpp:2675
const T & value() const
Returns the current item&#39;s value.
Definition: qhash.h:420
Q_CORE_EXPORT void qWarning(const char *,...)
void invalidateFilter()
Invalidates the current filtering.
static const char * data(const QByteArray &arr)
QVector< QPair< int, int > > proxy_intervals_for_source_items(const QVector< int > &source_to_proxy, const QVector< int > &source_items) const
Given source-to-proxy mapping source_to_proxy and the set of source items source_items (which are par...
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
Returns true if the item in the row indicated by the given source_row and source_parent should be inc...
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const =0
Returns the data stored under the given role for the item referred to by the index.
QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const
DropAction
Definition: qnamespace.h:1597
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder)
Reimplemented Function
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
Reimplemented Function
void remove_source_items(QVector< int > &source_to_proxy, QVector< int > &proxy_to_source, const QVector< int > &source_items, const QModelIndex &source_parent, Qt::Orientation orient, bool emit_signal=true)
Given source-to-proxy mapping src_to_proxy and proxy-to-source mapping proxy_to_source, removes source_items from this proxy model.
void layoutChanged()
This signal is emitted whenever the layout of items exposed by the model has changed; for example...
QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits=1, Qt::MatchFlags flags=Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const
Reimplemented Function
QHash< QModelIndex, Mapping * > source_index_mapping
The QMimeData class provides a container for data that records information about its MIME type...
Definition: qmimedata.h:57
const QSortFilterProxyModel * proxy_model
bool dynamicSortFilter() const
bool isValid() const
Returns true if this model index is valid; otherwise returns false.
void qSort(RandomAccessIterator start, RandomAccessIterator end)
Definition: qalgorithms.h:177
int localeAwareCompare(const QString &s) const
Definition: qstring.cpp:5197
QSortFilterProxyModelGreaterThan(int column, const QModelIndex &parent, const QAbstractItemModel *source, const QSortFilterProxyModel *proxy)
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
The QAbstractItemModel class provides the abstract interface for item model classes.
The QAbstractProxyModel class provides a base class for proxy item models that can do sorting...
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
Reimplemented Function
void qStableSort(RandomAccessIterator start, RandomAccessIterator end)
Definition: qalgorithms.h:202
void filter_changed(const QModelIndex &source_parent=QModelIndex())
Updates the proxy model (adds/removes rows) based on the new filter.
void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end)
void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
This signal is emitted just before columns are removed from the model.
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
void insert(int i, const T &t)
Inserts value at index position i in the vector.
Definition: qvector.h:362
CaseSensitivity
Definition: qnamespace.h:1451
const_iterator constEnd() const
Returns a const STL-style iterator pointing to the imaginary item after the last item in the hash...
Definition: qhash.h:469
void setSourceModel(QAbstractItemModel *sourceModel)
Reimplemented Function
QDate toDate() const
Returns the variant as a QDate if the variant has type() Date , DateTime , or String ; otherwise retu...
Definition: qvariant.cpp:2311
The QSortFilterProxyModel class provides support for sorting and filtering data passed between anothe...
int userType() const
Returns the storage type of the value stored in the variant.
Definition: qvariant.cpp:1913
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
The QItemSelection class manages information about selected items in a model.
int compare(const QString &s) const
Definition: qstring.cpp:5037
QSortFilterProxyModel(QObject *parent=0)
Constructs a sorting filter model with the given parent.
iterator begin()
Returns an STL-style iterator pointing to the first item in the vector.
Definition: qvector.h:247
QRegExp filterRegExp() const
void headerDataChanged(Qt::Orientation orientation, int first, int last)
This signal is emitted whenever a header is changed.
The QPersistentModelIndex class is used to locate data in a data model.
void rowsInserted(const QModelIndex &parent, int first, int last)
This signal is emitted after rows have been inserted into the model.
QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const
Type type() const
Returns the storage type of the value stored in the variant.
Definition: qvariant.cpp:1901
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
Q_OUTOFLINE_TEMPLATE QPair< T1, T2 > qMakePair(const T1 &x, const T2 &y)
Definition: qpair.h:102
iterator erase(iterator begin, iterator end)
Removes all the items from begin up to (but not including) end.
Definition: qvector.h:627
Qt::ItemFlags flags(const QModelIndex &index) const
Reimplemented Function
int key
const QSortFilterProxyModel * proxy_model
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Reimplemented Function
QVector< QPair< int, QVector< int > > > proxy_intervals_for_source_items_to_add(const QVector< int > &proxy_to_source, const QVector< int > &source_items, const QModelIndex &source_parent, Qt::Orientation orient) const
Given proxy-to-source mapping proxy_to_source and a set of unmapped source items source_items, determines the proxy item intervals at which the subsets of source items should be inserted (but does not actually add them to the mapping).
The QModelIndex class is used to locate data in a data model.
uint toUInt(bool *ok=0) const
Returns the variant as an unsigned int if the variant has type() UInt , Bool , ByteArray ...
Definition: qvariant.cpp:2644
float toFloat(bool *ok=0) const
Returns the variant as a float if the variant has type() Double , QMetaType::Float ...
Definition: qvariant.cpp:2725
void modelReset()
This signal is emitted when reset() is called, after the model&#39;s internal state (e.
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
This signal is emitted whenever the data in an existing item changes.
QModelIndex create_index(int row, int column, QHash< QModelIndex, Mapping *>::const_iterator it) const
QFactoryLoader * l
bool operator()(int r1, int r2) const
QList< QPair< QModelIndex, QPersistentModelIndex > > QModelIndexPairList
void push_back(const T &t)
This function is provided for STL compatibility.
Definition: qvector.h:281
double toDouble(bool *ok=0) const
Returns the variant as a double if the variant has type() Double , QMetaType::Float ...
Definition: qvariant.cpp:2710
bool insertColumns(int column, int count, const QModelIndex &parent=QModelIndex())
Reimplemented Function
void setFilterCaseSensitivity(Qt::CaseSensitivity cs)
QHash< QModelIndex, Mapping * >::const_iterator create_mapping(const QModelIndex &source_parent) const
bool can_create_mapping(const QModelIndex &source_parent) const
void invalidate()
Invalidates the current sorting and filtering.
void _q_sourceRowsRemoved(const QModelIndex &source_parent, int start, int end)
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
QModelIndex buddy(const QModelIndex &index) const
Reimplemented Function
bool isEmpty() const
Returns true if the vector has size 0; otherwise returns false.
Definition: qvector.h:139
bool canFetchMore(const QModelIndex &parent) const
Reimplemented Function
QTime toTime() const
Returns the variant as a QTime if the variant has type() Time , DateTime , or String ; otherwise retu...
Definition: qvariant.cpp:2330
void reserve(int size)
Attempts to allocate memory for at least size elements.
Definition: qvector.h:339
int columnCount(const QModelIndex &parent=QModelIndex()) const
Reimplemented Function
QHash< QModelIndex, Mapping * >::const_iterator map_iter
T value() const
Returns the stored value converted to the template type T.
Definition: qvariant.h:332
static const KeyPair *const end
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
This signal is emitted just before rows are removed from the model.
void setDynamicSortFilter(bool enable)
Orientation
Definition: qnamespace.h:174
QChar toChar() const
Returns the variant as a QChar if the variant has type() Char , Int , or UInt ; otherwise returns an ...
Definition: qvariant.cpp:2579
Qt::SortOrder sortOrder() const
the order currently used for sorting
Q_CORE_EXPORT QTextStream & left(QTextStream &s)
void rowsRemoved(const QModelIndex &parent, int first, int last)
This signal is emitted after rows have been removed from the model.
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end)
Definition: qalgorithms.h:319
QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection) const
Reimplemented Function
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
void columnsRemoved(const QModelIndex &parent, int first, int last)
This signal is emitted after columns have been removed from the model.
void filterChanged()
This function is obsolete.
void beginResetModel()
Begins a model reset operation.
#define INT_MAX
int filterKeyColumn() const
void source_items_about_to_be_removed(const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
Handles source model items removal (columnsAboutToBeRemoved(), rowsAboutToBeRemoved()).
int column() const
Returns the column this model index refers to.
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
Returns the model index in the QSortFilterProxyModel given the sourceIndex from the source model...
void remove_from_mapping(const QModelIndex &source_parent)
void reserve(int size)
Definition: qset.h:241
void insert_source_items(QVector< int > &source_to_proxy, QVector< int > &proxy_to_source, const QVector< int > &source_items, const QModelIndex &source_parent, Qt::Orientation orient, bool emit_signal=true)
Given source-to-proxy mapping source_to_proxy and proxy-to-source mapping proxy_to_source, inserts the given source_items into this proxy model.