Itemviews: add ItemIsUserTristate flag

ItemIsTristate is now again purely for enabling the automatic management
of the check state of QTreeWidgetItems, while ItemIsUserTristate is
separate from that and lets the user select the three states manually.

This restores the original behavior of ItemIsTristate for QTreeWidgetItems,
which got broken by letting the user cycle through the states too.

[ChangeLog][QtWidgets][QTreeWidget] Restored Qt 5.1 behavior of
QTreeWidgetItems with ItemIsTristate to enable automatic management
of the check state. User-editable tristate checkboxes are now enabled
by setting the new flag ItemIsUserTristate.

Task-number: QTBUG-40060
Change-Id: I341f5e983804d3b4f27982520bb6647f3014cccc
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Reviewed-by: Jarek Kobus <jaroslaw.kobus@theqtcompany.com>
This commit is contained in:
David Faure 2015-01-15 14:12:34 +01:00
parent ed56e79b53
commit 4910f416c2
6 changed files with 74 additions and 5 deletions

View File

@ -1475,7 +1475,8 @@ public:
ItemIsUserCheckable = 16,
ItemIsEnabled = 32,
ItemIsTristate = 64,
ItemNeverHasChildren = 128
ItemNeverHasChildren = 128,
ItemIsUserTristate = 256
};
Q_DECLARE_FLAGS(ItemFlags, ItemFlag)

View File

@ -2574,8 +2574,13 @@
\value ItemIsDropEnabled It can be used as a drop target.
\value ItemIsUserCheckable It can be checked or unchecked by the user.
\value ItemIsEnabled The user can interact with the item.
\value ItemIsTristate The item is checkable with three separate states.
\value ItemIsTristate The item can show three separate states.
This enables automatic management of the state of parent items in QTreeWidget
(checked if all children are checked, unchecked if all children are unchecked,
or partially checked if only some children are checked).
\value ItemNeverHasChildren The item never has child items.
\value ItemIsUserTristate The user can cycle through three separate states.
This value has been added in Qt 5.5.
Note that checkable items need to be given both a suitable set of flags
and an initial state, indicating whether the item is checked or not.

View File

@ -1182,7 +1182,7 @@ bool QItemDelegate::editorEvent(QEvent *event,
}
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
if (flags & Qt::ItemIsTristate)
if (flags & Qt::ItemIsUserTristate)
state = ((Qt::CheckState)((state + 1) % 3));
else
state = (state == Qt::Checked) ? Qt::Unchecked : Qt::Checked;

View File

@ -660,7 +660,7 @@ bool QStyledItemDelegate::editorEvent(QEvent *event,
}
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
if (flags & Qt::ItemIsTristate)
if (flags & Qt::ItemIsUserTristate)
state = ((Qt::CheckState)((state + 1) % 3));
else
state = (state == Qt::Checked) ? Qt::Unchecked : Qt::Checked;

View File

@ -1159,7 +1159,7 @@ void tst_QItemDelegate::editorEvent_data()
<< (int)(QEvent::MouseButtonRelease)
<< (int)(Qt::LeftButton)
<< true
<< (int)(Qt::PartiallyChecked);
<< (int)(Qt::Checked);
QTest::newRow("partially checked, tristate, release")
<< (int)(Qt::PartiallyChecked)
@ -1178,6 +1178,33 @@ void tst_QItemDelegate::editorEvent_data()
<< (int)(Qt::LeftButton)
<< true
<< (int)(Qt::Unchecked);
QTest::newRow("unchecked, user-tristate, release")
<< (int)(Qt::Unchecked)
<< (int)(defaultFlags | Qt::ItemIsUserTristate)
<< true
<< (int)(QEvent::MouseButtonRelease)
<< (int)(Qt::LeftButton)
<< true
<< (int)(Qt::PartiallyChecked);
QTest::newRow("partially checked, user-tristate, release")
<< (int)(Qt::PartiallyChecked)
<< (int)(defaultFlags | Qt::ItemIsUserTristate)
<< true
<< (int)(QEvent::MouseButtonRelease)
<< (int)(Qt::LeftButton)
<< true
<< (int)(Qt::Checked);
QTest::newRow("checked, user-tristate, release")
<< (int)(Qt::Checked)
<< (int)(defaultFlags | Qt::ItemIsUserTristate)
<< true
<< (int)(QEvent::MouseButtonRelease)
<< (int)(Qt::LeftButton)
<< true
<< (int)(Qt::Unchecked);
}
void tst_QItemDelegate::editorEvent()

View File

@ -129,6 +129,8 @@ private slots:
void task245280_sortChildren();
void task253109_itemHeight();
void nonEditableTristate();
// QTreeWidgetItem
void itemOperatorLessThan();
void addChild();
@ -3162,6 +3164,40 @@ void tst_QTreeWidget::task217309()
QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::Checked);
}
void tst_QTreeWidget::nonEditableTristate()
{
// A tree with checkable items, the parent is tristate
QTreeWidget *tree = new QTreeWidget;
QTreeWidgetItem *item = new QTreeWidgetItem();
tree->insertTopLevelItem(0, item);
item->setFlags(item->flags() | Qt::ItemIsTristate);
item->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subitem1 = new QTreeWidgetItem(item);
subitem1->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subitem2 = new QTreeWidgetItem(item);
subitem2->setCheckState(0, Qt::Unchecked);
QCOMPARE(int(item->checkState(0)), int(Qt::Unchecked));
tree->show();
// Test clicking on the parent item, it should become Checked (not PartiallyChecked)
QStyleOptionViewItem option;
option.rect = tree->visualRect(tree->model()->index(0, 0));
option.state |= QStyle::State_Enabled;
option.features |= QStyleOptionViewItem::HasCheckIndicator | QStyleOptionViewItem::HasDisplay;
option.checkState = item->checkState(0);
const int checkMargin = qApp->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, 0) + 1;
QPoint pos = qApp->style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &option, 0).center() + QPoint(checkMargin, 0);
QTest::mouseClick(tree->viewport(), Qt::LeftButton, Qt::NoModifier, pos);
QCOMPARE(int(item->checkState(0)), int(Qt::Checked));
// Click again, it should become Unchecked.
QTest::mouseClick(tree->viewport(), Qt::LeftButton, Qt::NoModifier, pos);
QCOMPARE(int(item->checkState(0)), int(Qt::Unchecked));
delete tree;
}
class TreeWidgetItem : public QTreeWidgetItem
{