summaryrefslogtreecommitdiffstats
path: root/src/gui/itemviews
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/itemviews')
-rw-r--r--src/gui/itemviews/qabstractitemview.cpp32
-rw-r--r--src/gui/itemviews/qabstractitemview_p.h2
-rw-r--r--src/gui/itemviews/qdirmodel.cpp11
-rw-r--r--src/gui/itemviews/qfileiconprovider.cpp14
-rw-r--r--src/gui/itemviews/qheaderview.cpp39
-rw-r--r--src/gui/itemviews/qheaderview_p.h9
-rw-r--r--src/gui/itemviews/qlistview.cpp28
-rw-r--r--src/gui/itemviews/qsortfilterproxymodel.cpp51
-rw-r--r--src/gui/itemviews/qtableview.cpp333
-rw-r--r--src/gui/itemviews/qtableview_p.h98
-rw-r--r--src/gui/itemviews/qtreeview.cpp46
11 files changed, 395 insertions, 268 deletions
diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp
index 83e05b4..90c38ca 100644
--- a/src/gui/itemviews/qabstractitemview.cpp
+++ b/src/gui/itemviews/qabstractitemview.cpp
@@ -1426,10 +1426,10 @@ bool QAbstractItemView::viewportEvent(QEvent *event)
case QEvent::HoverEnter: {
QHoverEvent *he = static_cast<QHoverEvent*>(event);
d->hover = indexAt(he->pos());
- d->viewport->update(visualRect(d->hover));
+ update(d->hover);
break; }
case QEvent::HoverLeave: {
- d->viewport->update(visualRect(d->hover)); // update old
+ update(d->hover); // update old
d->hover = QModelIndex();
break; }
case QEvent::HoverMove: {
@@ -1642,7 +1642,7 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event)
if (d->isIndexValid(index)
&& d->isIndexEnabled(index)
&& d->sendDelegateEvent(index, event))
- d->viewport->update(visualRect(index));
+ update(index);
return;
}
@@ -2165,11 +2165,12 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event)
}
#endif
bool modified = (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier));
- if (!event->text().isEmpty() && !modified) {
- if (!edit(currentIndex(), AnyKeyPressed, event))
- keyboardSearch(event->text());
+ if (!event->text().isEmpty() && !modified && !edit(currentIndex(), AnyKeyPressed, event)) {
+ keyboardSearch(event->text());
+ event->accept();
+ } else {
+ event->ignore();
}
- event->ignore();
break; }
}
}
@@ -2325,7 +2326,7 @@ bool QAbstractItemView::edit(const QModelIndex &index, EditTrigger trigger, QEve
}
if (d->sendDelegateEvent(index, event)) {
- d->viewport->update(visualRect(index));
+ update(index);
return true;
}
@@ -2844,9 +2845,9 @@ void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget
d->persistent.insert(widget);
d->addEditor(index, widget, true);
widget->show();
+ dataChanged(index, index); // update the geometry
if (!d->delayedPendingLayout)
widget->setGeometry(visualRect(index));
- dataChanged(index, index); // update the geometry
}
}
@@ -2926,7 +2927,7 @@ void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelInde
}
if (isVisible() && !d->delayedPendingLayout) {
// otherwise the items will be update later anyway
- d->viewport->update(visualRect(topLeft));
+ update(topLeft);
}
return;
}
@@ -3131,9 +3132,7 @@ void QAbstractItemView::selectionChanged(const QItemSelection &selected,
{
Q_D(QAbstractItemView);
if (isVisible() && updatesEnabled()) {
- d->setDirtyRegion(visualRegionForSelection(deselected));
- d->setDirtyRegion(visualRegionForSelection(selected));
- d->updateDirtyRegion();
+ d->viewport->update(visualRegionForSelection(deselected) | visualRegionForSelection(selected));
}
}
@@ -3161,16 +3160,15 @@ void QAbstractItemView::currentChanged(const QModelIndex &current, const QModelI
closeEditor(editor, QAbstractItemDelegate::NoHint);
}
if (isVisible()) {
- d->setDirtyRegion(visualRect(previous));
- d->updateDirtyRegion();
+ update(previous);
}
}
+
if (current.isValid() && !d->autoScrollTimer.isActive()) {
if (isVisible()) {
if (d->autoScroll)
scrollTo(current);
- d->setDirtyRegion(visualRect(current));
- d->updateDirtyRegion();
+ update(current);
edit(current, CurrentChanged, 0);
if (current.row() == (d->model->rowCount(d->root) - 1))
d->_q_fetchMore();
diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h
index 16bd1ab..139d0b7 100644
--- a/src/gui/itemviews/qabstractitemview_p.h
+++ b/src/gui/itemviews/qabstractitemview_p.h
@@ -99,7 +99,7 @@ public:
QVariant data(const QModelIndex &, int) const { return QVariant(); }
};
-class Q_GUI_EXPORT QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate
+class QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate
{
Q_DECLARE_PUBLIC(QAbstractItemView)
diff --git a/src/gui/itemviews/qdirmodel.cpp b/src/gui/itemviews/qdirmodel.cpp
index 7da7c7a..65e3032 100644
--- a/src/gui/itemviews/qdirmodel.cpp
+++ b/src/gui/itemviews/qdirmodel.cpp
@@ -44,6 +44,7 @@
#ifndef QT_NO_DIRMODEL
#include <qstack.h>
#include <qfile.h>
+#include <qfilesystemmodel.h>
#include <qurl.h>
#include <qmime.h>
#include <qpair.h>
@@ -1335,14 +1336,14 @@ QString QDirModelPrivate::size(const QModelIndex &index) const
const quint64 tb = 1024 * gb;
quint64 bytes = n->info.size();
if (bytes >= tb)
- return QLocale().toString(bytes / tb) + QString::fromLatin1(" TB");
+ return QFileSystemModel::tr("%1 TB").arg(QLocale().toString(qreal(bytes) / tb, 'f', 3));
if (bytes >= gb)
- return QLocale().toString(bytes / gb) + QString::fromLatin1(" GB");
+ return QFileSystemModel::tr("%1 GB").arg(QLocale().toString(qreal(bytes) / gb, 'f', 2));
if (bytes >= mb)
- return QLocale().toString(bytes / mb) + QString::fromLatin1(" MB");
+ return QFileSystemModel::tr("%1 MB").arg(QLocale().toString(qreal(bytes) / mb, 'f', 1));
if (bytes >= kb)
- return QLocale().toString(bytes / kb) + QString::fromLatin1(" KB");
- return QLocale().toString(bytes) + QString::fromLatin1(" bytes");
+ return QFileSystemModel::tr("%1 KB").arg(QLocale().toString(bytes / kb));
+ return QFileSystemModel::tr("%1 bytes").arg(QLocale().toString(bytes));
}
QString QDirModelPrivate::type(const QModelIndex &index) const
diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp
index ac62551..054f4cf 100644
--- a/src/gui/itemviews/qfileiconprovider.cpp
+++ b/src/gui/itemviews/qfileiconprovider.cpp
@@ -356,7 +356,7 @@ QIcon QFileIconProvider::icon(const QFileInfo &info) const
return icon;
#endif
if (info.isRoot())
-#if defined (Q_WS_WIN) && !defined(Q_OS_WINCE)
+#if defined (Q_WS_WIN) && !defined(Q_WS_WINCE)
{
uint type = DRIVE_UNKNOWN;
QT_WA({ type = GetDriveTypeW((wchar_t *)info.absoluteFilePath().utf16()); },
@@ -416,26 +416,22 @@ QString QFileIconProvider::type(const QFileInfo &info) const
}
if (info.isDir())
- return QApplication::translate("QFileDialog",
#ifdef Q_WS_WIN
- "File Folder", "Match Windows Explorer"
+ return QApplication::translate("QFileDialog", "File Folder", "Match Windows Explorer");
#else
- "Folder", "All other platforms"
+ return QApplication::translate("QFileDialog", "Folder", "All other platforms");
#endif
- );
// Windows - "File Folder"
// OS X - "Folder"
// Konqueror - "Folder"
// Nautilus - "folder"
if (info.isSymLink())
- return QApplication::translate("QFileDialog",
#ifdef Q_OS_MAC
- "Alias", "Mac OS X Finder"
+ return QApplication::translate("QFileDialog", "Alias", "Mac OS X Finder");
#else
- "Shortcut", "All other platforms"
+ return QApplication::translate("QFileDialog", "Shortcut", "All other platforms");
#endif
- );
// OS X - "Alias"
// Windows - "Shortcut"
// Konqueror - "Folder" or "TXT File" i.e. what it is pointing to
diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp
index dc63b25..6238df5 100644
--- a/src/gui/itemviews/qheaderview.cpp
+++ b/src/gui/itemviews/qheaderview.cpp
@@ -1195,7 +1195,7 @@ QHeaderView::ResizeMode QHeaderView::resizeMode(int logicalIndex) const
Q_D(const QHeaderView);
int visual = visualIndex(logicalIndex);
Q_ASSERT(visual != -1);
- return d->visualIndexResizeMode(visual);
+ return d->headerSectionResizeMode(visual);
}
/*!
@@ -1234,7 +1234,7 @@ void QHeaderView::setSortIndicatorShown(bool show)
if (sortIndicatorSection() < 0 || sortIndicatorSection() > count())
return;
- if (d->visualIndexResizeMode(sortIndicatorSection()) == ResizeToContents)
+ if (d->headerSectionResizeMode(sortIndicatorSection()) == ResizeToContents)
resizeSections();
d->viewport->update();
@@ -1967,20 +1967,19 @@ void QHeaderView::currentChanged(const QModelIndex &current, const QModelIndex &
if (d->orientation == Qt::Horizontal && current.column() != old.column()) {
if (old.isValid() && old.parent() == d->root)
- d->setDirtyRegion(QRect(sectionViewportPosition(old.column()), 0,
+ d->viewport->update(QRect(sectionViewportPosition(old.column()), 0,
sectionSize(old.column()), d->viewport->height()));
if (current.isValid() && current.parent() == d->root)
- d->setDirtyRegion(QRect(sectionViewportPosition(current.column()), 0,
+ d->viewport->update(QRect(sectionViewportPosition(current.column()), 0,
sectionSize(current.column()), d->viewport->height()));
} else if (d->orientation == Qt::Vertical && current.row() != old.row()) {
if (old.isValid() && old.parent() == d->root)
- d->setDirtyRegion(QRect(0, sectionViewportPosition(old.row()),
+ d->viewport->update(QRect(0, sectionViewportPosition(old.row()),
d->viewport->width(), sectionSize(old.row())));
if (current.isValid() && current.parent() == d->root)
- d->setDirtyRegion(QRect(0, sectionViewportPosition(current.row()),
+ d->viewport->update(QRect(0, sectionViewportPosition(current.row()),
d->viewport->width(), sectionSize(current.row())));
}
- d->updateDirtyRegion();
}
@@ -2934,22 +2933,25 @@ int QHeaderViewPrivate::lastVisibleVisualIndex() const
void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode)
{
Q_Q(QHeaderView);
+ //stop the timer in case it is delayed
+ delayedResize.stop();
executePostedLayout();
if (sectionCount == 0)
return;
+
+ if (resizeRecursionBlock)
+ return;
+ resizeRecursionBlock = true;
+
invalidateCachedSizeHint();
+ const int lastVisibleSection = lastVisibleVisualIndex();
+
// find stretchLastSection if we have it
int stretchSection = -1;
- if (stretchLastSection && !useGlobalMode) {
- for (int i = sectionCount - 1; i >= 0; --i) {
- if (!isVisualIndexHidden(i)) {
- stretchSection = i;
- break;
- }
- }
- }
+ if (stretchLastSection && !useGlobalMode)
+ stretchSection = lastVisibleVisualIndex();
// count up the number of strected sections and how much space left for them
int lengthToStrech = (orientation == Qt::Horizontal ? viewport->width() : viewport->height());
@@ -2963,7 +2965,7 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool
if (useGlobalMode && (i != stretchSection))
resizeMode = globalMode;
else
- resizeMode = (i == stretchSection ? QHeaderView::Stretch : visualIndexResizeMode(i));
+ resizeMode = (i == stretchSection ? QHeaderView::Stretch : headerSectionResizeMode(i));
if (resizeMode == QHeaderView::Stretch) {
++numberOfStretchedSections;
@@ -2995,7 +2997,6 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool
int spanStartSection = 0;
int previousSectionLength = 0;
- const int lastVisibleSection = lastVisibleVisualIndex();
QHeaderView::ResizeMode previousSectionResizeMode = QHeaderView::Interactive;
@@ -3014,7 +3015,7 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool
else
resizeMode = (i == stretchSection
? QHeaderView::Stretch
- : visualIndexResizeMode(i));
+ : newSectionResizeMode);
if (resizeMode == QHeaderView::Stretch && stretchSectionLength != -1) {
if (i == lastVisibleSection)
newSectionLength = qMax(stretchSectionLength, lastSectionSize);
@@ -3051,7 +3052,7 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool
(sectionCount - spanStartSection) * previousSectionLength,
previousSectionResizeMode);
//Q_ASSERT(headerLength() == length);
-
+ resizeRecursionBlock = false;
viewport->update();
}
diff --git a/src/gui/itemviews/qheaderview_p.h b/src/gui/itemviews/qheaderview_p.h
index 2889f08..cfb1c3e 100644
--- a/src/gui/itemviews/qheaderview_p.h
+++ b/src/gui/itemviews/qheaderview_p.h
@@ -90,6 +90,7 @@ public:
highlightSelected(false),
stretchLastSection(false),
cascadingResizing(false),
+ resizeRecursionBlock(false),
stretchSections(0),
contentsSections(0),
minimumSectionSize(-1),
@@ -169,10 +170,6 @@ public:
if (!sectionHidden.isEmpty()) sectionHidden.setBit(visual, hidden);
}
- inline QHeaderView::ResizeMode visualIndexResizeMode(int visual) const {
- return headerSectionResizeMode(visual);
- }
-
inline bool hasAutoResizeSections() const {
return stretchSections || stretchLastSection || contentsSections;
}
@@ -210,7 +207,7 @@ public:
}
inline bool sectionIsCascadable(int visual) const {
- return visualIndexResizeMode(visual) == QHeaderView::Interactive;
+ return headerSectionResizeMode(visual) == QHeaderView::Interactive;
}
inline int modelSectionCount() const {
@@ -230,7 +227,6 @@ public:
inline void executePostedResize() const {
if (delayedResize.isActive() && state == NoState) {
- delayedResize.stop();
const_cast<QHeaderView*>(q_func())->resizeSections();
}
}
@@ -274,6 +270,7 @@ public:
bool highlightSelected;
bool stretchLastSection;
bool cascadingResizing;
+ bool resizeRecursionBlock;
int stretchSections;
int contentsSections;
int defaultSectionSize;
diff --git a/src/gui/itemviews/qlistview.cpp b/src/gui/itemviews/qlistview.cpp
index 48f53a0..1071c1d 100644
--- a/src/gui/itemviews/qlistview.cpp
+++ b/src/gui/itemviews/qlistview.cpp
@@ -588,7 +588,7 @@ void QListView::scrollTo(const QModelIndex &index, ScrollHint hint)
const QRect rect = visualRect(index);
if (hint == EnsureVisible && d->viewport->rect().contains(rect)) {
- d->setDirtyRegion(rect);
+ d->viewport->update(rect);
return;
}
@@ -755,7 +755,7 @@ void QListView::scrollContentsBy(int dx, int dy)
// update the dragged items
if (d->viewMode == IconMode) // ### move to dynamic class
if (!d->dynamicListView->draggedItems.isEmpty())
- d->setDirtyRegion(d->dynamicListView->draggedItemsRect().translated(dx, dy));
+ d->viewport->update(d->dynamicListView->draggedItemsRect().translated(dx, dy));
}
/*!
@@ -835,7 +835,7 @@ void QListView::mouseMoveEvent(QMouseEvent *e)
&& d->selectionMode != NoSelection) {
QRect rect(d->pressedPosition, e->pos() + QPoint(horizontalOffset(), verticalOffset()));
rect = rect.normalized();
- d->setDirtyRegion(d->mapToViewport(rect.united(d->elasticBand), d->viewMode == QListView::ListMode));
+ d->viewport->update(d->mapToViewport(rect.united(d->elasticBand), d->viewMode == QListView::ListMode));
d->elasticBand = rect;
}
}
@@ -849,7 +849,7 @@ void QListView::mouseReleaseEvent(QMouseEvent *e)
QAbstractItemView::mouseReleaseEvent(e);
// #### move this implementation into a dynamic class
if (d->showElasticBand && d->elasticBand.isValid()) {
- d->setDirtyRegion(d->mapToViewport(d->elasticBand, d->viewMode == QListView::ListMode));
+ d->viewport->update(d->mapToViewport(d->elasticBand, d->viewMode == QListView::ListMode));
d->elasticBand = QRect();
}
}
@@ -914,11 +914,11 @@ void QListView::dragMoveEvent(QDragMoveEvent *e)
if (d->canDecode(e)) {
// get old dragged items rect
QRect itemsRect = d->dynamicListView->itemsRect(d->dynamicListView->draggedItems);
- d->setDirtyRegion(itemsRect.translated(d->dynamicListView->draggedItemsDelta()));
+ d->viewport->update(itemsRect.translated(d->dynamicListView->draggedItemsDelta()));
// update position
d->dynamicListView->draggedItemsPos = e->pos();
// get new items rect
- d->setDirtyRegion(itemsRect.translated(d->dynamicListView->draggedItemsDelta()));
+ d->viewport->update(itemsRect.translated(d->dynamicListView->draggedItemsDelta()));
// set the item under the cursor to current
QModelIndex index;
if (d->movement == Snap) {
@@ -1007,12 +1007,12 @@ void QListView::internalDrop(QDropEvent *event)
for (int i = 0; i < indexes.count(); ++i) {
QModelIndex index = indexes.at(i);
QRect rect = rectForIndex(index);
- d->setDirtyRegion(d->mapToViewport(rect, d->viewMode == QListView::ListMode));
+ d->viewport->update(d->mapToViewport(rect, d->viewMode == QListView::ListMode));
QPoint dest = rect.topLeft() + delta;
if (isRightToLeft())
dest.setX(d->flipX(dest.x()) - rect.width());
d->dynamicListView->moveItem(index.row(), dest);
- d->setDirtyRegion(visualRect(index));
+ update(index);
}
stopAutoScroll();
d->dynamicListView->draggedItems.clear();
@@ -1455,9 +1455,9 @@ void QListView::setPositionForIndex(const QPoint &position, const QModelIndex &i
if (index.row() >= d->dynamicListView->items.count())
return;
const QSize oldContents = d->contentsSize();
- d->setDirtyRegion(visualRect(index)); // update old position
+ update(index); // update old position
d->dynamicListView->moveItem(index.row(), position);
- d->setDirtyRegion(visualRect(index)); // update new position
+ update(index); // update new position
if (d->contentsSize() != oldContents)
updateGeometries(); // update the scroll bars
@@ -1608,6 +1608,10 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con
if (!selection.at(i).isValid())
continue;
QModelIndex parent = selection.at(i).topLeft().parent();
+ //we only display the children of the root in a listview
+ //we're not interested in the other model indexes
+ if (parent != d->root)
+ continue;
int t = selection.at(i).topLeft().row();
int b = selection.at(i).bottomRight().row();
if (d->viewMode == IconMode || d->isWrapping()) { // in non-static mode, we have to go through all selected items
@@ -1616,8 +1620,8 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con
} else { // in static mode, we can optimize a bit
while (t <= b && d->isHidden(t)) ++t;
while (b >= t && d->isHidden(b)) --b;
- const QModelIndex top = d->model->index(t, c, d->root);
- const QModelIndex bottom = d->model->index(b, c, d->root);
+ const QModelIndex top = d->model->index(t, c, parent);
+ const QModelIndex bottom = d->model->index(b, c, parent);
QRect rect(visualRect(top).topLeft(),
visualRect(bottom).bottomRight());
selectionRegion += QRegion(rect);
diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp
index 43feda8..56925b8 100644
--- a/src/gui/itemviews/qsortfilterproxymodel.cpp
+++ b/src/gui/itemviews/qsortfilterproxymodel.cpp
@@ -56,6 +56,15 @@ QT_BEGIN_NAMESPACE
typedef QList<QPair<QModelIndex, QPersistentModelIndex> > QModelIndexPairList;
+static inline QSet<int> qVectorToSet(const QVector<int> &vector)
+{
+ QSet<int> set;
+ set.reserve(vector.size());
+ for(int i=0; i < vector.size(); ++i)
+ set << vector.at(i);
+ return set;
+}
+
class QSortFilterProxyModelLessThan
{
public:
@@ -224,8 +233,8 @@ public:
QModelIndexPairList store_persistent_indexes();
void update_persistent_indexes(const QModelIndexPairList &source_indexes);
- void filter_changed();
- void handle_filter_changed(
+ void filter_changed(const QModelIndex &source_parent = QModelIndex());
+ QSet<int> handle_filter_changed(
QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
const QModelIndex &source_parent, Qt::Orientation orient);
@@ -937,27 +946,39 @@ void QSortFilterProxyModelPrivate::update_persistent_indexes(
q->changePersistentIndexList(from, to);
}
+
/*!
\internal
Updates the proxy model (adds/removes rows) based on the
new filter.
*/
-void QSortFilterProxyModelPrivate::filter_changed()
+void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_parent)
{
- QMap<QModelIndex, Mapping *>::const_iterator it;
- for (it = source_index_mapping.constBegin(); it != source_index_mapping.constEnd(); ++it) {
- QModelIndex source_parent = it.key();
- Mapping *m = it.value();
- handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical);
- handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal);
+ IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
+ if (it == source_index_mapping.constEnd())
+ return;
+ Mapping *m = it.value();
+ QSet<int> rows_removed = handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical);
+ QSet<int> columns_removed = handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal);
+ QVector<QModelIndex>::iterator it2 = m->mapped_children.end();
+ while (it2 != m->mapped_children.begin()) {
+ --it2;
+ const QModelIndex source_child_index = *it2;
+ if (rows_removed.contains(source_child_index.row()) || columns_removed.contains(source_child_index.column())) {
+ it2 = m->mapped_children.erase(it2);
+ remove_from_mapping(source_child_index);
+ } else {
+ filter_changed(source_child_index);
+ }
}
}
/*!
\internal
+ returns the removed items indexes
*/
-void QSortFilterProxyModelPrivate::handle_filter_changed(
+QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
const QModelIndex &source_parent, Qt::Orientation orient)
{
@@ -994,6 +1015,7 @@ void QSortFilterProxyModelPrivate::handle_filter_changed(
insert_source_items(source_to_proxy, proxy_to_source,
source_items_insert, source_parent, orient);
}
+ return qVectorToSet(source_items_remove);
}
void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &source_top_left,
@@ -1044,15 +1066,14 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
if (!source_rows_remove.isEmpty()) {
remove_source_items(m->proxy_rows, m->source_rows,
source_rows_remove, source_parent, Qt::Vertical);
- QSet<int> source_rows_remove_set = source_rows_remove.toList().toSet();
- QVector<QModelIndex>::iterator it = m->mapped_children.begin();
- while (it != m->mapped_children.end()) {
+ QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove);
+ QVector<QModelIndex>::iterator it = m->mapped_children.end();
+ while (it != m->mapped_children.begin()) {
+ --it;
const QModelIndex source_child_index = *it;
if (source_rows_remove_set.contains(source_child_index.row())) {
it = m->mapped_children.erase(it);
remove_from_mapping(source_child_index);
- } else {
- ++it;
}
}
}
diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp
index 2902768..757ecf2 100644
--- a/src/gui/itemviews/qtableview.cpp
+++ b/src/gui/itemviews/qtableview.cpp
@@ -59,6 +59,138 @@
QT_BEGIN_NAMESPACE
+/** \internal
+ Add a span to the collection. the collection takes the ownership.
+ */
+void QSpanCollection::addSpan(QSpanCollection::Span *span)
+{
+ spans.append(span);
+ Index::iterator it_y = index.lowerBound(-span->top());
+ if (it_y == index.end() || it_y.key() != -span->top()) {
+ //there is no spans that starts with the row in the index, so create a sublist for it.
+ SubIndex sub_index;
+ if (it_y != index.end()) {
+ //the previouslist is the list of spans that sarts _before_ the row of the span.
+ // and which may intersect this row.
+ const SubIndex previousList = it_y.value();
+ foreach(Span *s, previousList) {
+ //If a subspans intersect the row, we need to split it into subspans
+ if(s->bottom() >= span->top())
+ sub_index.insert(-s->left(), s);
+ }
+ }
+ it_y = index.insert(-span->top(), sub_index);
+ //we will insert span to *it_y in the later loop
+ }
+
+ //insert the span as supspan in all the lists that intesects the span
+ while(-it_y.key() <= span->bottom()) {
+ (*it_y).insert(-span->left(), span);
+ if(it_y == index.begin())
+ break;
+ --it_y;
+ }
+}
+
+
+/** \internal
+* Has to be called after the height and width of a span is changed.
+*
+* old_height is the height before the change
+*
+* if the size of the span is now 0x0 the span will be deleted.
+*/
+void QSpanCollection::updateSpan(QSpanCollection::Span *span, int old_height)
+{
+ if (old_height < span->height()) {
+ //add the span as subspan in all the lists that intersect the new covered columns
+ Index::iterator it_y = index.lowerBound(-(span->top() + old_height - 1));
+ Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list
+ while (-it_y.key() <= span->bottom()) {
+ (*it_y).insert(-span->left(), span);
+ if(it_y == index.begin())
+ break;
+ --it_y;
+ }
+ } else if (old_height > span->height()) {
+ //remove the span from all the subspans lists that intersect the columns not covered anymore
+ Index::iterator it_y = index.lowerBound(-span->bottom());
+ Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list
+ while (-it_y.key() <= span->top() + old_height -1) {
+ if(-it_y.key() != span->bottom()) {
+ (*it_y).remove(-span->left());
+ if (it_y->isEmpty()) {
+ it_y = index.erase(it_y) - 1;
+ }
+ }
+ if(it_y == index.begin())
+ break;
+ --it_y;
+ }
+ }
+
+ if (span->width() == 0 && span->height() == 0) {
+ spans.removeOne(span);
+ delete span;
+ }
+}
+
+/** \internal
+ * \return a spans that spans over cell x,y (column,row) or 0 if there is none.
+ */
+QSpanCollection::Span *QSpanCollection::spanAt(int x, int y) const
+{
+ Index::const_iterator it_y = index.lowerBound(-y);
+ if (it_y == index.end())
+ return 0;
+ SubIndex::const_iterator it_x = (*it_y).lowerBound(-x);
+ if (it_x == (*it_y).end())
+ return 0;
+ Span *span = *it_x;
+ if (span->right() >= x && span->bottom() >= y)
+ return span;
+ return 0;
+}
+
+
+/** \internal
+* remove and deletes all spans inside the collection
+*/
+void QSpanCollection::clear()
+{
+ qDeleteAll(spans);
+ index.clear();
+ spans.clear();
+}
+
+/** \internal
+ * return a list to all the spans that spans over cells in the given rectangle
+ */
+QList<QSpanCollection::Span *> QSpanCollection::spansInRect(int x, int y, int w, int h) const
+{
+ QSet<Span *> list;
+ Index::const_iterator it_y = index.lowerBound(-y);
+ if(it_y == index.end())
+ --it_y;
+ while(-it_y.key() <= y + h) {
+ SubIndex::const_iterator it_x = (*it_y).lowerBound(-x);
+ if (it_x == (*it_y).end())
+ --it_x;
+ while(-it_x.key() <= x + w) {
+ Span *s = *it_x;
+ if (s->bottom() >= y && s->right() >= x)
+ list << s;
+ if (it_x == (*it_y).begin())
+ break;
+ --it_x;
+ }
+ if(it_y == index.begin())
+ break;
+ --it_y;
+ }
+ return list.toList();
+}
+
class QTableCornerButton : public QAbstractButton
{
Q_OBJECT
@@ -149,35 +281,40 @@ void QTableViewPrivate::trimHiddenSelections(QItemSelectionRange *range) const
*/
void QTableViewPrivate::setSpan(int row, int column, int rowSpan, int columnSpan)
{
- if (row < 0 || column < 0 || rowSpan < 0 || columnSpan < 0)
+ if (row < 0 || column < 0 || rowSpan <= 0 || columnSpan <= 0) {
+ qWarning() << "QTableView::setSpan: invalid span given: (" << row << "," << column << "," << rowSpan << "," << columnSpan << ")";
return;
- Span sp(row, column, rowSpan, columnSpan);
- QList<Span>::iterator it;
- for (it = spans.begin(); it != spans.end(); ++it) {
- if (((*it).top() == sp.top()) && ((*it).left() == sp.left())) {
- if ((sp.height() == 1) && (sp.width() == 1))
- spans.erase(it); // "Implicit" span (1, 1), no need to store it
- else
- *it = sp; // Replace
+ }
+ QSpanCollection::Span *sp = spans.spanAt(column, row);
+ if (sp) {
+ if (sp->top() != row || sp->left() != column) {
+ qWarning() << "QTableView::setSpan: span cannot overlap";
return;
}
+ if (rowSpan == 1 && columnSpan == 1) {
+ rowSpan = columnSpan = 0;
+ }
+ const int old_height = sp->height();
+ sp->m_bottom = row + rowSpan - 1;
+ sp->m_right = column + columnSpan - 1;
+ spans.updateSpan(sp, old_height);
+ return;
}
- spans.append(sp);
+ sp = new QSpanCollection::Span(row, column, rowSpan, columnSpan);
+ spans.addSpan(sp);
}
/*!
\internal
Gets the span information for the cell at (\a row, \a column).
*/
-QTableViewPrivate::Span QTableViewPrivate::span(int row, int column) const
+QSpanCollection::Span QTableViewPrivate::span(int row, int column) const
{
- QList<Span>::const_iterator it;
- for (it = spans.constBegin(); it != spans.constEnd(); ++it) {
- Span span = *it;
- if (isInSpan(row, column, span))
- return span;
- }
- return Span(row, column, 1, 1);
+ QSpanCollection::Span *sp = spans.spanAt(column, row);
+ if (sp)
+ return *sp;
+
+ return QSpanCollection::Span(row, column, 1, 1);
}
/*!
@@ -233,67 +370,9 @@ bool QTableViewPrivate::spanContainsSection(const QHeaderView *header, int logic
/*!
\internal
- Returns true if one or more spans intersect column \a column.
-*/
-bool QTableViewPrivate::spansIntersectColumn(int column) const
-{
- QList<Span>::const_iterator it;
- for (it = spans.constBegin(); it != spans.constEnd(); ++it) {
- Span span = *it;
- if (spanContainsColumn(column, span.left(), span.width()))
- return true;
- }
- return false;
-}
-
-/*!
- \internal
- Returns true if one or more spans intersect row \a row.
-*/
-bool QTableViewPrivate::spansIntersectRow(int row) const
-{
- QList<Span>::const_iterator it;
- for (it = spans.constBegin(); it != spans.constEnd(); ++it) {
- Span span = *it;
- if (spanContainsRow(row, span.top(), span.height()))
- return true;
- }
- return false;
-}
-
-/*!
- \internal
- Returns true if one or more spans intersect one or more columns.
-*/
-bool QTableViewPrivate::spansIntersectColumns(const QList<int> &columns) const
-{
- QList<int>::const_iterator it;
- for (it = columns.constBegin(); it != columns.constEnd(); ++it) {
- if (spansIntersectColumn(*it))
- return true;
- }
- return false;
-}
-
-/*!
- \internal
- Returns true if one or more spans intersect one or more rows.
-*/
-bool QTableViewPrivate::spansIntersectRows(const QList<int> &rows) const
-{
- QList<int>::const_iterator it;
- for (it = rows.constBegin(); it != rows.constEnd(); ++it) {
- if (spansIntersectRow(*it))
- return true;
- }
- return false;
-}
-
-/*!
- \internal
Returns the visual rect for the given \a span.
*/
-QRect QTableViewPrivate::visualSpanRect(const Span &span) const
+QRect QTableViewPrivate::visualSpanRect(const QSpanCollection::Span &span) const
{
Q_Q(const QTableView);
// vertical
@@ -319,42 +398,54 @@ QRect QTableViewPrivate::visualSpanRect(const Span &span) const
preparation for the main drawing loop.
\a drawn is a QBitArray of visualRowCountxvisualCoulumnCount which say if particular cell has been drawn
*/
-void QTableViewPrivate::drawAndClipSpans(const QRect &area, QPainter *painter,
+void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter,
const QStyleOptionViewItemV4 &option, QBitArray *drawn,
int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn)
{
bool alternateBase = false;
QRegion region = viewport->rect();
- QList<Span>::const_iterator it;
- for (it = spans.constBegin(); it != spans.constEnd(); ++it) {
- Span span = *it;
+ QList<QSpanCollection::Span *> visibleSpans;
+ bool sectionMoved = verticalHeader->sectionsMoved() || horizontalHeader->sectionsMoved();
+
+ if (!sectionMoved) {
+ visibleSpans = spans.spansInRect(logicalColumn(firstVisualColumn), logicalRow(firstVisualRow),
+ lastVisualColumn - firstVisualColumn + 1, lastVisualRow - firstVisualRow + 1);
+ } else {
+ QSet<QSpanCollection::Span *> set;
+ for(int x = firstVisualColumn; x <= lastVisualColumn; x++)
+ for(int y = firstVisualRow; y <= lastVisualRow; y++)
+ set.insert(spans.spanAt(x,y));
+ set.remove(0);
+ visibleSpans = set.toList();
+ }
- int row = span.top();
- int col = span.left();
+ foreach (QSpanCollection::Span *span, visibleSpans) {
+ int row = span->top();
+ int col = span->left();
if (isHidden(row, col))
continue;
QModelIndex index = model->index(row, col, root);
if (!index.isValid())
continue;
- QRect rect = visualSpanRect(span);
+ QRect rect = visualSpanRect(*span);
rect.translate(scrollDelayOffset);
- if (!rect.intersects(area))
+ if (!area.intersects(rect))
continue;
QStyleOptionViewItemV4 opt = option;
opt.rect = rect;
- alternateBase = alternatingColors && (span.top() & 1);
+ alternateBase = alternatingColors && (span->top() & 1);
if (alternateBase)
opt.features |= QStyleOptionViewItemV2::Alternate;
else
opt.features &= ~QStyleOptionViewItemV2::Alternate;
drawCell(painter, opt, index);
region -= rect;
- for (int r = span.top(); r <= span.bottom(); ++r) {
+ for (int r = span->top(); r <= span->bottom(); ++r) {
const int vr = visualRow(r);
if (vr < firstVisualRow || vr > lastVisualRow)
continue;
- for (int c = span.left(); c <= span.right(); ++c) {
+ for (int c = span->left(); c <= span->right(); ++c) {
const int vc = visualColumn(c);
if (vc < firstVisualColumn || vc > lastVisualColumn)
continue;
@@ -753,7 +844,8 @@ void QTableView::paintEvent(QPaintEvent *event)
uint x = horizontalHeader->length() - horizontalHeader->offset() - (rightToLeft ? 0 : 1);
uint y = verticalHeader->length() - verticalHeader->offset() - 1;
- QVector<QRect> rects = event->region().rects();
+ const QRegion region = event->region().translated(offset);
+ const QVector<QRect> rects = region.rects();
//firstVisualRow is the visual index of the first visible row. lastVisualRow is the visual index of the last visible Row.
//same goes for ...VisualColumn
@@ -773,9 +865,13 @@ void QTableView::paintEvent(QPaintEvent *event)
QBitArray drawn((lastVisualRow - firstVisualRow + 1) * (lastVisualColumn - firstVisualColumn + 1));
+ if (d->hasSpans()) {
+ d->drawAndClipSpans(region, &painter, option, &drawn,
+ firstVisualRow, lastVisualRow, firstVisualColumn, lastVisualColumn);
+ }
+
for (int i = 0; i < rects.size(); ++i) {
QRect dirtyArea = rects.at(i);
- dirtyArea.translate(offset);
dirtyArea.setBottom(qMin(dirtyArea.bottom(), int(y)));
if (rightToLeft) {
dirtyArea.setLeft(qMax(dirtyArea.left(), d->viewport->width() - int(x)));
@@ -783,10 +879,6 @@ void QTableView::paintEvent(QPaintEvent *event)
dirtyArea.setRight(qMin(dirtyArea.right(), int(x)));
}
- if (d->hasSpans())
- d->drawAndClipSpans(dirtyArea, &painter, option, &drawn,
- firstVisualRow, lastVisualRow, firstVisualColumn, lastVisualColumn);
-
// get the horizontal start and end visual sections
int left = horizontalHeader->visualIndexAt(dirtyArea.left());
int right = horizontalHeader->visualIndexAt(dirtyArea.right());
@@ -913,7 +1005,7 @@ QModelIndex QTableView::indexAt(const QPoint &pos) const
int c = columnAt(pos.x());
if (r >= 0 && c >= 0) {
if (d->hasSpans()) {
- QTableViewPrivate::Span span = d->span(r, c);
+ QSpanCollection::Span span = d->span(r, c);
r = span.top();
c = span.left();
}
@@ -1011,14 +1103,14 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
--visualRow;
if (d->hasSpans()) {
int row = d->logicalRow(visualRow);
- QTableViewPrivate::Span span = d->span(row, current.column());
+ QSpanCollection::Span span = d->span(row, current.column());
visualRow = d->visualRow(span.top());
visualColumn = d->visualColumn(span.left());
}
break;
case MoveDown:
if (d->hasSpans()) {
- QTableViewPrivate::Span span = d->span(current.row(), current.column());
+ QSpanCollection::Span span = d->span(current.row(), current.column());
visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
}
#ifdef QT_KEYPAD_NAVIGATION
@@ -1030,7 +1122,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
++visualRow;
if (d->hasSpans()) {
int row = d->logicalRow(visualRow);
- QTableViewPrivate::Span span = d->span(row, current.column());
+ QSpanCollection::Span span = d->span(row, current.column());
visualColumn = d->visualColumn(span.left());
}
break;
@@ -1058,7 +1150,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
--visualColumn;
if (d->hasSpans()) {
int column = d->logicalColumn(visualColumn);
- QTableViewPrivate::Span span = d->span(current.row(), column);
+ QSpanCollection::Span span = d->span(current.row(), column);
visualRow = d->visualRow(span.top());
visualColumn = d->visualColumn(span.left());
}
@@ -1078,7 +1170,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
} // else MoveRight
case MoveRight:
if (d->hasSpans()) {
- QTableViewPrivate::Span span = d->span(current.row(), current.column());
+ QSpanCollection::Span span = d->span(current.row(), current.column());
visualColumn = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
}
++visualColumn;
@@ -1086,7 +1178,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
++visualColumn;
if (d->hasSpans()) {
int column = d->logicalColumn(visualColumn);
- QTableViewPrivate::Span span = d->span(current.row(), column);
+ QSpanCollection::Span span = d->span(current.row(), column);
visualRow = d->visualRow(span.top());
}
break;
@@ -1161,9 +1253,8 @@ void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF
int right = qMax(d->visualColumn(tl.column()), d->visualColumn(br.column()));
do {
expanded = false;
- QList<QTableViewPrivate::Span>::const_iterator it;
- for (it = d->spans.constBegin(); it != d->spans.constEnd(); ++it) {
- QTableViewPrivate::Span span = *it;
+ foreach (QSpanCollection::Span *it, d->spans.spans) {
+ const QSpanCollection::Span &span = *it;
int t = d->visualRow(span.top());
int l = d->visualColumn(span.left());
int b = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
@@ -1253,7 +1344,7 @@ QRegion QTableView::visualRegionForSelection(const QItemSelection &selection) co
bool verticalMoved = verticalHeader()->sectionsMoved();
bool horizontalMoved = horizontalHeader()->sectionsMoved();
- if ((verticalMoved && horizontalMoved) || d->hasSpans()) {
+ if ((verticalMoved && horizontalMoved) || (d->hasSpans() && (verticalMoved || horizontalMoved))) {
for (int i = 0; i < selection.count(); ++i) {
QItemSelectionRange range = selection.at(i);
if (range.parent() != d->root || !range.isValid())
@@ -1296,9 +1387,19 @@ QRegion QTableView::visualRegionForSelection(const QItemSelection &selection) co
if (range.parent() != d->root || !range.isValid())
continue;
d->trimHiddenSelections(&range);
- QRect tl = visualRect(range.topLeft());
- QRect br = visualRect(range.bottomRight());
- selectionRegion += QRegion(tl|br);
+
+ const int rtop = rowViewportPosition(range.top());
+ const int rbottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom());
+ const int rleft = columnViewportPosition(range.left());
+ const int rright = columnViewportPosition(range.right()) + columnWidth(range.right());
+ selectionRegion += QRect(QPoint(rleft, rtop), QPoint(rright, rbottom));
+ if (d->hasSpans()) {
+ foreach (QSpanCollection::Span *s,
+ d->spans.spansInRect(range.left(), range.top(), range.width(), range.height())) {
+ if (range.contains(s->top(), s->left(), range.parent()))
+ selectionRegion += d->visualSpanRect(*s);
+ }
+ }
}
}
@@ -1874,7 +1975,7 @@ QRect QTableView::visualRect(const QModelIndex &index) const
d->executePostedLayout();
if (d->hasSpans()) {
- QTableViewPrivate::Span span = d->span(index.row(), index.column());
+ QSpanCollection::Span span = d->span(index.row(), index.column());
return d->visualSpanRect(span);
}
@@ -1903,7 +2004,7 @@ void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint)
|| isIndexHidden(index))
return;
- QTableViewPrivate::Span span;
+ QSpanCollection::Span span;
if (d->hasSpans())
span = d->span(index.row(), index.column());
@@ -2010,7 +2111,7 @@ void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint)
}
}
- d->setDirtyRegion(visualRect(index));
+ update(index);
}
/*!
@@ -2058,7 +2159,7 @@ void QTableView::timerEvent(QTimerEvent *event)
QRect rect;
int viewportHeight = d->viewport->height();
int viewportWidth = d->viewport->width();
- if (d->hasSpans() && d->spansIntersectColumns(d->columnsToUpdate)) {
+ if (d->hasSpans()) {
rect = QRect(0, 0, viewportWidth, viewportHeight);
} else {
for (int i = d->columnsToUpdate.size()-1; i >= 0; --i) {
@@ -2083,7 +2184,7 @@ void QTableView::timerEvent(QTimerEvent *event)
int viewportHeight = d->viewport->height();
int viewportWidth = d->viewport->width();
int top;
- if (d->hasSpans() && d->spansIntersectRows(d->rowsToUpdate)) {
+ if (d->hasSpans()) {
top = 0;
} else {
top = viewportHeight;
@@ -2114,7 +2215,7 @@ void QTableView::rowMoved(int, int oldIndex, int newIndex)
updateGeometries();
int logicalOldIndex = d->verticalHeader->logicalIndex(oldIndex);
int logicalNewIndex = d->verticalHeader->logicalIndex(newIndex);
- if (d->hasSpans() && (d->spansIntersectRow(logicalOldIndex) || d->spansIntersectRow(logicalNewIndex))) {
+ if (d->hasSpans()) {
d->viewport->update();
} else {
int oldTop = rowViewportPosition(logicalOldIndex);
@@ -2142,7 +2243,7 @@ void QTableView::columnMoved(int, int oldIndex, int newIndex)
updateGeometries();
int logicalOldIndex = d->horizontalHeader->logicalIndex(oldIndex);
int logicalNewIndex = d->horizontalHeader->logicalIndex(newIndex);
- if (d->hasSpans() && (d->spansIntersectColumn(logicalOldIndex) || d->spansIntersectColumn(logicalNewIndex))) {
+ if (d->hasSpans()) {
d->viewport->update();
} else {
int oldLeft = columnViewportPosition(logicalOldIndex);
@@ -2325,7 +2426,7 @@ bool QTableView::isIndexHidden(const QModelIndex &index) const
if (isRowHidden(index.row()) || isColumnHidden(index.column()))
return true;
if (d->hasSpans()) {
- QTableViewPrivate::Span span = d->span(index.row(), index.column());
+ QSpanCollection::Span span = d->span(index.row(), index.column());
return !((span.top() == index.row()) && (span.left() == index.column()));
}
return false;
diff --git a/src/gui/itemviews/qtableview_p.h b/src/gui/itemviews/qtableview_p.h
index b08eabd..3f3dd36 100644
--- a/src/gui/itemviews/qtableview_p.h
+++ b/src/gui/itemviews/qtableview_p.h
@@ -53,12 +53,69 @@
// We mean it.
//
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QSet>
+#include <QtCore/QDebug>
#include "private/qabstractitemview_p.h"
#ifndef QT_NO_TABLEVIEW
QT_BEGIN_NAMESPACE
+/** \internal
+*
+* This is a list of span with a binary index to look up quickly a span at a certain index.
+*
+* The index is a map of map.
+* spans are mentaly divided into sub spans so that the start of any subspans doesn't overlap
+* with any other subspans. There is no real representation of the subspans.
+* The key of the first map is the row where the subspan starts, the value of the first map is
+* a list (map) of all subspans that starts at the same row. It is indexed with its row
+*/
+class QSpanCollection
+{
+public:
+ struct Span
+ {
+ int m_top;
+ int m_left;
+ int m_bottom;
+ int m_right;
+ Span()
+ : m_top(-1), m_left(-1), m_bottom(-1), m_right(-1) { }
+ Span(int row, int column, int rowCount, int columnCount)
+ : m_top(row), m_left(column), m_bottom(row+rowCount-1), m_right(column+columnCount-1) { }
+ inline int top() const { return m_top; }
+ inline int left() const { return m_left; }
+ inline int bottom() const { return m_bottom; }
+ inline int right() const { return m_right; }
+ inline int height() const { return m_bottom - m_top + 1; }
+ inline int width() const { return m_right - m_left + 1; }
+ };
+
+ ~QSpanCollection()
+ {
+ qDeleteAll(spans);
+ }
+
+ void addSpan(Span *span);
+ void updateSpan(Span *span, int old_height);
+ Span *spanAt(int x, int y) const;
+ void clear();
+ QList<Span *> spansInRect(int x, int y, int w, int h) const;
+
+ QList<Span *> spans; //lists of all spans
+private:
+ //the indexes are negative so the QMap::lowerBound do what i need.
+ typedef QMap<int, Span *> SubIndex;
+ typedef QMap<int, SubIndex> Index;
+ Index index;
+};
+
+Q_DECLARE_TYPEINFO ( QSpanCollection::Span, Q_MOVABLE_TYPE);
+
+
class QTableViewPrivate : public QAbstractItemViewPrivate
{
Q_DECLARE_PUBLIC(QTableView)
@@ -98,11 +155,7 @@ public:
int sectionSpanEndLogical(const QHeaderView *header, int logical, int span) const;
int sectionSpanSize(const QHeaderView *header, int logical, int span) const;
bool spanContainsSection(const QHeaderView *header, int logical, int spanLogical, int span) const;
- bool spansIntersectColumn(int column) const;
- bool spansIntersectRow(int row) const;
- bool spansIntersectColumns(const QList<int> &columns) const;
- bool spansIntersectRows(const QList<int> &rows) const;
- void drawAndClipSpans(const QRect &area, QPainter *painter,
+ void drawAndClipSpans(const QRegion &area, QPainter *painter,
const QStyleOptionViewItemV4 &option, QBitArray *drawn,
int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn);
void drawCell(QPainter *painter, const QStyleOptionViewItemV4 &option, const QModelIndex &index);
@@ -121,27 +174,10 @@ public:
bool sortingEnabled;
bool geometryRecursionBlock;
- struct Span
- {
- int m_top;
- int m_left;
- int m_bottom;
- int m_right;
- Span()
- : m_top(-1), m_left(-1), m_bottom(-1), m_right(-1) { }
- Span(int row, int column, int rowCount, int columnCount)
- : m_top(row), m_left(column), m_bottom(row+rowCount-1), m_right(column+columnCount-1) { }
- inline int top() const { return m_top; }
- inline int left() const { return m_left; }
- inline int bottom() const { return m_bottom; }
- inline int right() const { return m_right; }
- inline int height() const { return m_bottom - m_top + 1; }
- inline int width() const { return m_right - m_left + 1; }
- };
- QList<Span> spans;
+ QSpanCollection spans;
void setSpan(int row, int column, int rowSpan, int columnSpan);
- Span span(int row, int column) const;
+ QSpanCollection::Span span(int row, int column) const;
inline int rowSpan(int row, int column) const {
return span(row, column).height();
}
@@ -149,17 +185,7 @@ public:
return span(row, column).width();
}
inline bool hasSpans() const {
- return !spans.isEmpty();
- }
- inline bool spanContainsRow(int row, int spanRow, int span) const {
- return spanContainsSection(verticalHeader, row, spanRow, span);
- }
- inline bool spanContainsColumn(int column, int spanColumn, int span) const {
- return spanContainsSection(horizontalHeader, column, spanColumn, span);
- }
- inline bool isInSpan(int row, int column, const Span &span) const {
- return spanContainsRow(row, span.top(), span.height())
- && spanContainsColumn(column, span.left(), span.width());
+ return !spans.spans.isEmpty();
}
inline int rowSpanHeight(int row, int span) const {
return sectionSpanSize(verticalHeader, row, span);
@@ -194,7 +220,7 @@ public:
return isColumnHidden(c) || !isCellEnabled(r, c);
}
- QRect visualSpanRect(const Span &span) const;
+ QRect visualSpanRect(const QSpanCollection::Span &span) const;
void _q_selectRow(int row);
void _q_selectColumn(int column);
diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp
index 62c1277..d742698 100644
--- a/src/gui/itemviews/qtreeview.cpp
+++ b/src/gui/itemviews/qtreeview.cpp
@@ -680,10 +680,9 @@ void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto
// refresh the height cache here; we don't really lose anything by getting the size hint,
// since QAbstractItemView::dataChanged() will get the visualRect for the items anyway
- QModelIndex top = topLeft.sibling(topLeft.row(), 0);
- int topViewIndex = d->viewIndex(top);
+ int topViewIndex = d->viewIndex(topLeft);
if (topViewIndex == 0)
- d->defaultItemHeight = indexRowSizeHint(top);
+ d->defaultItemHeight = indexRowSizeHint(topLeft);
bool sizeChanged = false;
if (topViewIndex != -1) {
if (topLeft == bottomRight) {
@@ -691,8 +690,7 @@ void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto
d->invalidateHeightCache(topViewIndex);
sizeChanged = (oldHeight != d->itemHeight(topViewIndex));
} else {
- QModelIndex bottom = bottomRight.sibling(bottomRight.row(), 0);
- int bottomViewIndex = d->viewIndex(bottom);
+ int bottomViewIndex = d->viewIndex(bottomRight);
for (int i = topViewIndex; i <= bottomViewIndex; ++i) {
int oldHeight = d->itemHeight(i);
d->invalidateHeightCache(i);
@@ -1140,7 +1138,7 @@ void QTreeView::scrollTo(const QModelIndex &index, ScrollHint hint)
if (rect.isEmpty()) {
// nothing to do
} else if (hint == EnsureVisible && area.contains(rect)) {
- d->setDirtyRegion(rect);
+ d->viewport->update(rect);
// nothing to do
} else {
bool above = (hint == EnsureVisible
@@ -1546,7 +1544,7 @@ void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option,
? logicalIndexBeforeLeft
: logicalIndices.at(currentLogicalSection - 1);
if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1)
- || (headerSection == 0 && nextLogicalSection == -1))
+ || (headerSection == 0 && nextLogicalSection == -1) || spanning)
opt.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
else if (headerSection == 0 || (nextLogicalSection != 0 && prevLogicalSection == -1))
opt.viewItemPosition = QStyleOptionViewItemV4::Beginning;
@@ -1815,10 +1813,10 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event)
if (i == -1)
return; // user clicked outside the items
- const QModelIndex &index = d->viewItems.at(i).index;
+ const QPersistentModelIndex firstColumnIndex = d->viewItems.at(i).index;
int column = d->header->logicalIndexAt(event->x());
- QPersistentModelIndex persistent = index.sibling(index.row(), column);
+ QPersistentModelIndex persistent = firstColumnIndex.sibling(firstColumnIndex.row(), column);
if (d->pressedIndex != persistent) {
mousePressEvent(event);
@@ -1841,10 +1839,10 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event)
if (d->itemsExpandable
&& d->expandsOnDoubleClick
&& d->hasVisibleChildren(persistent)) {
- if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == persistent))) {
+ if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == firstColumnIndex))) {
// find the new index of the item
for (i = 0; i < d->viewItems.count(); ++i) {
- if (d->viewItems.at(i).index == persistent)
+ if (d->viewItems.at(i).index == firstColumnIndex)
break;
}
if (i == d->viewItems.count())
@@ -2422,14 +2420,10 @@ void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end)
? d->viewItems.count()
: d->viewItems.at(parentItem).total) - 1;
- int firstColumn = 0;
- while (isColumnHidden(firstColumn) && firstColumn < header()->count() - 1)
- ++firstColumn;
-
const int delta = end - start + 1;
QVector<QTreeViewItem> insertedItems(delta);
for (int i = 0; i < delta; ++i) {
- insertedItems[i].index = d->model->index(i + start, firstColumn, parent);
+ insertedItems[i].index = d->model->index(i + start, 0, parent);
insertedItems[i].level = childLevel;
}
if (d->viewItems.isEmpty())
@@ -2612,7 +2606,7 @@ void QTreeView::expandAll()
d->viewItems[i].expanded = true;
d->layout(i);
QModelIndex idx = d->viewItems.at(i).index;
- d->expandedIndexes.insert(idx.sibling(idx.row(), 0));
+ d->expandedIndexes.insert(idx);
}
updateGeometries();
d->viewport->update();
@@ -3092,10 +3086,6 @@ void QTreeViewPrivate::layout(int i)
Q_Q(QTreeView);
QModelIndex current;
QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i);
- // modelIndex() will return an index that don't have a parent if column 0 is hidden,
- // so we must make sure that parent points to the actual parent that has children.
- if (parent != root)
- parent = model->index(parent.row(), 0, parent.parent());
if (i>=0 && !parent.isValid()) {
//modelIndex() should never return something invalid for the real items.
@@ -3130,13 +3120,9 @@ void QTreeViewPrivate::layout(int i)
int last = 0;
int children = 0;
- int firstColumn = 0;
- while (header->isSectionHidden(firstColumn) && firstColumn < header->count())
- ++firstColumn;
-
for (int j = first; j < first + count; ++j) {
- current = model->index(j - first, firstColumn, parent);
- if (isRowHidden(current.sibling(current.row(), 0))) {
+ current = model->index(j - first, 0, parent);
+ if (isRowHidden(current)) {
++hidden;
last = j - hidden + children;
} else {
@@ -3319,15 +3305,11 @@ int QTreeViewPrivate::itemAtCoordinate(int coordinate) const
int QTreeViewPrivate::viewIndex(const QModelIndex &_index) const
{
- Q_Q(const QTreeView);
if (!_index.isValid() || viewItems.isEmpty())
return -1;
const int totalCount = viewItems.count();
- int firstColumn = 0;
- while (q->isColumnHidden(firstColumn) && firstColumn < header->count())
- ++firstColumn;
- const QModelIndex index = _index.sibling(_index.row(), firstColumn);
+ const QModelIndex index = _index.sibling(_index.row(), 0);
// A quick check near the last item to see if we are just incrementing