Files
qt6-migration-pipeline/Z/src/nglwidgets/ngltreemodel.cpp
T
2026-07-14 12:07:36 +02:00

459 lines
11 KiB
C++
Executable File

#include "ngltreemodel.h"
#include "ngltreeitem.h"
#include <QtCore/QHash>
#include <QtCore/QMetaType>
#include <QtCore/QMimeData>
#include <QtCore/QDebug>
#include <QtGui/QIcon>
NGLTreeModel::NGLTreeModel(QObject *parent, NGLTreeItem *rootItem,
const QStringList &titles)
: QAbstractItemModel(parent)
, m_rootItem(rootItem)
, m_titles(titles)
, m_mimeType(QStringLiteral("NGLTreeModel/dragDrop"))
, m_bMimeDataWithicon(true)
{
connect(this, &NGLTreeModel::dataChanged,
this, &NGLTreeModel::modelDataChanged);
connect(this, &NGLTreeModel::rowsInserted,
this, &NGLTreeModel::modelDataChanged);
connect(this, &NGLTreeModel::rowsMoved,
this, &NGLTreeModel::modelDataChanged);
connect(this, &NGLTreeModel::rowsRemoved,
this, &NGLTreeModel::modelDataChanged);
}
NGLTreeModel::~NGLTreeModel()
{
resetModel();
delete m_rootItem;
}
void NGLTreeModel::setRootItem(NGLTreeItem *rootItem)
{
resetModel();
delete m_rootItem;
m_rootItem = nullptr;
beginResetModel();
endResetModel();
m_rootItem = rootItem;
}
NGLTreeItem *NGLTreeModel::getRootItem() const
{
return m_rootItem;
}
NGLTreeItem *NGLTreeModel::createItem(const QVariant &data, const QIcon &icon) const
{
return new NGLTreeItem(data, icon);
}
void NGLTreeModel::resetModel()
{
if (m_rootItem)
{
beginResetModel();
m_rootItem->removeAllChildren();
endResetModel();
}
}
Qt::ItemFlags NGLTreeModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
if (index.isValid())
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
return defaultFlags;
}
QVariant NGLTreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
if ((section >= 0) && (section < m_titles.size()))
return m_titles.at(section);
}
return QVariant();
}
QModelIndex NGLTreeModel::index(int row, int column,
const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
{
return QModelIndex();
}
NGLTreeItem *parentItem = privateData(parent);
NGLTreeItem *childItem = parentItem->child(row);
if (childItem)
{
return createIndex(row, column, childItem);
}
return QModelIndex();
}
QModelIndex NGLTreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
NGLTreeItem *childItem = privateData(index);
NGLTreeItem *parentItem = childItem->parent();
if (!parentItem || parentItem == m_rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
int NGLTreeModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_titles.size();
}
int NGLTreeModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0)
return 0;
NGLTreeItem *ti = privateData(parent);
if (!ti)
return 0;
return ti->childCount();
}
bool NGLTreeModel::setData(const QModelIndex &index, const QVariant &value,
int role)
{
Q_UNUSED(index)
Q_UNUSED(value)
Q_UNUSED(role)
return false;
}
void NGLTreeModel::setMimeType(const QString &mimeType)
{
m_mimeType = mimeType;
}
void NGLTreeModel::resetModifedFlag(NGLTreeItem *rootItem)
{
if (!rootItem)
return;
rootItem->setModified(false);
for (int i = 0; i < rootItem->childCount(); ++i)
resetModifedFlag(rootItem->child(i));
}
bool NGLTreeModel::setItemData(const QModelIndex &index, const QVariant &value,
const QIcon &icon)
{
if (!index.isValid())
return false;
NGLTreeItem *item = privateData(index);
item->setData(value);
item->setIcon(icon);
item->setModified(true);
emit dataChanged(index, index);
return true;
}
QVariant NGLTreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role == Qt::DecorationRole)
{
if (index.column() == 0)
{
NGLTreeItem *item = privateData(index);
if (item)
return item->icon();
}
}
return QVariant();
}
QMimeData *NGLTreeModel::mimeData(const QModelIndexList &indexes) const
{
return getMimeData(indexes, m_mimeType);
}
QMimeData *NGLTreeModel::getMimeData(const QModelIndexList &indexes,
const QString &mimeType) const
{
QMimeData *mimeData = new QMimeData();
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
stream << m_bMimeDataWithicon;
bool dataStreamed = false;
for (const QModelIndex &index : indexes)
{
if (index.isValid() && (index.column() == 0))
{
streamAddChilds(stream, privateData(index));
dataStreamed = true;
}
}
if (dataStreamed)
mimeData->setData(mimeType, encodedData);
return mimeData;
}
void NGLTreeModel::streamAddChilds(QDataStream &stream, const NGLTreeItem *item) const
{
stream << qint64(item->parent()) << qint64(item) << getItemData(item);
if (m_bMimeDataWithicon)
stream << item->icon();
for (int i = 0; i < item->childCount(); i++)
streamAddChilds(stream, item->child(i));
}
bool NGLTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent)
{
qDebug() << "dropMimeData: action = " << action
<< ", row = " << row
<< ", column = " << column
<< ", parent: valid = " << parent.isValid();
if ((action != Qt::MoveAction) && (action != Qt::CopyAction))
return false;
if (!data->hasFormat(m_mimeType))
return false;
int beginRow;
QModelIndex parentR;
if (row != -1)
{
parentR = parent;
beginRow = row;
}
else if (parent.isValid())
{
parentR = parent;
beginRow = rowCount(parentR);
}
else
{
parentR = QModelIndex();
beginRow = rowCount(parentR);
}
return insertMimeData(data, m_mimeType, parentR, beginRow);
}
bool NGLTreeModel::insertMimeData(const QMimeData *data, const QString &mimeType,
QModelIndex parentR, int beginRow)
{
bool bStreamContainsIcons;
QByteArray encodedData = data->data(mimeType);
QDataStream stream(&encodedData, QIODevice::ReadOnly);
qint64 idParent, idItem;
QHash<qint64, QModelIndex> rowCache;
QVariant itemData;
QIcon icon;
stream >> bStreamContainsIcons;
bool first = true;
qint64 prevIdParent = 0;
while (!stream.atEnd())
{
stream >> idParent >> idItem >> itemData;
if (bStreamContainsIcons)
stream >> icon;
NGLTreeItem *item = createItem(itemData, icon);
if (first)
{
first = false;
rowCache.insert(idParent, parentR);
}
else if (idParent == prevIdParent)
{
parentR = rowCache[idParent];
beginRow++;
}
else
{
parentR = rowCache[idParent];
beginRow = privateData(rowCache[idParent])->childCount();
}
prevIdParent = idParent;
if (!insertRow(beginRow, parentR, item))
{
delete item;
return false;
}
rowCache.insert(idItem, index(beginRow, 0, parentR));
emit signalDataDropped(beginRow, parentR);
}
return true;
}
QVector<NGLTreeItem*> NGLTreeModel::getMimeDataItems(const QMimeData *data,
const QString &mimeType) const
{
QVector<NGLTreeItem*> ret;
QByteArray encodedData = data->data(mimeType);
QDataStream stream(&encodedData, QIODevice::ReadOnly);
qint64 idParent, idItem;
QVariant itemData;
QIcon icon;
bool bStreamContainsIcons;
stream >> bStreamContainsIcons;
while (!stream.atEnd())
{
stream >> idParent >> idItem >> itemData;
if (bStreamContainsIcons)
stream >> icon;
ret += createItem(itemData, icon);
}
return ret;
}
NGLTreeItem *NGLTreeModel::privateData(const QModelIndex &index) const
{
if (!index.isValid())
return m_rootItem;
Q_ASSERT(index.model() == this);
return static_cast<NGLTreeItem *>(index.internalPointer());
}
bool NGLTreeModel::moveRow(const QModelIndex &sourceParent, int sourceRow,
const QModelIndex &destParent, int destRow)
{
Q_ASSERT(sourceParent.column() == 0 || !sourceParent.isValid());
Q_ASSERT(destParent.column() == 0 || !destParent.isValid());
NGLTreeItem *sourceParentItem = privateData(sourceParent);
NGLTreeItem *destParentItem = privateData(destParent);
if ((sourceRow >= 0) && (sourceRow < sourceParentItem->childCount()) &&
(destRow >= 0) && (destRow < destParentItem->childCount()))
{
beginRemoveRows(sourceParent, sourceRow, sourceRow);
NGLTreeItem *item = sourceParentItem->takeChild(sourceRow);
endRemoveRows();
if (item)
{
beginInsertRows(destParent, destRow, destRow);
bool ret = destParentItem->insertChild(destRow, item);
endInsertRows();
return ret;
}
}
return false;
}
bool NGLTreeModel::removeRows(int row, int count, const QModelIndex &parent)
{
qDebug() << "removeRows: row = " << row << ", "
<< "count = " << count;
NGLTreeItem *parentItem = privateData(parent);
if ((row < 0 && row >= parentItem->childCount()) || count <= 0)
return false;
Q_ASSERT(parent.column() == 0 || !parent.isValid());
if (parent.column() != 0 && parent.isValid())
return false;
beginRemoveRows(parent, row, row + count - 1);
bool ret = parentItem->removeChildren(row, count);
if (ret)
{
for (int r = row; r < parentItem->childCount(); ++r)
parentItem->child(r)->setModified(true);
}
endRemoveRows();
return ret;
}
bool NGLTreeModel::insertRow(int row, const QModelIndex &parent, NGLTreeItem *item)
{
NGLTreeItem *parentItem = privateData(parent);
if (!parentItem)
return false;
Q_ASSERT(parent.column() == 0 || !parent.isValid());
if (parent.column() != 0 && parent.isValid())
return false;
parentItem->setModified(true);
beginInsertRows(parent, row, row);
bool ret = parentItem->insertChild(row, item);
for (int r = row; r < parentItem->childCount(); ++r)
parentItem->child(r)->setModified(true);
endInsertRows();
return ret;
}
QModelIndex NGLTreeModel::indexFromItem(const NGLTreeItem *item, int column) const
{
if (item == m_rootItem || item == nullptr)
return QModelIndex();
const NGLTreeItem *parent = item->parent();
const QModelIndex parentIdx = indexFromItem(parent);
return index(item->row(), column, parentIdx);
}
QVariant NGLTreeModel::getItemData(const NGLTreeItem *item) const
{
return item->data();
}