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

QListView item looses items from models that don't override moveRows during internal drag'n'drop

    XMLWordPrintable

Details

    • 0f1008a5936c903ca9448193df7df6117e2c617b (qt/qtbase/dev) e356239397def8540ca2ec82274830a6c980a1a7 (qt/qtbase/5.15)

    Description

      With the following example running against Qt 5.15.1, moving items around via internal drag'n'drop loses the moved item. Running the same example against 5.15.0 does not. This regression was introduced in fd894fd68edf3d67975cda8eb9dda43646887b0d.

      #include <QApplication>
      #include <QAbstractListModel>
      #include <QStringList>
      #include <QListView>
      
      class ListModel : public QAbstractListModel
      {
      public:
          ListModel(QObject * parent = nullptr)
              : QAbstractListModel {parent}
              , list {"A", "B", "C", "D"}
          {
          }
      
      protected:
          int rowCount(QModelIndex const& index = QModelIndex {}) const override
          {
              return index.isValid() ? 0 : list.size();
          }
      
          QVariant data(QModelIndex const& index, int role) const override
          {
              QVariant result;
              if (Qt::DisplayRole == role) result = list[index.row()];
              return result;
          }
      
          Qt::ItemFlags flags(QModelIndex const& index) const override
          {
              auto flags = QAbstractListModel::flags(index) | Qt::ItemIsDragEnabled;
              if (!index.isValid()) flags |= Qt::ItemIsDropEnabled;
              return flags;
          }
      
          bool setData(QModelIndex const& index, QVariant const& value, int role = Qt::EditRole) override
          {
              if (index.isValid() && index.row() < rowCount() && Qt::DisplayRole == role)
              {
                  list[index.row ()] = value.toString();
                  Q_EMIT dataChanged(index, index, QVector<int> {role});
                  return true;
              }
              return false;
          }
      
          Qt::DropActions supportedDropActions() const override {return Qt::MoveAction;}
      
          bool insertRows(int row, int count, QModelIndex const& parent = QModelIndex {}) override
          {
              beginInsertRows(parent, row, row + count - 1);
              for (int i = 0; i < count; ++i) list.insert(row, {});
              endInsertRows();
              return true;
          }
      
          bool removeRows(int row, int count, QModelIndex const& parent = QModelIndex {}) override
          {
              beginRemoveRows(parent, row, row + count - 1);
              for (int index = 0; index < count; ++index) list.removeAt(row);
              endRemoveRows();
              return true;
          }
      
      private:
          QStringList list;
      };
      
      int main (int argc, char * argv[])
      {
          QApplication controller {argc, argv};
          ListModel model;
          QListView view;
          view.setModel (&model);
          view.setDragDropMode (QListView::InternalMove);
          view.show ();
          return controller.exec ();
      }
      

      The problem is that dropEvent, which in 5.15.1 is implemented in QListView (rather than only QListWidget) to move rows around, only tries to move the rows via moveRows. If the model doesn't implement moveRows (ie returns false), then the event is nevertheless accepted.

      In 5.15.0, the default dropEvent implementation in QAbstractItemView was used with an unaccepted event, which used QAbstractItemModel::dropMimeData rather than moveRows.

      Attachments

        Issue Links

          For Gerrit Dashboard: QTBUG-87057
          # Subject Branch Project Status CR V

          Activity

            People

              vhilshei Volker Hilsheimer
              vhilshei Volker Hilsheimer
              Votes:
              1 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: