Set missing flags in the option when rendering QTreeView drag pixmap

QAbstractItemViewPrivate::renderToPixmap was not setting all the flags
that the normal QTreeView painting sets:
option.showDecorationSelected, option.viewItemPosition (so the drag pixmap
looked wrong on Windows 7, with rects around each cell), and then the
unittest also discovered that State_Children/State_Sibling wasn't set either.

Task-number: QTBUG-15834
Merge-request: 2517

(cherry picked from Qt4 commit d63910575949106f84dacf04abaa14fc866aa66b)

Change-Id: I0a5014d960543c3ed8fea73d6df578e7e521b0e0
Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
This commit is contained in:
David Faure 2010-12-03 11:34:09 +01:00 committed by Qt by Nokia
parent 188db2b817
commit 22b7d21186
6 changed files with 95 additions and 40 deletions

View File

@ -4296,6 +4296,7 @@ QPixmap QAbstractItemViewPrivate::renderToPixmap(const QModelIndexList &indexes,
for (int j = 0; j < paintPairs.count(); ++j) {
option.rect = paintPairs.at(j).first.translated(-r->topLeft());
const QModelIndex &current = paintPairs.at(j).second;
adjustViewOptionsForIndex(&option, current);
delegateForIndex(current)->paint(&painter, option, current);
}
return pixmap;

View File

@ -197,6 +197,8 @@ public:
#endif
virtual QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const;
// reimplemented in subclasses
virtual void adjustViewOptionsForIndex(QStyleOptionViewItemV4*, const QModelIndex&) const {}
inline void releaseEditor(QWidget *editor) const {
if (editor) {

View File

@ -1378,6 +1378,23 @@ QItemViewPaintPairs QTreeViewPrivate::draggablePaintPairs(const QModelIndexList
return ret;
}
void QTreeViewPrivate::adjustViewOptionsForIndex(QStyleOptionViewItemV4 *option, const QModelIndex &current) const
{
const int row = current.row();
option->state = option->state | (viewItems.at(row).expanded ? QStyle::State_Open : QStyle::State_None)
| (viewItems.at(row).hasChildren ? QStyle::State_Children : QStyle::State_None)
| (viewItems.at(row).hasMoreSiblings ? QStyle::State_Sibling : QStyle::State_None);
option->showDecorationSelected = (selectionBehavior & QTreeView::SelectRows)
|| option->showDecorationSelected;
QVector<int> logicalIndices;
QVector<QStyleOptionViewItemV4::ViewItemPosition> viewItemPosList; // vector of left/middle/end for each logicalIndex
calcLogicalIndices(&logicalIndices, &viewItemPosList);
int logicalIndex = header->logicalIndex(current.column());
option->viewItemPosition = viewItemPosList.at(logicalIndex);
}
/*!
\since 4.2
@ -1463,6 +1480,59 @@ static inline bool ancestorOf(QObject *widget, QObject *other)
return false;
}
void QTreeViewPrivate::calcLogicalIndices(QVector<int> *logicalIndices, QVector<QStyleOptionViewItemV4::ViewItemPosition> *itemPositions) const
{
const int left = (spanning ? header->visualIndex(0) : leftAndRight.first);
const int right = (spanning ? header->visualIndex(0) : leftAndRight.second);
const int columnCount = header->count();
/* 'left' and 'right' are the left-most and right-most visible visual indices.
Compute the first visible logical indices before and after the left and right.
We will use these values to determine the QStyleOptionViewItemV4::viewItemPosition. */
int logicalIndexBeforeLeft = -1, logicalIndexAfterRight = -1;
for (int visualIndex = left - 1; visualIndex >= 0; --visualIndex) {
int logicalIndex = header->logicalIndex(visualIndex);
if (!header->isSectionHidden(logicalIndex)) {
logicalIndexBeforeLeft = logicalIndex;
break;
}
}
for (int visualIndex = left; visualIndex < columnCount; ++visualIndex) {
int logicalIndex = header->logicalIndex(visualIndex);
if (!header->isSectionHidden(logicalIndex)) {
if (visualIndex > right) {
logicalIndexAfterRight = logicalIndex;
break;
}
logicalIndices->append(logicalIndex);
}
}
itemPositions->resize(logicalIndices->count());
for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices->count(); ++currentLogicalSection) {
const int headerSection = logicalIndices->at(currentLogicalSection);
// determine the viewItemPosition depending on the position of column 0
int nextLogicalSection = currentLogicalSection + 1 >= logicalIndices->count()
? logicalIndexAfterRight
: logicalIndices->at(currentLogicalSection + 1);
int prevLogicalSection = currentLogicalSection - 1 < 0
? logicalIndexBeforeLeft
: logicalIndices->at(currentLogicalSection - 1);
QStyleOptionViewItemV4::ViewItemPosition pos;
if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1)
|| (headerSection == 0 && nextLogicalSection == -1) || spanning)
pos = QStyleOptionViewItemV4::OnlyOne;
else if (headerSection == 0 || (nextLogicalSection != 0 && prevLogicalSection == -1))
pos = QStyleOptionViewItemV4::Beginning;
else if (nextLogicalSection == 0 || nextLogicalSection == -1)
pos = QStyleOptionViewItemV4::End;
else
pos = QStyleOptionViewItemV4::Middle;
(*itemPositions)[currentLogicalSection] = pos;
}
}
/*!
Draws the row in the tree view that contains the model item \a index,
using the \a painter given. The \a option control how the item is
@ -1531,33 +1601,13 @@ void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option,
int width, height = option.rect.height();
int position;
QModelIndex modelIndex;
int columnCount = header->count();
const bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
&& index.parent() == hover.parent()
&& index.row() == hover.row();
/* 'left' and 'right' are the left-most and right-most visible visual indices.
Compute the first visible logical indices before and after the left and right.
We will use these values to determine the QStyleOptionViewItemV4::viewItemPosition. */
int logicalIndexBeforeLeft = -1, logicalIndexAfterRight = -1;
for (int visualIndex = left - 1; visualIndex >= 0; --visualIndex) {
int logicalIndex = header->logicalIndex(visualIndex);
if (!header->isSectionHidden(logicalIndex)) {
logicalIndexBeforeLeft = logicalIndex;
break;
}
}
QVector<int> logicalIndices; // vector of currently visibly logical indices
for (int visualIndex = left; visualIndex < columnCount; ++visualIndex) {
int logicalIndex = header->logicalIndex(visualIndex);
if (!header->isSectionHidden(logicalIndex)) {
if (visualIndex > right) {
logicalIndexAfterRight = logicalIndex;
break;
}
logicalIndices.append(logicalIndex);
}
}
QVector<int> logicalIndices;
QVector<QStyleOptionViewItemV4::ViewItemPosition> viewItemPosList; // vector of left/middle/end for each logicalIndex
d->calcLogicalIndices(&logicalIndices, &viewItemPosList);
for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices.count(); ++currentLogicalSection) {
int headerSection = logicalIndices.at(currentLogicalSection);
@ -1579,22 +1629,7 @@ void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option,
continue;
opt.state = state;
// determine the viewItemPosition depending on the position of column 0
int nextLogicalSection = currentLogicalSection + 1 >= logicalIndices.count()
? logicalIndexAfterRight
: logicalIndices.at(currentLogicalSection + 1);
int prevLogicalSection = currentLogicalSection - 1 < 0
? logicalIndexBeforeLeft
: logicalIndices.at(currentLogicalSection - 1);
if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1)
|| (headerSection == 0 && nextLogicalSection == -1) || spanning)
opt.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
else if (headerSection == 0 || (nextLogicalSection != 0 && prevLogicalSection == -1))
opt.viewItemPosition = QStyleOptionViewItemV4::Beginning;
else if (nextLogicalSection == 0 || nextLogicalSection == -1)
opt.viewItemPosition = QStyleOptionViewItemV4::End;
else
opt.viewItemPosition = QStyleOptionViewItemV4::Middle;
opt.viewItemPosition = viewItemPosList.at(currentLogicalSection);
// fake activeness when row editor has focus
if (indexWidgetHasFocus)

View File

@ -97,6 +97,7 @@ public:
void initialize();
QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const;
void adjustViewOptionsForIndex(QStyleOptionViewItemV4 *option, const QModelIndex &current) const;
#ifndef QT_NO_ANIMATION
struct AnimatedOperation : public QVariantAnimation
@ -167,6 +168,10 @@ public:
void paintAlternatingRowColors(QPainter *painter, QStyleOptionViewItemV4 *option, int y, int bottom) const;
// logicalIndices: vector of currently visibly logical indices
// itemPositions: vector of view item positions (beginning/middle/end/onlyone)
void calcLogicalIndices(QVector<int> *logicalIndices, QVector<QStyleOptionViewItemV4::ViewItemPosition> *itemPositions) const;
QHeaderView *header;
int indent;

View File

@ -1,4 +1,5 @@
CONFIG += testcase
TARGET = tst_qtreeview
QT += widgets testlib
QT += widgets-private gui-private core-private
SOURCES += tst_qtreeview.cpp

View File

@ -43,6 +43,7 @@
#include <QtTest/QtTest>
#include <QtGui/QtGui>
#include <QtWidgets/QtWidgets>
#include <private/qabstractitemview_p.h>
Q_DECLARE_METATYPE(QModelIndex)
#ifndef QT_NO_DRAGANDDROP
@ -106,6 +107,8 @@ struct PublicView : public QTreeView
inline QStyleOptionViewItem viewOptions() const { return QTreeView::viewOptions(); }
inline int sizeHintForColumn(int column) const { return QTreeView::sizeHintForColumn(column); }
inline void startDrag(Qt::DropActions supportedActions) { QTreeView::startDrag(supportedActions); }
QAbstractItemViewPrivate* aiv_priv() { return static_cast<QAbstractItemViewPrivate*>(d_ptr.data()); }
};
class tst_QTreeView : public QObject
@ -2933,7 +2936,7 @@ void tst_QTreeView::styleOptionViewItem()
bool allCollapsed;
};
QTreeView view;
PublicView view;
QStandardItemModel model;
view.setModel(&model);
MyDelegate delegate;
@ -2992,6 +2995,14 @@ void tst_QTreeView::styleOptionViewItem()
QApplication::processEvents();
QTRY_VERIFY(delegate.count >= 4);
// test that the rendering of drag pixmap sets the correct options too (QTBUG-15834)
#ifdef QT_BUILD_INTERNAL
delegate.count = 0;
QItemSelection sel(model.index(0,0), model.index(0,3));
QRect rect;
view.aiv_priv()->renderToPixmap(sel.indexes(), &rect);
QTRY_VERIFY(delegate.count >= 4);
#endif
//test dynamic models
{