需求
QTreeview中需要显示多个不同根路径的节点
为什么需要开发
如果是使用单节点,通过过滤的方式隐藏其他目录节点,在setRootPath后,其他不显示的文件夹和文件发生变化都会监听到,导致性能浪费。如果仿照QFileSystemModel单独实现一个多root的model,代价比较高,开发周期过长。
整理逻辑
QFileSystemModel只能监听一个rootPath,局限比较大。当需要监听多个rootPath的时候,则需要使用多个model,多root方案是自定义一个QAbstractItemModel,将多个model进行管理和映射来实现,类似于proxymodel。
代码
#ifndef FOLDERLISTMODEL_H
#define FOLDERLISTMODEL_H
#include <QAbstractItemModel>
#include <QFileSystemModel>
#include <QItemSelection>
#include <QModelIndex>
#include "utils_global.h"
class QFileSystemWatcher;
struct SourceModel
{
QFileSystemModel *model;
QString rootPath;
// 用于监听当前model,如果当前这个model在本地删除了,要将其移除
QString watchPath;
// 实际在view中的位置
QModelIndex rootIndex;
// setRootPath后的index
QModelIndex rootSourceIndex;
};
class MultiFolderModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit MultiFolderModel(QObject *parent = nullptr);
virtual ~MultiFolderModel();
void clear();
QModelIndex addRootPath(const QString &path);
QModelIndex insertRootPath(int targetIndex, const QString &path);
QModelIndex refreshRoot(const QModelIndex &index);
void removeRootPath(const QString &path);
void removeRoot(const QModelIndex &index);
bool isRootPath(const QString &path);
QList<QModelIndex> rootIndexs() const;
QStringList rootPathList() const;
QString filePath(const QModelIndex &index) const;
QString fileName(const QModelIndex &index) const;
QFileInfo fileInfo(const QModelIndex &index) const;
bool isDir(const QModelIndex &index) const;
QModelIndex mkdir(const QModelIndex &parent, const QString &name);
bool rmdir(const QModelIndex &index);
bool remove(const QModelIndex &index);
void setFilter(QDir::Filters filters);
QDir::Filters filter() const;
void setNameFilters(const QStringList &filters);
QStringList nameFilters() const;
void setNameFilterDisables(bool enable);
bool nameFilterDisables() const;
void setResolveSymlinks(bool enable);
bool resolveSymlinks() const;
bool isRootIndex(const QModelIndex &index) const;
void setWatcherRoot(bool b);
QList<QModelIndex> indexForPath(const QString &path) const;
QModelIndex indexForPath(QFileSystemModel *model, const QString &path) const;
QModelIndex rootIndex(const QModelIndex &index) const;
void topRootPath(const QModelIndex &index);
Q_SIGNALS:
void directoryLoaded(QFileSystemModel *model, const QString &path);
void fileRenamed(const QString &path, const QString &oldName, const QString &newName);
void rootRemoved(const QString &path);
protected:
QFileSystemModel *findSource(const QModelIndex &proxyIndex) const;
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const;
QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection) const;
bool isRootSourceIndex(const QModelIndex &sourceIndex) const;
void resort();
public:
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value,
int role = Qt::EditRole) override;
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
QSize span(const QModelIndex &index) const override;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;
bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
public Q_SLOTS:
void directoryChanged(const QString &path);
void sourceRowsInserted(const QModelIndex &, int, int);
void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int);
void sourceRowsRemoved(const QModelIndex &, int, int);
void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceColumnsAboutToBeInserted(const QModelIndex &, int, int);
void sourceColumnsInserted(const QModelIndex &, int, int);
void sourceColumnsAboutToBeRemoved(const QModelIndex &, int, int);
void sourceColumnsRemoved(const QModelIndex &, int, int);
void sourceColumnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceColumnsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceDataChanged(const QModelIndex &, const QModelIndex &);
void sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last);
void sourceLayoutAboutToBeChanged();
void sourceLayoutChanged();
void sourceModelAboutToBeReset();
void sourceModelReset();
protected:
QList<SourceModel> m_modelList;
mutable QHash<qint64, QAbstractItemModel *> m_indexMap;
QList<QPersistentModelIndex> layoutChangePersistentIndexes;
QModelIndexList proxyIndexes;
QFileSystemWatcher *m_watcher = nullptr;
QDir::Filters m_filters = QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs;
QStringList m_nameFilters;
bool m_resolveSymlinks = false;
bool m_nameFilterDisables = true;
};
#endif // FOLDERLISTMODEL_H
#include "multifoldermodel.h"
#include <QCollator>
#include <QDebug>
#include <QFileSystemWatcher>
#include <QSortFilterProxyModel>
class FileSystemModelEx : public QFileSystemModel
{
public:
using QFileSystemModel::QFileSystemModel;
Qt::ItemFlags flags(const QModelIndex &index) const override
{
return QFileSystemModel::flags(index) | Qt::ItemIsEditable;
}
QModelIndex createIndex(int arow, int acolumn, void *adata) const
{
return QFileSystemModel::createIndex(arow, acolumn, adata);
}
};
MultiFolderModel::MultiFolderModel(QObject *parent)
: QAbstractItemModel(parent)
{ }
MultiFolderModel::~MultiFolderModel() = default;
void MultiFolderModel::clear()
{
if (m_modelList.isEmpty()) {
return;
}
this->beginRemoveRows(QModelIndex(), 0, m_modelList.size());
this->removeRows(0, m_modelList.size());
if (m_watcher) {
for (auto &s : m_modelList) {
m_watcher->removePath(s.watchPath);
}
}
for (auto &s : m_modelList) {
delete s.model;
}
m_modelList.clear();
m_indexMap.clear();
this->endRemoveRows();
}
QModelIndex MultiFolderModel::addRootPath(const QString &path)
{
int index = this->m_modelList.size();
return this->insertRootPath(index, path);
}
QModelIndex MultiFolderModel::insertRootPath(int targetIndex, const QString &path)
{
if (!QDir(path).exists()) {
return QModelIndex();
}
auto model = new FileSystemModelEx(this);
model->setFilter(m_filters);
if (!m_nameFilters.isEmpty()) {
model->setNameFilters(m_nameFilters);
}
model->setNameFilterDisables(m_nameFilterDisables);
model->setResolveSymlinks(m_resolveSymlinks);
QModelIndex sourceIndex = model->setRootPath(path);
if (!sourceIndex.isValid()) {
return sourceIndex;
}
SourceModel m;
m.model = model;
m.rootPath = QDir::cleanPath(QDir::fromNativeSeparators(path));
m.watchPath = model->filePath(sourceIndex.parent());
if (m_watcher && !m_watcher->directories().contains(m.watchPath)) {
m_watcher->addPath(m.watchPath);
}
m.rootSourceIndex = sourceIndex;
m.rootIndex = createIndex(targetIndex, 0, sourceIndex.internalPointer());
m_indexMap.insert(sourceIndex.internalId(), model);
for (int i = targetIndex; i < m_modelList.size(); i++) {
auto model = m_modelList.at(i);
model.rootIndex = createIndex(model.rootIndex.row() + 1, 0, sourceIndex.internalPointer());
}
m_modelList.insert(targetIndex, m);
connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int)));
connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
connect(
model, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
connect(model, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
connect(model, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)),
SLOT(sourceColumnsAboutToBeInserted(const QModelIndex &, int, int)));
connect(model, SIGNAL(columnsInserted(const QModelIndex &, int, int)),
SLOT(sourceColumnsInserted(const QModelIndex &, int, int)));
connect(model, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)),
SLOT(sourceColumnsAboutToBeRemoved(const QModelIndex &, int, int)));
connect(model, SIGNAL(columnsRemoved(const QModelIndex &, int, int)),
SLOT(sourceColumnsRemoved(const QModelIndex &, int, int)));
connect(
model,
SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
SLOT(sourceColumnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
connect(model, SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
SLOT(sourceColumnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
connect(model, SIGNAL(modelAboutToBeReset()), SLOT(sourceModelAboutToBeReset()));
connect(model, SIGNAL(modelReset()), SLOT(sourceModelReset()));
connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &)));
connect(model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)),
SLOT(sourceHeaderDataChanged(Qt::Orientation, int, int)));
connect(model, SIGNAL(layoutAboutToBeChanged()), SLOT(sourceLayoutAboutToBeChanged()));
connect(model, SIGNAL(layoutChanged()), SLOT(sourceLayoutChanged()));
connect(model, &QFileSystemModel::directoryLoaded, this,
[=](const QString &path) { Q_EMIT directoryLoaded(model, path); });
connect(model, &QFileSystemModel::fileRenamed, this,
[=](const QString &path, const QString &oldName, const QString &newName) {
this->resort();
Q_EMIT fileRenamed(path, oldName, newName);
});
return m.rootIndex;
}
QModelIndex MultiFolderModel::refreshRoot(const QModelIndex &index)
{
// 刷新root需要先记录旧的索引,将旧的移除,然后将新的重新插入到对应索引的位置
int pos = index.row();
auto path = this->filePath(index);
this->removeRoot(index);
return this->insertRootPath(pos, path);
}
void MultiFolderModel::removeRootPath(const QString &path)
{
QString rootPath = QDir::cleanPath(QDir::fromNativeSeparators(path));
QModelIndex index;
for (auto &s : m_modelList) {
if (s.rootPath == rootPath) {
index = s.rootIndex;
break;
}
}
if (index.isValid()) {
removeRoot(index);
}
}
void MultiFolderModel::removeRoot(const QModelIndex &index)
{
QMutableListIterator<SourceModel> i(m_modelList);
while (i.hasNext()) {
SourceModel s = i.next();
if (s.rootIndex.internalId() == index.internalId()) {
this->beginRemoveRows(QModelIndex(), index.row(), index.row());
if (m_watcher) {
m_watcher->removePath(s.watchPath);
}
this->removeRow(index.row());
i.remove();
this->endRemoveRows();
QMutableHashIterator<qint64, QAbstractItemModel *> i2(m_indexMap);
while (i2.hasNext()) {
i2.next();
if (i2.value() == s.model) {
i2.remove();
}
}
delete s.model;
break;
}
}
}
bool MultiFolderModel::isRootPath(const QString &path)
{
QString rootPath = QDir::cleanPath(QDir::fromNativeSeparators(path));
for (auto &s : m_modelList) {
if (s.rootPath == rootPath) {
return true;
}
}
return false;
}
QList<QModelIndex> MultiFolderModel::rootIndexs() const
{
QList<QModelIndex> indexs;
for (auto &s : m_modelList) {
indexs.append(s.rootIndex);
}
return indexs;
}
QStringList MultiFolderModel::rootPathList() const
{
QStringList paths;
for (auto &s : m_modelList) {
paths.append(s.rootPath);
}
return paths;
}
QFileSystemModel *MultiFolderModel::findSource(const QModelIndex &proxyIndex) const
{
return (QFileSystemModel *)m_indexMap[proxyIndex.internalId()];
}
QItemSelection MultiFolderModel::mapSelectionToSource(const QItemSelection &proxySelection) const
{
QModelIndexList proxyIndexes = proxySelection.indexes();
QItemSelection sourceSelection;
for (int i = 0; i < proxyIndexes.size(); ++i) {
const QModelIndex proxyIdx = mapToSource(proxyIndexes.at(i));
if (!proxyIdx.isValid())
continue;
sourceSelection << QItemSelectionRange(proxyIdx);
}
return sourceSelection;
}
QItemSelection MultiFolderModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
{
QModelIndexList sourceIndexes = sourceSelection.indexes();
QItemSelection proxySelection;
for (int i = 0; i < sourceIndexes.size(); ++i) {
const QModelIndex srcIdx = mapFromSource(sourceIndexes.at(i));
if (!srcIdx.isValid())
continue;
proxySelection << QItemSelectionRange(srcIdx);
}
return proxySelection;
}
QModelIndex MultiFolderModel::mapFromSource(const QModelIndex &sourceIndex) const
{
if (!sourceIndex.isValid())
return QModelIndex();
int row = sourceIndex.row();
for (int i = 0; i < m_modelList.size(); i++) {
if (m_modelList[i].rootSourceIndex.internalId() == sourceIndex.internalId()) {
row = i;
break;
}
}
QModelIndex index = createIndex(row, sourceIndex.column(), sourceIndex.internalPointer());
m_indexMap.insert(sourceIndex.internalId(), (QAbstractItemModel *)sourceIndex.model());
return index;
}
QModelIndex MultiFolderModel::mapToSource(const QModelIndex &proxyIndex) const
{
if (!proxyIndex.isValid()) {
return QModelIndex();
}
int row = proxyIndex.row();
for (int i = 0; i < m_modelList.size(); i++) {
if (m_modelList[i].rootIndex.internalId() == proxyIndex.internalId()) {
row = i;
break;
}
}
auto model = (FileSystemModelEx *)findSource(proxyIndex);
return model->createIndex(row, proxyIndex.column(), proxyIndex.internalPointer());
}
QString MultiFolderModel::filePath(const QModelIndex &index) const
{
if (!index.isValid()) {
return QString();
}
QModelIndex sourceIndex = mapToSource(index);
return ((QFileSystemModel *)sourceIndex.model())->filePath(sourceIndex);
}
QString MultiFolderModel::fileName(const QModelIndex &index) const
{
if (!index.isValid()) {
return QString();
}
QModelIndex sourceIndex = mapToSource(index);
return ((QFileSystemModel *)sourceIndex.model())->fileName(sourceIndex);
}
QFileInfo MultiFolderModel::fileInfo(const QModelIndex &index) const
{
if (!index.isValid()) {
return QFileInfo();
}
QModelIndex sourceIndex = mapToSource(index);
return ((QFileSystemModel *)sourceIndex.model())->fileInfo(sourceIndex);
}
bool MultiFolderModel::isDir(const QModelIndex &index) const
{
if (!index.isValid()) {
return true;
}
QModelIndex sourceIndex = mapToSource(index);
return ((QFileSystemModel *)sourceIndex.model())->isDir(sourceIndex);
}
QModelIndex MultiFolderModel::mkdir(const QModelIndex &parent, const QString &name)
{
if (!parent.isValid()) {
return QModelIndex();
}
QModelIndex sourceIndex = mapToSource(parent);
auto index = ((QFileSystemModel *)sourceIndex.model())->mkdir(sourceIndex, name);
this->resort();
return index;
}
bool MultiFolderModel::rmdir(const QModelIndex &index)
{
if (!index.isValid()) {
return false;
}
QModelIndex sourceIndex = mapToSource(index);
return ((QFileSystemModel *)sourceIndex.model())->rmdir(sourceIndex);
}
bool MultiFolderModel::remove(const QModelIndex &index)
{
if (!index.isValid()) {
return false;
}
QModelIndex sourceIndex = mapToSource(index);
return ((QFileSystemModel *)sourceIndex.model())->remove(sourceIndex);
}
void MultiFolderModel::setFilter(QDir::Filters filters)
{
m_filters = filters;
for (auto &s : m_modelList) {
s.model->setFilter(filters);
}
}
QDir::Filters MultiFolderModel::filter() const
{
return m_filters;
}
void MultiFolderModel::setNameFilters(const QStringList &filters)
{
m_nameFilters = filters;
for (auto &s : m_modelList) {
s.model->setNameFilters(filters);
}
}
QStringList MultiFolderModel::nameFilters() const
{
return m_nameFilters;
}
void MultiFolderModel::setNameFilterDisables(bool enable)
{
if (m_nameFilterDisables == enable) {
return;
}
m_nameFilterDisables = enable;
for (auto &s : m_modelList) {
s.model->setNameFilterDisables(enable);
}
}
bool MultiFolderModel::nameFilterDisables() const
{
return m_nameFilterDisables;
}
void MultiFolderModel::setResolveSymlinks(bool enable)
{
if (m_resolveSymlinks == enable) {
return;
}
m_resolveSymlinks = enable;
for (auto &s : m_modelList) {
s.model->setResolveSymlinks(enable);
}
}
bool MultiFolderModel::resolveSymlinks() const
{
return m_resolveSymlinks;
}
bool MultiFolderModel::isRootIndex(const QModelIndex &index) const
{
for (auto &s : m_modelList) {
if (s.rootIndex.internalId() == index.internalId()) {
return true;
}
}
return false;
}
void MultiFolderModel::setWatcherRoot(bool b)
{
if (m_watcher) {
delete m_watcher;
m_watcher = nullptr;
}
if (b) {
m_watcher = new QFileSystemWatcher(this);
connect(m_watcher, SIGNAL(directoryChanged(QString)), this,
SLOT(directoryChanged(QString)));
QStringList paths;
for (auto &s : m_modelList) {
paths.append(s.watchPath);
}
paths.removeDuplicates();
if (!paths.isEmpty()) {
m_watcher->addPaths(paths);
}
}
}
QList<QModelIndex> MultiFolderModel::indexForPath(const QString &path) const
{
QList<QModelIndex> indexs;
QString findPath = QDir::cleanPath(QDir::fromNativeSeparators(path));
for (auto &s : m_modelList) {
if (!findPath.startsWith(s.rootPath)) {
continue;
}
QModelIndex sourceIndex = s.model->index(path);
if (sourceIndex.isValid()) {
indexs.append(this->mapFromSource(sourceIndex));
}
}
return indexs;
}
QModelIndex MultiFolderModel::indexForPath(QFileSystemModel *model, const QString &path) const
{
auto index = model->index(path);
if (index.isValid()) {
return this->mapFromSource(index);
}
return index;
}
QModelIndex MultiFolderModel::rootIndex(const QModelIndex &index) const
{
auto path = this->filePath(index);
for (auto &model : m_modelList) {
if (path == model.rootPath || path.startsWith(model.rootPath + "/")) {
return model.rootIndex;
}
}
return {};
}
void MultiFolderModel::topRootPath(const QModelIndex &index)
{
if (index.row() == 0) {
return;
}
this->beginMoveRows({}, index.row(), index.row(), {}, 0);
this->m_modelList.move(index.row(), 0);
int pos = 0;
for (auto &s : this->m_modelList) {
s.rootIndex = createIndex(pos, 0, s.rootSourceIndex.internalPointer());
pos++;
}
this->endMoveRows();
}
bool MultiFolderModel::isRootSourceIndex(const QModelIndex &sourceIndex) const
{
for (auto &s : m_modelList) {
if (s.rootSourceIndex.internalId() == sourceIndex.internalId()) {
return true;
}
}
return false;
}
void MultiFolderModel::resort()
{
// 查看源码后,无法单独对某个节点进行重新排序
// 如果需要排序,只能通过重新设置rootpath才能做到,其余方式都为私有方法并且又成员变量控制
for (auto &s : m_modelList) {
auto rootPath = s.model->rootPath();
s.model->setRootPath("");
s.model->setRootPath(rootPath);
}
}
int MultiFolderModel::columnCount(const QModelIndex & /*parent*/) const
{
return 1;
}
QModelIndex MultiFolderModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
if (!parent.isValid()) {
QModelIndex sourceIndex = m_modelList[row].rootSourceIndex;
if (sourceIndex.column() != column) {
sourceIndex = sourceIndex.sibling(sourceIndex.row(), column);
m_indexMap.insert(sourceIndex.internalId(), m_modelList[row].model);
}
return createIndex(row, column, sourceIndex.internalPointer());
}
const QModelIndex sourceParent = mapToSource(parent);
const QModelIndex sourceIndex = sourceParent.model()->index(row, column, sourceParent);
Q_ASSERT(sourceIndex.isValid());
return mapFromSource(sourceIndex);
}
QModelIndex MultiFolderModel::parent(const QModelIndex &child) const
{
Q_ASSERT(child.isValid() ? child.model() == this : true);
if (isRootIndex(child)) {
return QModelIndex();
}
const QModelIndex sourceIndex = mapToSource(child);
const QModelIndex sourceParent = sourceIndex.parent();
return mapFromSource(sourceParent);
}
int MultiFolderModel::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid()) {
return m_modelList.size();
}
Q_ASSERT(parent.isValid() ? parent.model() == this : true);
QModelIndex sourceIndex = mapToSource(parent);
return sourceIndex.model()->rowCount(sourceIndex);
}
QVariant MultiFolderModel::data(const QModelIndex &proxyIndex, int role) const
{
if (!proxyIndex.isValid()) {
return QVariant();
}
QModelIndex sourceIndex = mapToSource(proxyIndex);
return sourceIndex.model()->data(sourceIndex, role);
}
QVariant MultiFolderModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (m_modelList.isEmpty()) {
return QVariant();
}
if (orientation == Qt::Horizontal) {
const QModelIndex proxyIndex = index(0, section);
QModelIndex sourceIndex = mapToSource(proxyIndex);
int sourceSection = sourceIndex.column();
return sourceIndex.model()->headerData(sourceSection, orientation, role);
} else {
const QModelIndex proxyIndex = index(section, 0);
QModelIndex sourceIndex = mapToSource(proxyIndex);
int sourceSection = sourceIndex.row();
return sourceIndex.model()->headerData(sourceSection, orientation, role);
}
}
Qt::ItemFlags MultiFolderModel::flags(const QModelIndex &index) const
{
QModelIndex sourceIndex = mapToSource(index);
if (!sourceIndex.isValid()) {
return Qt::NoItemFlags;
}
return sourceIndex.model()->flags(sourceIndex);
}
bool MultiFolderModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
QModelIndex sourceIndex = mapToSource(index);
return ((QAbstractItemModel *)sourceIndex.model())->setData(sourceIndex, value, role);
}
bool MultiFolderModel::setHeaderData(int section, Qt::Orientation orientation,
const QVariant &value, int role)
{
if (orientation == Qt::Horizontal) {
const QModelIndex proxyIndex = index(0, section);
QModelIndex sourceIndex = mapToSource(proxyIndex);
int sourceSection = sourceIndex.column();
return ((QAbstractItemModel *)sourceIndex.model())
->setHeaderData(sourceSection, orientation, value, role);
} else {
const QModelIndex proxyIndex = index(section, 0);
QModelIndex sourceIndex = mapToSource(proxyIndex);
int sourceSection = sourceIndex.row();
return ((QAbstractItemModel *)sourceIndex.model())
->setHeaderData(sourceSection, orientation, value, role);
}
}
bool MultiFolderModel::insertColumns(int column, int count, const QModelIndex &parent)
{
Q_ASSERT(parent.isValid() ? parent.model() == this : true);
QModelIndex sourceIndex = mapToSource(parent);
return ((QAbstractItemModel *)sourceIndex.model())->insertColumns(column, count, sourceIndex);
}
bool MultiFolderModel::insertRows(int row, int count, const QModelIndex &parent)
{
Q_ASSERT(parent.isValid() ? parent.model() == this : true);
QModelIndex sourceIndex = mapToSource(parent);
return ((QAbstractItemModel *)sourceIndex.model())->insertRows(row, count, sourceIndex);
}
bool MultiFolderModel::removeColumns(int column, int count, const QModelIndex &parent)
{
Q_ASSERT(parent.isValid() ? parent.model() == this : true);
QModelIndex sourceIndex = mapToSource(parent);
return ((QAbstractItemModel *)sourceIndex.model())->removeColumns(column, count, sourceIndex);
}
bool MultiFolderModel::removeRows(int row, int count, const QModelIndex &parent)
{
Q_ASSERT(parent.isValid() ? parent.model() == this : true);
if (!parent.isValid()) {
return QAbstractItemModel::removeRows(row, count);
}
QModelIndex sourceIndex = mapToSource(parent);
return ((QAbstractItemModel *)sourceIndex.model())->removeRows(row, count, sourceIndex);
}
void MultiFolderModel::directoryChanged(const QString &path)
{
for (auto &s : m_modelList) {
if (s.watchPath == path && !QDir(s.rootPath).exists()) {
this->removeRoot(s.rootIndex);
Q_EMIT rootRemoved(path);
break;
}
}
}
bool MultiFolderModel::canFetchMore(const QModelIndex &parent) const
{
if (!parent.isValid()) {
return false;
}
QModelIndex sourceIndex = mapToSource(parent);
return sourceIndex.model()->canFetchMore(sourceIndex);
}
void MultiFolderModel::fetchMore(const QModelIndex &parent)
{
if (!parent.isValid()) {
return;
}
QModelIndex sourceIndex = mapToSource(parent);
QAbstractItemModel *model = (QAbstractItemModel *)sourceIndex.model();
model->fetchMore(sourceIndex);
}
void MultiFolderModel::sort(int column, Qt::SortOrder order)
{
for (auto &s : m_modelList) {
s.model->sort(column, order);
}
}
QSize MultiFolderModel::span(const QModelIndex &index) const
{
if (!index.isValid()) {
return QAbstractItemModel::span(index);
}
QModelIndex sourceIndex = mapToSource(index);
return sourceIndex.model()->span(sourceIndex);
}
bool MultiFolderModel::hasChildren(const QModelIndex &parent) const
{
if (!parent.isValid()) {
return m_modelList.size() > 0;
}
QModelIndex sourceIndex = mapToSource(parent);
return sourceIndex.model()->hasChildren(sourceIndex);
}
void MultiFolderModel::sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
{
this->beginInsertColumns(mapFromSource(parent), start, end);
}
void MultiFolderModel::sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart,
int sourceEnd, const QModelIndex &destParent,
int dest)
{
this->beginMoveColumns(this->mapFromSource(sourceParent), sourceStart, sourceEnd,
this->mapFromSource(destParent), dest);
}
void MultiFolderModel::sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
this->beginRemoveColumns(this->mapFromSource(parent), start, end);
}
void MultiFolderModel::sourceColumnsInserted(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent)
Q_UNUSED(start)
Q_UNUSED(end)
this->endInsertColumns();
}
void MultiFolderModel::sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart,
int sourceEnd, const QModelIndex &destParent, int dest)
{
Q_UNUSED(sourceParent)
Q_UNUSED(sourceStart)
Q_UNUSED(sourceEnd)
Q_UNUSED(destParent)
Q_UNUSED(dest)
this->endMoveColumns();
}
void MultiFolderModel::sourceColumnsRemoved(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent)
Q_UNUSED(start)
Q_UNUSED(end)
this->endRemoveColumns();
}
void MultiFolderModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
this->dataChanged(this->mapFromSource(topLeft), this->mapFromSource(bottomRight));
}
void MultiFolderModel::sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last)
{
this->headerDataChanged(orientation, first, last);
}
void MultiFolderModel::sourceLayoutAboutToBeChanged()
{
for (auto &proxyPersistentIndex : this->persistentIndexList()) {
proxyIndexes << proxyPersistentIndex;
const QPersistentModelIndex srcPersistentIndex = this->mapToSource(proxyPersistentIndex);
layoutChangePersistentIndexes << srcPersistentIndex;
}
this->layoutAboutToBeChanged();
}
void MultiFolderModel::sourceLayoutChanged()
{
for (int i = 0; i < proxyIndexes.size(); ++i) {
this->changePersistentIndex(proxyIndexes.at(i),
this->mapFromSource(layoutChangePersistentIndexes.at(i)));
}
layoutChangePersistentIndexes.clear();
proxyIndexes.clear();
this->layoutChanged();
}
void MultiFolderModel::sourceModelAboutToBeReset()
{
this->beginResetModel();
}
void MultiFolderModel::sourceModelReset()
{
this->endResetModel();
}
void MultiFolderModel::sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart,
int sourceEnd, const QModelIndex &destParent,
int dest)
{
this->beginMoveRows(this->mapFromSource(sourceParent), sourceStart, sourceEnd,
this->mapFromSource(destParent), dest);
}
void MultiFolderModel::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
this->beginRemoveRows(this->mapFromSource(parent), start, end);
}
void MultiFolderModel::sourceRowsInserted(const QModelIndex &parent, int start, int end)
{
for (int i = start; i <= end; i++) {
this->beginInsertRows(this->mapFromSource(parent), i, i);
this->endInsertRows();
}
}
void MultiFolderModel::sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart,
int sourceEnd, const QModelIndex &destParent, int dest)
{
Q_UNUSED(sourceParent)
Q_UNUSED(sourceStart)
Q_UNUSED(sourceEnd)
Q_UNUSED(destParent)
Q_UNUSED(dest)
this->endMoveRows();
}
void MultiFolderModel::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent)
Q_UNUSED(start)
Q_UNUSED(end)
this->endRemoveRows();
}