Details
-
Bug
-
Status: Reported
-
P2: Important
-
Resolution: Unresolved
-
5.15.2
-
None
-
None
Description
When removing a model's row that has child row, and the QTreeView has editor opened for the child row created by a custom delegate, the overriding `destroyEditor()` function is not called for the child row. Although this function is called for the removed row(the parent), and both the editors are destructed later.
This is the test code:
class TreeModel : public QAbstractItemModel { public: struct MNode { MNode * parent; int self_row_num; std::vector<std::unique_ptr<MNode>> children; public: MNode(MNode * parent, int self_row_num) : parent(parent) , self_row_num(self_row_num) , children() {} }; private: std::unique_ptr<MNode> root_mnode; public: TreeModel() { root_mnode = std::make_unique<MNode>(nullptr, 0); //auto & l1_node = root_mnode->children.emplace_back(std::make_unique<MNode>(root_mnode.get(), 0)); //auto & l2_node = l1_node->children.emplace_back(std::make_unique<MNode>(l1_node.get(), 0)); } public: static MNode * retrieveMNodeFromIndex(QModelIndex const & index) { auto r = static_cast<MNode *>(index.internalPointer()); return r; } public: virtual QModelIndex index(int row, int column, QModelIndex const & parent = QModelIndex()) const override { if (row < 0 || column < 0) return QModelIndex(); if (column >= 1) return QModelIndex(); if (false == parent.isValid()) { if (row != 0) return QModelIndex(); return createIndex(0, column, static_cast<void *>(root_mnode.get())); } assert(parent.column() == 0);//Only the first column can be parent. auto parent_mnode = retrieveMNodeFromIndex(parent); assert(parent_mnode); if (row >= parent_mnode->children.size()) return QModelIndex(); return createIndex(row, column, static_cast<void *>(parent_mnode->children[row].get())); } virtual QModelIndex parent(QModelIndex const & index) const override { if (false == index.isValid()) return QModelIndex(); auto mnode = retrieveMNodeFromIndex(index); assert(mnode); auto parent_mnode = mnode->parent; if (!parent_mnode) return QModelIndex(); return createIndex(parent_mnode->self_row_num, 0, static_cast<void *>(parent_mnode)); } virtual int rowCount(QModelIndex const & parent = QModelIndex()) const override { if (false == parent.isValid()) return 1; if (parent.row() < 0) return 0; if (parent.column() != 0) return 0; auto parent_mnode = retrieveMNodeFromIndex(parent); assert(parent_mnode); return parent_mnode->children.size(); } virtual int columnCount(QModelIndex const & parent = QModelIndex()) const override { if (false == parent.isValid()) return 1; if (parent.row() < 0) return 0; if (parent.column() != 0) return 0; return 1; } virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override { if (orientation == Qt::Vertical) return QAbstractItemModel::headerData(section, orientation, role); if (role != Qt::DisplayRole) return QAbstractItemModel::headerData(section, orientation, role); if (section == 0) return "Data"; else return {}; } virtual QVariant data(QModelIndex const & index, int role = Qt::DisplayRole) const override { if (false == index.isValid()) return {}; if (role != Qt::DisplayRole) return {}; auto mnode = retrieveMNodeFromIndex(index); assert(mnode); if (index.column() == 0) return mnode->self_row_num; return {}; } public: virtual bool insertRows(int row, int count, const QModelIndex & parent = QModelIndex()) override { if (false == parent.isValid()) return false; if (row < 0) return false; if (count != 1) return false; auto parent_mnode = retrieveMNodeFromIndex(parent); assert(parent_mnode); if (row != parent_mnode->children.size()) return false; beginInsertRows(parent, row, row); parent_mnode->children.emplace_back(std::make_unique<MNode>(parent_mnode, row)); endInsertRows(); return true; } virtual bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex()) override { if (false == parent.isValid()) return false; if (row < 0) return false; if (count != 1) return false; auto parent_mnode = retrieveMNodeFromIndex(parent); assert(parent_mnode); if (row + 1 != parent_mnode->children.size()) return false; beginRemoveRows(parent, row, row); parent_mnode->children.pop_back(); endRemoveRows(); return true; } }; class MyLabel : public QLabel { std::vector<char> v; public: MyLabel(QWidget * parent = nullptr) : QLabel(parent) { v.resize(100 * 1024 * 1024); } ~MyLabel() { __nop();//for debug break point } }; class Delegate : public QItemDelegate { public: virtual QWidget * createEditor(QWidget * parent, QStyleOptionViewItem const & /*option*/, QModelIndex const & index) const override { __nop();//for debug break point auto mnode = TreeModel::retrieveMNodeFromIndex(index); auto r = new MyLabel(parent); r->setText(QString::number(mnode->self_row_num)); r->setAutoFillBackground(true); r->setFrameShape(QFrame::StyledPanel); r->setFrameShadow(QFrame::Sunken); return r; } virtual void destroyEditor(QWidget * editor, QModelIndex const & index) const override { __nop();//for debug break point return QItemDelegate::destroyEditor(editor, index); } }; int main(int argc, char ** argv) { QApplication app{ argc, argv }; int r = 0; TreeModel model; Delegate delegate; QTreeView view; view.setModel(&model); view.setItemDelegateForColumn(0, &delegate); auto index0 = model.index(0, 0, QModelIndex()); view.openPersistentEditor(index0); view.show(); QPushButton button; button.setText("Push Me"); QObject::connect(&button, &QPushButton::clicked, [&]() { model.insertRow(0, index0); auto index1 = model.index(0, 0, index0); view.openPersistentEditor(index1); model.insertRow(0, index1); auto index2 = model.index(0, 0, index1); view.openPersistentEditor(index2); model.removeRow(0, index0); }); button.show(); r = app.exec(); return r; }