PDA

View Full Version : How to Drag and Drop working with tableview?



diginikkari
22nd October 2012, 10:14
I have tried to implement moving rows with by drag and drop in tableview with my custom model. I have read everything I have found regarding this, and I just don't get it to work with tableview. It's working perfectly with listview.

In tableview row is copied correctly, but removerows is not called. What I am missing? If I have to call removerows directly where should I do it. I would like to be able to use the same model with listview and tableview. I feel that I am missing something trivial, but I just don't get what.

Here is simplified example:


#include <QtGui>
#include "stringlistmodel.h"
#include <QAbstractItemModel>

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QStringList numbers;
numbers << "One" << "Two" << "Three" << "Four" << "Five";

QAbstractItemModel *model = new StringListModel(numbers);
QTableView *tableView = new QTableView;
QListView *listView = new QListView;
tableView->setSelectionMode(QAbstractItemView::ExtendedSelect ion);
tableView->setDragEnabled(true);
tableView->setAcceptDrops(true);
tableView->setDropIndicatorShown(true);
tableView->setModel(model);
tableView->setDefaultDropAction(Qt::MoveAction);
tableView->show();
listView->setDragEnabled(true);
listView->setAcceptDrops(true);
listView->setModel(model);
listView->setDefaultDropAction(Qt::MoveAction);
listView->show();
return app.exec();
}

This is my model header:


#ifndef STRINGLISTMODEL_H
#define STRINGLISTMODEL_H

#include <QAbstractListModel>
#include <QStringList>
#include <QMimeData>

class StringListModel : public QAbstractListModel
{
Q_OBJECT
public:
StringListModel(const QStringList &strings, QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole);
bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());
bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());

Qt::DropActions supportedDropActions() const;
QStringList mimeTypes() const;
QMimeData *mimeData(const QModelIndexList &indexes) const;
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
private:
QStringList stringList;

signals:

public slots:

};

#endif // STRINGLISTMODEL_H


and this is my model source:

#include "stringlistmodel.h"
#include <QStringListModel>
#include <QDebug>

StringListModel::StringListModel(const QStringList &strings, QObject *parent)
: QAbstractListModel(parent), stringList(strings)
{
}

int StringListModel::rowCount(const QModelIndex &parent) const
{
return stringList.count();
}

QVariant StringListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (index.row() >= stringList.size())
return QVariant();

if (role == Qt::DisplayRole || role == Qt::EditRole)
return stringList.at(index.row());
else
return QVariant();
}

QVariant StringListModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (role != Qt::DisplayRole)
return QVariant();

if (orientation == Qt::Horizontal)
return QString("Column %1").arg(section);
else
return QString("Row %1").arg(section);
}

Qt::ItemFlags StringListModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);

if (index.isValid())
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
else
return Qt::ItemIsDropEnabled | defaultFlags;
}

bool StringListModel::setData(const QModelIndex &index,
const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole) {

stringList.replace(index.row(), value.toString());
emit dataChanged(index, index);
return true;
}
return false;
}

bool StringListModel::insertRows(int position, int rows, const QModelIndex &parent)
{
beginInsertRows(QModelIndex(), position, position+rows-1);

for (int row = 0; row < rows; ++row) {
stringList.insert(position, "");
}

endInsertRows();
return true;
}

bool StringListModel::removeRows(int position, int rows, const QModelIndex &parent)
{
beginRemoveRows(QModelIndex(), position, position+rows-1);

for (int row = 0; row < rows; ++row) {
stringList.removeAt(position);
}

endRemoveRows();
return true;
}

Qt::DropActions StringListModel::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}

QStringList StringListModel::mimeTypes() const
{
QStringList types;
types << "application/vnd.text.list";
return types;
}

QMimeData *StringListModel::mimeData(const QModelIndexList &indexes) const
{
QMimeData *mimeData = new QMimeData();
QByteArray encodedData;

QDataStream stream(&encodedData, QIODevice::WriteOnly);

foreach (const QModelIndex &index, indexes) {
if (index.isValid()) {
QString text = data(index, Qt::DisplayRole).toString();
stream << text;
}
}

mimeData->setData("application/vnd.text.list", encodedData);
return mimeData;
}

bool StringListModel::dropMimeData(const QMimeData *data,
Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
qDebug() << action;
if (action == Qt::IgnoreAction)
return true;

if (!data->hasFormat("application/vnd.text.list"))
return false;

if (column > 0)
return false;
int beginRow;

if (row != -1)
beginRow = row;
else if (parent.isValid())
beginRow = parent.row();
else
beginRow = rowCount(QModelIndex());
QByteArray encodedData = data->data("application/vnd.text.list");
QDataStream stream(&encodedData, QIODevice::ReadOnly);
QStringList newItems;
int rows = 0;

while (!stream.atEnd()) {
QString text;
stream >> text;
newItems << text;
++rows;
}
insertRows(beginRow, rows, QModelIndex());
foreach (const QString &text, newItems) {
QModelIndex idx = index(beginRow, 0, QModelIndex());
setData(idx, text);
beginRow++;
}

return true;
}

norobro
22nd October 2012, 16:09
Try setting the dragDropOverWriteMode property to false on your table view. link (http://qt-project.org/doc/qt-4.8/qabstractitemview.html#dragDropOverwriteMode-prop)

diginikkari
22nd October 2012, 18:02
Thanks a lot! That was the solution.