mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 05:56:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			149 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			149 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;
 | 
						|
}
 |