diff --git a/src/gui/itemmodels/qstandarditemmodel.cpp b/src/gui/itemmodels/qstandarditemmodel.cpp index a972b7b1069..675b71c5301 100644 --- a/src/gui/itemmodels/qstandarditemmodel.cpp +++ b/src/gui/itemmodels/qstandarditemmodel.cpp @@ -1893,10 +1893,35 @@ QStandardItem *QStandardItem::takeChild(int row, int column) QStandardItem *item = nullptr; int index = d->childIndex(row, column); if (index != -1) { + QModelIndex changedIdx; item = d->children.at(index); - if (item) - item->d_func()->setParentAndModel(nullptr, nullptr); + if (item && d->model) { + QStandardItemPrivate *const item_d = item->d_func(); + const int savedRows = item_d->rows; + const int savedCols = item_d->columns; + const QVector savedChildren = item_d->children; + if (savedRows > 0) { + d->model->d_func()->rowsAboutToBeRemoved(item, 0, savedRows - 1); + item_d->rows = 0; + item_d->children = QVector(); //slightly faster than clear + d->model->d_func()->rowsRemoved(item, 0, savedRows); + } + if (savedCols > 0) { + d->model->d_func()->columnsAboutToBeRemoved(item, 0, savedCols - 1); + item_d->columns = 0; + if (!item_d->children.isEmpty()) + item_d->children = QVector(); //slightly faster than clear + d->model->d_func()->columnsRemoved(item, 0, savedCols); + } + item_d->rows = savedRows; + item_d->columns = savedCols; + item_d->children = savedChildren; + changedIdx = d->model->indexFromItem(item); + item_d->setParentAndModel(nullptr, nullptr); + } d->children.replace(index, nullptr); + if (changedIdx.isValid()) + d->model->dataChanged(changedIdx, changedIdx); } return item; } diff --git a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp index 343150d25d9..7fc2c473ded 100644 --- a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp +++ b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp @@ -137,7 +137,7 @@ private slots: void taskQTBUG_45114_setItemData(); void setItemPersistentIndex(); - + void signalsOnTakeItem(); private: QStandardItemModel *m_model = nullptr; QPersistentModelIndex persistent; @@ -1738,5 +1738,52 @@ void tst_QStandardItemModel::setItemPersistentIndex() QVERIFY(!persistentIndex.isValid()); } +void tst_QStandardItemModel::signalsOnTakeItem() // QTBUG-89145 +{ + QStandardItemModel m; + m.insertColumns(0, 2); + m.insertRows(0, 5); + for (int i = 0; i < m.rowCount(); ++i) { + for (int j = 0; j < m.columnCount(); ++j) + m.setData(m.index(i, j), i + j); + } + const QModelIndex parentIndex = m.index(1, 0); + m.insertColumns(0, 2, parentIndex); + m.insertRows(0, 2, parentIndex); + for (int i = 0; i < m.rowCount(parentIndex); ++i) { + for (int j = 0; j < m.columnCount(parentIndex); ++j) + m.setData(m.index(i, j, parentIndex), i + j + 100); + } + QAbstractItemModelTester mTester(&m, nullptr); + QSignalSpy columnsRemovedSpy(&m, &QAbstractItemModel::columnsRemoved); + QSignalSpy columnsAboutToBeRemovedSpy(&m, &QAbstractItemModel::columnsAboutToBeRemoved); + QSignalSpy rowsRemovedSpy(&m, &QAbstractItemModel::rowsRemoved); + QSignalSpy rowsAboutToBeRemovedSpy(&m, &QAbstractItemModel::rowsAboutToBeRemoved); + QSignalSpy *const removeSpies[] = {&columnsRemovedSpy, &columnsAboutToBeRemovedSpy, &rowsRemovedSpy, &rowsAboutToBeRemovedSpy}; + QSignalSpy dataChangedSpy(&m, &QAbstractItemModel::dataChanged); + QStandardItem *const takenItem = m.takeItem(1, 0); + for (auto &&spy : removeSpies) { + QCOMPARE(spy->count(), 1); + const auto spyArgs = spy->takeFirst(); + QCOMPARE(spyArgs.at(0).value(), parentIndex); + QCOMPARE(spyArgs.at(1).toInt(), 0); + QCOMPARE(spyArgs.at(2).toInt(), 1); + } + QCOMPARE(dataChangedSpy.count(), 1); + const auto dataChangedSpyArgs = dataChangedSpy.takeFirst(); + QCOMPARE(dataChangedSpyArgs.at(0).value(), m.index(1, 0)); + QCOMPARE(dataChangedSpyArgs.at(1).value(), m.index(1, 0)); + QCOMPARE(takenItem->data(Qt::EditRole).toInt(), 1); + QCOMPARE(takenItem->rowCount(), 2); + QCOMPARE(takenItem->columnCount(), 2); + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) + QCOMPARE(takenItem->child(i, j)->data(Qt::EditRole).toInt(), i + j + 100); + } + QCOMPARE(takenItem->model(), nullptr); + QCOMPARE(takenItem->child(0, 0)->model(), nullptr); + QCOMPARE(m.index(1, 0).data(), QVariant()); +} + QTEST_MAIN(tst_QStandardItemModel) #include "tst_qstandarditemmodel.moc"