You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
4.8 KiB
C++
150 lines
4.8 KiB
C++
#include <QMimeData>
|
|
#include <QBitArray>
|
|
|
|
#include <limits>
|
|
|
|
#include "pluginsmodel.hpp"
|
|
|
|
PluginsModel::PluginsModel(QObject *parent) : QStandardItemModel(parent)
|
|
{
|
|
|
|
}
|
|
|
|
void decodeDataRecursive(QDataStream &stream, QStandardItem *item)
|
|
{
|
|
int colCount, childCount;
|
|
stream >> *item;
|
|
stream >> colCount >> childCount;
|
|
item->setColumnCount(colCount);
|
|
|
|
int childPos = childCount;
|
|
|
|
while(childPos > 0) {
|
|
childPos--;
|
|
QStandardItem *child = new QStandardItem();
|
|
decodeDataRecursive(stream, child);
|
|
item->setChild( childPos / colCount, childPos % colCount, child);
|
|
}
|
|
}
|
|
|
|
bool PluginsModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
|
int row, int column, const QModelIndex &parent)
|
|
{
|
|
// Code largely based on QStandardItemModel::dropMimeData
|
|
|
|
// check if the action is supported
|
|
if (!data || !(action == Qt::CopyAction || action == Qt::MoveAction))
|
|
return false;
|
|
|
|
// check if the format is supported
|
|
QString format = QLatin1String("application/x-qstandarditemmodeldatalist");
|
|
if (!data->hasFormat(format))
|
|
return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
|
|
|
|
if (row > rowCount(parent))
|
|
row = rowCount(parent);
|
|
if (row == -1)
|
|
row = rowCount(parent);
|
|
if (column == -1)
|
|
column = 0;
|
|
|
|
// decode and insert
|
|
QByteArray encoded = data->data(format);
|
|
QDataStream stream(&encoded, QIODevice::ReadOnly);
|
|
|
|
|
|
//code based on QAbstractItemModel::decodeData
|
|
// adapted to work with QStandardItem
|
|
int top = std::numeric_limits<int>::max();
|
|
int left = std::numeric_limits<int>::max();
|
|
int bottom = 0;
|
|
int right = 0;
|
|
QVector<int> rows, columns;
|
|
QVector<QStandardItem *> items;
|
|
|
|
while (!stream.atEnd()) {
|
|
int r, c;
|
|
QStandardItem *item = new QStandardItem();
|
|
stream >> r >> c;
|
|
decodeDataRecursive(stream, item);
|
|
|
|
rows.append(r);
|
|
columns.append(c);
|
|
items.append(item);
|
|
top = qMin(r, top);
|
|
left = qMin(c, left);
|
|
bottom = qMax(r, bottom);
|
|
right = qMax(c, right);
|
|
}
|
|
|
|
// insert the dragged items into the table, use a bit array to avoid overwriting items,
|
|
// since items from different tables can have the same row and column
|
|
int dragRowCount = 0;
|
|
int dragColumnCount = right - left + 1;
|
|
|
|
// Compute the number of continuous rows upon insertion and modify the rows to match
|
|
QVector<int> rowsToInsert(bottom + 1);
|
|
for (int i = 0; i < rows.count(); ++i)
|
|
rowsToInsert[rows.at(i)] = 1;
|
|
for (int i = 0; i < rowsToInsert.count(); ++i) {
|
|
if (rowsToInsert[i] == 1){
|
|
rowsToInsert[i] = dragRowCount;
|
|
++dragRowCount;
|
|
}
|
|
}
|
|
for (int i = 0; i < rows.count(); ++i)
|
|
rows[i] = top + rowsToInsert[rows[i]];
|
|
|
|
QBitArray isWrittenTo(dragRowCount * dragColumnCount);
|
|
|
|
// make space in the table for the dropped data
|
|
int colCount = columnCount(parent);
|
|
if (colCount < dragColumnCount + column) {
|
|
insertColumns(colCount, dragColumnCount + column - colCount, parent);
|
|
colCount = columnCount(parent);
|
|
}
|
|
insertRows(row, dragRowCount, parent);
|
|
|
|
row = qMax(0, row);
|
|
column = qMax(0, column);
|
|
|
|
QStandardItem *parentItem = itemFromIndex (parent);
|
|
if (!parentItem)
|
|
parentItem = invisibleRootItem();
|
|
|
|
QVector<QPersistentModelIndex> newIndexes(items.size());
|
|
// set the data in the table
|
|
for (int j = 0; j < items.size(); ++j) {
|
|
int relativeRow = rows.at(j) - top;
|
|
int relativeColumn = columns.at(j) - left;
|
|
int destinationRow = relativeRow + row;
|
|
int destinationColumn = relativeColumn + column;
|
|
int flat = (relativeRow * dragColumnCount) + relativeColumn;
|
|
// if the item was already written to, or we just can't fit it in the table, create a new row
|
|
if (destinationColumn >= colCount || isWrittenTo.testBit(flat)) {
|
|
destinationColumn = qBound(column, destinationColumn, colCount - 1);
|
|
destinationRow = row + dragRowCount;
|
|
insertRows(row + dragRowCount, 1, parent);
|
|
flat = (dragRowCount * dragColumnCount) + relativeColumn;
|
|
isWrittenTo.resize(++dragRowCount * dragColumnCount);
|
|
}
|
|
if (!isWrittenTo.testBit(flat)) {
|
|
newIndexes[j] = index(destinationRow, destinationColumn, parentItem->index());
|
|
isWrittenTo.setBit(flat);
|
|
}
|
|
}
|
|
|
|
for(int k = 0; k < newIndexes.size(); k++) {
|
|
if (newIndexes.at(k).isValid()) {
|
|
parentItem->setChild(newIndexes.at(k).row(), newIndexes.at(k).column(), items.at(k));
|
|
} else {
|
|
delete items.at(k);
|
|
}
|
|
}
|
|
|
|
// The important part, tell the view what is dropped
|
|
emit indexesDropped(newIndexes);
|
|
|
|
return true;
|
|
}
|