Search code examples
qtdrag-and-dropqlistviewqsortfilterproxymodel

QListView external drop doesn't work


I'm trying to implement drag&drop items (plain/text) from one QListView to another. The dragging starts well (I even able to drop items to another applications that accept text drops), but my second QListView doesn't accept drops for some reason. Here is how the list view configured:

ui->lessonsListView->setAcceptDrops(true);
ui->lessonsListView->setDropIndicatorShown(true);
ui->lessonsListView->setDragDropMode(QAbstractItemView::DropOnly);
ui->lessonsListView->setDragDropOverwriteMode(true);

The proxy model for this listView implements the next methods:

Qt::ItemFlags LessonsProxyModel::flags(const QModelIndex &index) const
{
    qDebug() << __FUNCTION__;
    return Qt::ItemIsDropEnabled | QSortFilterProxyModel::flags(index);
}

Qt::DropActions LessonsProxyModel::supportedDropActions() const
{
    qDebug() << __FUNCTION__;
    return Qt::MoveAction;
}

bool LessonsProxyModel::canDropMimeData(const QMimeData *data,
    Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
    qDebug() << __FUNCTION__;
    Q_UNUSED(action);
    Q_UNUSED(row);
    Q_UNUSED(column);

    if (!data->hasFormat("text/plain") || !parent.isValid())
        return false;

    return true;
}

bool LessonsProxyModel::dropMimeData(const QMimeData *data,
    Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
    qDebug() << __FUNCTION__;
    if (!canDropMimeData(data, action, row, column, parent))
        return false;

    emit dataDropped(data, parent);

    return true;
}

From the application output I see that only supportedDropActions() and flags() are called. Neither canDropMimeData() nor dropMimeData() ever called. What am I doing wrong? Any hints will be appreciated.

Thank you!

EDITED:

Just in case: below is source code for listView and model from those drag is initiated: listView setup:

ui->abonsListView->setDragEnabled(true);

proxyModel code:

Qt::ItemFlags AbonsProxyModel::flags(const QModelIndex &index) const
{
    return Qt::ItemIsDragEnabled | QSortFilterProxyModel::flags(index);
}

Qt::DropActions AbonsProxyModel::supportedDragActions() const
{
    qDebug() << __FUNCTION__;
    return Qt::MoveAction;
}

QStringList AbonsProxyModel::mimeTypes() const
{
    qDebug() << __FUNCTION__;
    QStringList types;
    types << "text/plain";
    return types;
}

QMimeData *AbonsProxyModel::mimeData(const QModelIndexList &indexes) const
{
    qDebug() << __FUNCTION__;
    QMimeData *mimeData = new QMimeData();

    foreach (const QModelIndex &index, indexes)
        if (index.isValid())
        {
            mimeData->setText(data(index, AbonsModel::Id).toString());
            qDebug() << __FUNCTION__;
            return mimeData;
        }

    return mimeData;
}

Solution

  • I've finally found an answer! When I started writing this code I copypasted some pieces from Qt docs Using Drag and Drop with Item Views and in this article they just missed const specifier for reimplementation of canDropMimeData(). Hence my version of canDropMimeData() became non-virtual and QListView just called the method from base class QAbstractProxyModel. I've added const - and all is working like a charm without any subclassing.