Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-103476

Custom`Delegate::destroyEditor()` is not called for some editor when removing a tree branch

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Reported
    • Priority: P2: Important
    • Resolution: Unresolved
    • Affects Version/s: 5.15.2
    • Fix Version/s: None
    • Labels:
      None
    • Platform/s:
      Windows

      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;
      }
      
      

       

        Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

            Assignee:
            dfaure_kdab David Faure
            Reporter:
            zwhfly WH Z
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated:

                Gerrit Reviews

                There are no open Gerrit changes