QAbstractItemDelegate: tolerate that editor gets reparented
An item delegate might override destroyEditor to merely reparent the
existing editor out of the item view for later reuse, rather than
actually destroying the editor.
As of d0dffdfc01
, the code calling
closeEditor() - which calls destroyEditor - might explicitly set focus
back to the item view parent of the editor. This needs to handle that
the parent of the editor might no longer be valid after the closeEditor
call returns, and rather store the old parent widget explicitly.
Add a test case that segfaults with nullptr access without the fix.
Fixes: QTBUG-105231
Pick-to: 6.4 6.3 6.2
Change-Id: I04a355673823c4941865f7a575864e991ceeb5f0
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
parent
b134300bc4
commit
52f4d0b0d2
@ -480,12 +480,13 @@ bool QAbstractItemDelegatePrivate::editorEventFilter(QObject *object, QEvent *ev
|
||||
// If the application loses focus while editing, then the focus needs to go back
|
||||
// to the itemview when the editor closes. This ensures that when the application
|
||||
// is active again it will have the focus on the itemview as expected.
|
||||
QWidget *editorParent = editor->parentWidget();
|
||||
const bool manuallyFixFocus = (event->type() == QEvent::FocusOut) && !editor->hasFocus() &&
|
||||
editor->parentWidget() &&
|
||||
editorParent &&
|
||||
(static_cast<QFocusEvent *>(event)->reason() == Qt::ActiveWindowFocusReason);
|
||||
emit q->closeEditor(editor, QAbstractItemDelegate::NoHint);
|
||||
if (manuallyFixFocus)
|
||||
editor->parentWidget()->setFocus();
|
||||
editorParent->setFocus();
|
||||
}
|
||||
#ifndef QT_NO_SHORTCUT
|
||||
} else if (event->type() == QEvent::ShortcutOverride) {
|
||||
|
@ -205,6 +205,8 @@ private slots:
|
||||
void dateTextForRole_data();
|
||||
void dateTextForRole();
|
||||
|
||||
void reuseEditor();
|
||||
|
||||
private:
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
struct RoleDelegate : public QItemDelegate
|
||||
@ -1617,6 +1619,74 @@ void tst_QItemDelegate::dateTextForRole()
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QItemDelegate::reuseEditor()
|
||||
{
|
||||
class ReusingDelegate: public QItemDelegate {
|
||||
public:
|
||||
using QItemDelegate::QItemDelegate;
|
||||
~ReusingDelegate()
|
||||
{
|
||||
cached->deleteLater();
|
||||
}
|
||||
|
||||
QWidget* createEditor(QWidget* parent,
|
||||
const QStyleOptionViewItem&,
|
||||
const QModelIndex&) const override
|
||||
{
|
||||
auto *cb = new QComboBox(parent);
|
||||
cb->addItem("One");
|
||||
cb->addItem("Two");
|
||||
cb->setEditable(true);
|
||||
return cb;
|
||||
}
|
||||
|
||||
void setEditorData(QWidget* editor, const QModelIndex& index)
|
||||
const override
|
||||
{
|
||||
auto *cb = qobject_cast<QComboBox*>(editor);
|
||||
cb->setCurrentText(index.data(Qt::DisplayRole).toString());
|
||||
}
|
||||
|
||||
void setModelData(QWidget* editor,
|
||||
QAbstractItemModel* model,
|
||||
const QModelIndex& index) const override
|
||||
{
|
||||
auto *cb = qobject_cast<QComboBox*>(editor);
|
||||
model->setData(index, cb->currentText(), Qt::DisplayRole);
|
||||
}
|
||||
|
||||
void destroyEditor(QWidget* editor, const QModelIndex&) const override
|
||||
{
|
||||
auto *cb = qobject_cast<QComboBox*>(editor);
|
||||
cb->setParent(nullptr); // How to completely detach the editor from treeview ?
|
||||
cb->hide();
|
||||
cb->setEnabled(false);
|
||||
cached = cb;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable QComboBox* cached = nullptr;
|
||||
};
|
||||
|
||||
QStandardItemModel model;
|
||||
model.appendRow(new QStandardItem("One"));
|
||||
model.appendRow(new QStandardItem("Two"));
|
||||
|
||||
ReusingDelegate delegate;
|
||||
|
||||
QTreeView tree;
|
||||
tree.setModel(&model);
|
||||
tree.setItemDelegate(&delegate);
|
||||
|
||||
tree.show();
|
||||
QVERIFY(QTest::qWaitForWindowActive(&tree));
|
||||
|
||||
tree.edit(model.index(0, 0));
|
||||
QTRY_VERIFY(qobject_cast<QComboBox *>(tree.focusWidget()));
|
||||
|
||||
tree.close();
|
||||
}
|
||||
|
||||
// ### _not_ covered:
|
||||
|
||||
// editing with a custom editor factory
|
||||
|
Loading…
Reference in New Issue
Block a user