summaryrefslogtreecommitdiffstats
path: root/src/widgets/itemviews
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/itemviews')
-rw-r--r--src/widgets/itemviews/qabstractitemdelegate.cpp6
-rw-r--r--src/widgets/itemviews/qabstractitemview.cpp90
-rw-r--r--src/widgets/itemviews/qabstractitemview_p.h1
-rw-r--r--src/widgets/itemviews/qheaderview.cpp30
-rw-r--r--src/widgets/itemviews/qheaderview_p.h2
-rw-r--r--src/widgets/itemviews/qlistview.cpp13
-rw-r--r--src/widgets/itemviews/qtableview.cpp6
-rw-r--r--src/widgets/itemviews/qtreeview.cpp19
-rw-r--r--src/widgets/itemviews/qtreewidget.cpp25
9 files changed, 142 insertions, 50 deletions
diff --git a/src/widgets/itemviews/qabstractitemdelegate.cpp b/src/widgets/itemviews/qabstractitemdelegate.cpp
index c5b22b5667..e120817edc 100644
--- a/src/widgets/itemviews/qabstractitemdelegate.cpp
+++ b/src/widgets/itemviews/qabstractitemdelegate.cpp
@@ -389,10 +389,12 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event,
{
if (!event || !view)
return false;
- Q_D(QAbstractItemDelegate);
+ Q_UNUSED(index);
+ Q_UNUSED(option);
switch (event->type()) {
#ifndef QT_NO_TOOLTIP
case QEvent::ToolTip: {
+ Q_D(QAbstractItemDelegate);
QHelpEvent *he = static_cast<QHelpEvent*>(event);
const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp
const QString tooltip = index.isValid() ?
@@ -413,6 +415,7 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event,
event->setAccepted(index.data(Qt::WhatsThisRole).isValid());
break;
case QEvent::WhatsThis: {
+ Q_D(QAbstractItemDelegate);
QHelpEvent *he = static_cast<QHelpEvent*>(event);
const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp
const QString whatsthis = index.isValid() ?
@@ -423,6 +426,7 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event,
break;
}
#endif
+ case QEvent::None:
default:
break;
}
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp
index b8cc5621fb..93dc5ee80c 100644
--- a/src/widgets/itemviews/qabstractitemview.cpp
+++ b/src/widgets/itemviews/qabstractitemview.cpp
@@ -87,6 +87,7 @@ QAbstractItemViewPrivate::QAbstractItemViewPrivate()
pressedModifiers(Qt::NoModifier),
pressedPosition(QPoint(-1, -1)),
pressedAlreadySelected(false),
+ releaseFromDoubleClick(false),
viewportEnteredNeeded(false),
state(QAbstractItemView::NoState),
stateBeforeAnimation(QAbstractItemView::NoState),
@@ -1168,12 +1169,21 @@ QModelIndex QAbstractItemView::rootIndex() const
void QAbstractItemView::selectAll()
{
Q_D(QAbstractItemView);
- SelectionMode mode = d->selectionMode;
- if (mode == MultiSelection || mode == ExtendedSelection)
+ const SelectionMode mode = d->selectionMode;
+ switch (mode) {
+ case MultiSelection:
+ case ExtendedSelection:
d->selectAll(QItemSelectionModel::ClearAndSelect
- |d->selectionBehaviorFlags());
- else if (mode != SingleSelection)
- d->selectAll(selectionCommand(d->model->index(0, 0, d->root)));
+ | d->selectionBehaviorFlags());
+ break;
+ case NoSelection:
+ case ContiguousSelection:
+ if (d->model->hasChildren(d->root))
+ d->selectAll(selectionCommand(d->model->index(0, 0, d->root)));
+ break;
+ case SingleSelection:
+ break;
+ }
}
/*!
@@ -1754,6 +1764,7 @@ bool QAbstractItemView::viewportEvent(QEvent *event)
void QAbstractItemView::mousePressEvent(QMouseEvent *event)
{
Q_D(QAbstractItemView);
+ d->releaseFromDoubleClick = false;
d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
QPoint pos = event->pos();
QPersistentModelIndex index = indexAt(pos);
@@ -1899,6 +1910,8 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QAbstractItemView);
+ const bool releaseFromDoubleClick = d->releaseFromDoubleClick;
+ d->releaseFromDoubleClick = false;
QPoint pos = event->pos();
QPersistentModelIndex index = indexAt(pos);
@@ -1911,7 +1924,7 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event)
return;
}
- bool click = (index == d->pressedIndex && index.isValid());
+ bool click = (index == d->pressedIndex && index.isValid() && !releaseFromDoubleClick);
bool selectedClicked = click && (event->button() == Qt::LeftButton) && d->pressedAlreadySelected;
EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers);
const bool edited = click ? edit(index, trigger, event) : false;
@@ -1964,7 +1977,7 @@ void QAbstractItemView::mouseDoubleClickEvent(QMouseEvent *event)
if ((event->button() == Qt::LeftButton) && !edit(persistent, DoubleClicked, event)
&& !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this))
emit activated(persistent);
- d->pressedIndex = QModelIndex();
+ d->releaseFromDoubleClick = true;
}
#if QT_CONFIG(draganddrop)
@@ -2334,11 +2347,12 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event)
#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
if (event == QKeySequence::Copy) {
- QVariant variant;
- if (d->model)
- variant = d->model->data(currentIndex(), Qt::DisplayRole);
- if (variant.canConvert<QString>())
- QGuiApplication::clipboard()->setText(variant.toString());
+ const QModelIndex index = currentIndex();
+ if (index.isValid() && d->model) {
+ const QVariant variant = d->model->data(index, Qt::DisplayRole);
+ if (variant.canConvert<QString>())
+ QGuiApplication::clipboard()->setText(variant.toString());
+ }
event->accept();
}
#endif
@@ -3404,15 +3418,39 @@ void QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int star
} else {
int row = end + 1;
QModelIndex next;
- do { // find the next visible and enabled item
+ const int rowCount = d->model->rowCount(parent);
+ bool found = false;
+ // find the next visible and enabled item
+ while (row < rowCount && !found) {
next = d->model->index(row++, current.column(), current.parent());
- } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next)));
- if (row > d->model->rowCount(parent)) {
+#ifdef QT_DEBUG
+ if (!next.isValid()) {
+ qWarning("Model unexpectedly returned an invalid index");
+ break;
+ }
+#endif
+ if (!isIndexHidden(next) && d->isIndexEnabled(next)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
row = start - 1;
- do { // find the previous visible and enabled item
+ // find the previous visible and enabled item
+ while (row >= 0) {
next = d->model->index(row--, current.column(), current.parent());
- } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next)));
+#ifdef QT_DEBUG
+ if (!next.isValid()) {
+ qWarning("Model unexpectedly returned an invalid index");
+ break;
+ }
+#endif
+ if (!isIndexHidden(next) && d->isIndexEnabled(next))
+ break;
+ }
}
+
setCurrentIndex(next);
}
}
@@ -3490,9 +3528,19 @@ void QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &par
} else {
int column = end;
QModelIndex next;
- do { // find the next visible and enabled item
+ const int columnCount = model->columnCount(current.parent());
+ // find the next visible and enabled item
+ while (column < columnCount) {
next = model->index(current.row(), column++, current.parent());
- } while (next.isValid() && (q->isIndexHidden(next) || !isIndexEnabled(next)));
+#ifdef QT_DEBUG
+ if (!next.isValid()) {
+ qWarning("Model unexpectedly returned an invalid index");
+ break;
+ }
+#endif
+ if (!q->isIndexHidden(next) && isIndexEnabled(next))
+ break;
+ }
q->setCurrentIndex(next);
}
}
@@ -4301,7 +4349,7 @@ void QAbstractItemViewPrivate::updateEditorData(const QModelIndex &tl, const QMo
In DND if something has been moved then this is called.
Typically this means you should "remove" the selected item or row,
- but the behavior is view dependant (table just clears the selected indexes for example).
+ but the behavior is view-dependent (table just clears the selected indexes for example).
Either remove the selected rows or clear them
*/
@@ -4494,6 +4542,8 @@ void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags com
{
if (!selectionModel)
return;
+ if (!model->hasChildren(root))
+ return;
QItemSelection selection;
QModelIndex tl = model->index(0, 0, root);
diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h
index 33924799fe..7532cf5789 100644
--- a/src/widgets/itemviews/qabstractitemview_p.h
+++ b/src/widgets/itemviews/qabstractitemview_p.h
@@ -385,6 +385,7 @@ public:
Qt::KeyboardModifiers pressedModifiers;
QPoint pressedPosition;
bool pressedAlreadySelected;
+ bool releaseFromDoubleClick;
//forces the next mouseMoveEvent to send the viewportEntered signal
//if the mouse is over the viewport and not over an item
diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp
index 84e2fd72a9..3b396c689b 100644
--- a/src/widgets/itemviews/qheaderview.cpp
+++ b/src/widgets/itemviews/qheaderview.cpp
@@ -2528,7 +2528,7 @@ void QHeaderView::mousePressEvent(QMouseEvent *e)
int handle = d->sectionHandleAt(pos);
d->originalSize = -1; // clear the stored original size
if (handle == -1) {
- d->pressed = logicalIndexAt(pos);
+ d->firstPressed = d->pressed = logicalIndexAt(pos);
if (d->clickableSections)
emit sectionPressed(d->pressed);
@@ -2576,7 +2576,7 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e)
// just before the mouseReleaseEvent and resets the state. This prevents
// column dragging from working. So this code is disabled under Cocoa.
d->state = QHeaderViewPrivate::NoState;
- d->pressed = -1;
+ d->firstPressed = d->pressed = -1;
}
switch (d->state) {
case QHeaderViewPrivate::ResizeSection: {
@@ -2705,9 +2705,27 @@ void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
case QHeaderViewPrivate::NoState:
if (d->clickableSections) {
int section = logicalIndexAt(pos);
- if (section != -1 && section == d->pressed) {
- d->flipSortIndicator(section);
- emit sectionClicked(section);
+ if (section != -1 && section == d->firstPressed) {
+ QRect firstPressedSectionRect;
+ switch (d->orientation) {
+ case Qt::Horizontal:
+ firstPressedSectionRect.setRect(sectionViewportPosition(d->firstPressed),
+ 0,
+ sectionSize(d->firstPressed),
+ d->viewport->height());
+ break;
+ case Qt::Vertical:
+ firstPressedSectionRect.setRect(0,
+ sectionViewportPosition(d->firstPressed),
+ d->viewport->width(),
+ sectionSize(d->firstPressed));
+ break;
+ };
+
+ if (firstPressedSectionRect.contains(e->pos())) {
+ d->flipSortIndicator(section);
+ emit sectionClicked(section);
+ }
}
if (d->pressed != -1)
updateSection(d->pressed);
@@ -2721,7 +2739,7 @@ void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
break;
}
d->state = QHeaderViewPrivate::NoState;
- d->pressed = -1;
+ d->firstPressed = d->pressed = -1;
}
/*!
diff --git a/src/widgets/itemviews/qheaderview_p.h b/src/widgets/itemviews/qheaderview_p.h
index 766adef36d..0f6641c3df 100644
--- a/src/widgets/itemviews/qheaderview_p.h
+++ b/src/widgets/itemviews/qheaderview_p.h
@@ -82,6 +82,7 @@ public:
originalSize(-1),
section(-1),
target(-1),
+ firstPressed(-1),
pressed(-1),
hover(-1),
length(0),
@@ -274,6 +275,7 @@ public:
int originalSize;
int section; // used for resizing and moving sections
int target;
+ int firstPressed;
int pressed;
int hover;
diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp
index 2d33759d8c..fab44923de 100644
--- a/src/widgets/itemviews/qlistview.cpp
+++ b/src/widgets/itemviews/qlistview.cpp
@@ -572,6 +572,8 @@ void QListView::scrollTo(const QModelIndex &index, ScrollHint hint)
return;
const QRect rect = visualRect(index);
+ if (!rect.isValid())
+ return;
if (hint == EnsureVisible && d->viewport->rect().contains(rect)) {
d->viewport->update(rect);
return;
@@ -940,7 +942,8 @@ void QListView::dropEvent(QDropEvent *event)
int r = row == -1 ? model()->rowCount() : (dropRow.row() >= 0 ? dropRow.row() : row);
for (int i = 0; i < persIndexes.count(); ++i) {
const QPersistentModelIndex &pIndex = persIndexes.at(i);
- if (r != pIndex.row()) {
+ // only generate a move when not same row or behind itself
+ if (r != pIndex.row() && r != pIndex.row() + 1) {
// try to move (preserves selection)
d->dropEventMoved |= model()->moveRow(QModelIndex(), pIndex.row(), QModelIndex(), r);
if (!d->dropEventMoved) // can't move - abort and let QAbstractItemView handle this
@@ -1539,12 +1542,14 @@ void QListView::doItemsLayout()
setState(ExpandingState);
if (d->model->columnCount(d->root) > 0) { // no columns means no contents
d->resetBatchStartRow();
- if (layoutMode() == SinglePass)
+ if (layoutMode() == SinglePass) {
d->doItemsLayout(d->model->rowCount(d->root)); // layout everything
- else if (!d->batchLayoutTimer.isActive()) {
+ } else if (!d->batchLayoutTimer.isActive()) {
if (!d->doItemsLayout(d->batchSize)) // layout is done
d->batchLayoutTimer.start(0, this); // do a new batch as fast as possible
}
+ } else { // clear the QBspTree generated by the last layout
+ d->clear();
}
QAbstractItemView::doItemsLayout();
setState(oldState); // restoring the oldState
@@ -2930,6 +2935,8 @@ bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
dd->stopAutoScroll();
draggedItems.clear();
dd->emitIndexesMoved(indexes);
+ // do not delete item on internal move, see filterStartDrag()
+ dd->dropEventMoved = true;
e->accept(); // we have handled the event
// if the size has not grown, we need to check if it has shrinked
if (contentsSize != contents) {
diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp
index 1b72536dcf..d120c41dc9 100644
--- a/src/widgets/itemviews/qtableview.cpp
+++ b/src/widgets/itemviews/qtableview.cpp
@@ -1101,6 +1101,8 @@ int QTableViewPrivate::heightHintForIndex(const QModelIndex &index, int hint, QS
table can be found by using rowHeight(); similarly, the width of
columns can be found using columnWidth(). Since both of these are plain
widgets, you can hide either of them using their hide() functions.
+ Each header is configured with its \l{QHeaderView::}{highlightSections}
+ and \l{QHeaderView::}{sectionsClickable} properties set to \c true.
Rows and columns can be hidden and shown with hideRow(), hideColumn(),
showRow(), and showColumn(). They can be selected with selectRow()
@@ -2944,6 +2946,8 @@ void QTableView::timerEvent(QTimerEvent *event)
updateGeometries();
killTimer(d->columnResizeTimerID);
d->columnResizeTimerID = 0;
+ } else {
+ updateEditorGeometries();
}
QRect rect;
@@ -2972,6 +2976,8 @@ void QTableView::timerEvent(QTimerEvent *event)
updateGeometries();
killTimer(d->rowResizeTimerID);
d->rowResizeTimerID = 0;
+ } else {
+ updateEditorGeometries();
}
int viewportHeight = d->viewport->height();
diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp
index b778ef9a47..6ab6576cbe 100644
--- a/src/widgets/itemviews/qtreeview.cpp
+++ b/src/widgets/itemviews/qtreeview.cpp
@@ -1448,7 +1448,8 @@ void QTreeViewPrivate::adjustViewOptionsForIndex(QStyleOptionViewItem *option, c
void QTreeView::drawTree(QPainter *painter, const QRegion &region) const
{
Q_D(const QTreeView);
- const QVector<QTreeViewItem> viewItems = d->viewItems;
+ // d->viewItems changes when posted layouts are executed in itemDecorationAt, so don't copy
+ const QVector<QTreeViewItem> &viewItems = d->viewItems;
QStyleOptionViewItem option = d->viewOptionsV1();
const QStyle::State state = option.state;
@@ -1947,7 +1948,7 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event)
if (!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this))
emit activated(persistent);
- d->pressedIndex = QModelIndex();
+ d->releaseFromDoubleClick = true;
d->executePostedLayout(); // we need to make sure viewItems is updated
if (d->itemsExpandable
&& d->expandsOnDoubleClick
@@ -2664,7 +2665,10 @@ QSize QTreeView::viewportSizeHint() const
\since 4.2
Expands all expandable items.
- \warning: if the model contains a large number of items,
+ \note This function will not try to \l{QAbstractItemModel::fetchMore}{fetch more}
+ data.
+
+ \warning If the model contains a large number of items,
this function will take some time to execute.
\sa collapseAll(), expand(), collapse(), setExpanded()
@@ -2686,7 +2690,10 @@ void QTreeView::expandAll()
A \a depth of -1 will expand all children, a \a depth of 0 will
only expand the given \a index.
- \warning: if the model contains a large number of items,
+ \note This function will not try to \l{QAbstractItemModel::fetchMore}{fetch more}
+ data.
+
+ \warning If the model contains a large number of items,
this function will take some time to execute.
\sa expandAll()
@@ -2751,6 +2758,9 @@ void QTreeView::collapseAll()
\since 4.3
Expands all expandable items to the given \a depth.
+ \note This function will not try to \l{QAbstractItemModel::fetchMore}{fetch more}
+ data.
+
\sa expandAll(), collapseAll(), expand(), collapse(), setExpanded()
*/
void QTreeView::expandToDepth(int depth)
@@ -3459,6 +3469,7 @@ int QTreeViewPrivate::indentationForItem(int item) const
int QTreeViewPrivate::itemHeight(int item) const
{
+ Q_ASSERT(item < viewItems.count());
if (uniformRowHeights)
return defaultItemHeight;
if (viewItems.isEmpty())
diff --git a/src/widgets/itemviews/qtreewidget.cpp b/src/widgets/itemviews/qtreewidget.cpp
index 47b06a4138..713cb8e0d2 100644
--- a/src/widgets/itemviews/qtreewidget.cpp
+++ b/src/widgets/itemviews/qtreewidget.cpp
@@ -508,22 +508,18 @@ bool QTreeModel::insertColumns(int column, int count, const QModelIndex &parent)
bool QTreeModel::removeRows(int row, int count, const QModelIndex &parent) {
if (count < 1 || row < 0 || (row + count) > rowCount(parent))
return false;
-
- beginRemoveRows(parent, row, row + count - 1);
-
- QSignalBlocker blocker(this);
-
- QTreeWidgetItem *itm = item(parent);
+ QTreeWidgetItem *parentItem = item(parent);
+ // if parentItem is valid, begin/end RemoveRows is handled by takeChild below
+ if (!parentItem)
+ beginRemoveRows(parent, row, row + count - 1);
for (int i = row + count - 1; i >= row; --i) {
- QTreeWidgetItem *child = itm ? itm->takeChild(i) : rootItem->children.takeAt(i);
+ QTreeWidgetItem *child = parentItem ? parentItem->takeChild(i) : rootItem->children.takeAt(i);
Q_ASSERT(child);
child->view = nullptr;
delete child;
- child = nullptr;
}
- blocker.unblock();
-
- endRemoveRows();
+ if (!parentItem)
+ endRemoveRows();
return true;
}
@@ -1690,7 +1686,7 @@ QTreeWidgetItem *QTreeWidgetItem::clone() const
/*!
Sets the item indicator \a policy. This policy decides when the
tree branch expand/collapse indicator is shown.
- The default value is ShowForChildren.
+ The default value is DontShowIndicatorWhenChildless.
\sa childIndicatorPolicy()
*/
@@ -2601,9 +2597,6 @@ void QTreeWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft,
This signal is emitted when the specified \a item is expanded so that
all of its children are displayed.
- \note This signal will not be emitted if an item changes its state when
- expandAll() is invoked.
-
\sa QTreeWidgetItem::isExpanded(), itemCollapsed(), expandItem()
*/
@@ -2702,7 +2695,7 @@ QTreeWidget::~QTreeWidget()
}
/*
- Retuns the number of header columns in the view.
+ Returns the number of header columns in the view.
\sa sortColumn(), currentColumn(), topLevelItemCount()
*/