diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-12-10 14:19:09 -0500 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2020-02-04 03:33:17 -0500 |
| commit | efdc3eb14fc238e3cb2032148ab37f143f1bbc5f (patch) | |
| tree | aa278433c57a87a71b76072f610f310adc17bf18 /src | |
| parent | a4624f239fe5d152ec8797c1a3f8c2b2aeaef1ba (diff) | |
load items on demand
Diffstat (limited to 'src')
| -rw-r--r-- | src/filetree.cpp | 210 | ||||
| -rw-r--r-- | src/filetree.h | 20 |
2 files changed, 195 insertions, 35 deletions
diff --git a/src/filetree.cpp b/src/filetree.cpp index cfc73de0..d7a61898 100644 --- a/src/filetree.cpp +++ b/src/filetree.cpp @@ -1,7 +1,9 @@ #include "filetree.h" #include "organizercore.h" +#include <log.h> using namespace MOShared; +using namespace MOBase; // in mainwindow.cpp QString UnmanagedModName(); @@ -41,6 +43,46 @@ FileTreeItem* FileTreeItem::parent() return m_parent; } +const QString& FileTreeItem::virtualParentPath() const +{ + return m_virtualParentPath; +} + +QString FileTreeItem::virtualPath() const +{ + if (m_virtualParentPath.isEmpty()) { + return m_file; + } else { + return m_virtualParentPath + "\\" + m_file; + } +} + +QString FileTreeItem::dataRelativeParentPath() const +{ + if (m_virtualParentPath == "data") { + return ""; + } + + static const QString prefix = "data\\"; + + auto path = m_virtualParentPath; + if (path.startsWith(prefix)) { + path = path.mid(prefix.size()); + } + + return path; +} + +QString FileTreeItem::dataRelativeFilePath() const +{ + auto path = dataRelativeParentPath(); + if (!path.isEmpty()) { + path += "\\"; + } + + return path += m_file; +} + const QString& FileTreeItem::filename() const { return m_file; @@ -51,14 +93,23 @@ const QString& FileTreeItem::mod() const return m_mod; } -bool FileTreeItem::isFromArchive() const +QFileIconProvider::IconType FileTreeItem::icon() const { - return (m_flags & FromArchive); + if (m_flags & Directory) { + return QFileIconProvider::Folder; + } else { + return QFileIconProvider::File; + } } -bool FileTreeItem::isHidden() const +bool FileTreeItem::isDirectory() const { - return m_file.endsWith(ModInfo::s_HiddenExt); + return (m_flags & Directory); +} + +bool FileTreeItem::isFromArchive() const +{ + return (m_flags & FromArchive); } bool FileTreeItem::isConflicted() const @@ -66,13 +117,22 @@ bool FileTreeItem::isConflicted() const return (m_flags & Conflicted); } -QFileIconProvider::IconType FileTreeItem::icon() const +bool FileTreeItem::isHidden() const { - if (m_flags & Directory) { - return QFileIconProvider::Folder; - } else { - return QFileIconProvider::File; + return m_file.endsWith(ModInfo::s_HiddenExt); +} + +bool FileTreeItem::hasChildren() const +{ + if (!isDirectory()) { + return false; + } + + if (isLoaded() && m_children.empty()) { + return false; } + + return true; } void FileTreeItem::setLoaded(bool b) @@ -80,6 +140,18 @@ void FileTreeItem::setLoaded(bool b) m_loaded = b; } +bool FileTreeItem::isLoaded() const +{ + return m_loaded; +} + +QString FileTreeItem::debugName() const +{ + return QString("%1(ld=%2,cs=%3)") + .arg(virtualPath()) + .arg(m_loaded) + .arg(m_children.size()); +} FileTreeModel::FileTreeModel(OrganizerCore& core, QObject* parent) @@ -107,37 +179,60 @@ bool FileTreeModel::showArchives() const void FileTreeModel::refresh() { + beginResetModel(); m_root = {nullptr, L"", L"", FileTreeItem::Directory, L"Data", L""}; - fill(m_root, *m_core.directoryStructure(), L""); - m_root.setLoaded(true); + endResetModel(); +} + +void FileTreeModel::ensureLoaded(FileTreeItem* item) const +{ + if (!item) { + log::error("ensureLoaded(): item is null"); + return; + } + + if (item->isLoaded()) { + return; + } + + log::debug("{}: loading on demand", item->debugName()); + + const auto path = item->dataRelativeFilePath(); + auto* dir = m_core.directoryStructure()->findSubDirectoryRecursive( + path.toStdWString()); + + if (!dir) { + log::error("{}: directory '{}' not found", item->debugName(), path); + return; + } + + const_cast<FileTreeModel*>(this) + ->fill(*item, *dir, item->dataRelativeParentPath().toStdWString()); } void FileTreeModel::fill( FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, const std::wstring& parentPath) { - const std::wstring path = parentPath + L"\\" + parentEntry.getName(); - bool isDirectory = true; + const std::wstring path = + parentPath + + (parentPath.empty() ? L"" : L"\\") + + parentEntry.getName(); + std::vector<DirectoryEntry*>::const_iterator begin, end; + parentEntry.getSubDirectories(begin, end); + fillDirectories(parentItem, path, begin, end); - { - std::vector<DirectoryEntry*>::const_iterator begin, end; - parentEntry.getSubDirectories(begin, end); - fillDirectories(parentItem, path, begin, end); - } + fillFiles(parentItem, path, parentEntry.getFiles()); - { - fillFiles(parentItem, path, parentEntry.getFiles()); - } + parentItem.setLoaded(true); } void FileTreeModel::fillDirectories( FileTreeItem& parentItem, const std::wstring& path, DirectoryIterator begin, DirectoryIterator end) { - const bool isDirectory = true; - for (auto itor=begin; itor!=end; ++itor) { const auto& dir = **itor; @@ -146,8 +241,6 @@ void FileTreeModel::fillDirectories( if (dir.isEmpty()) { child->setLoaded(true); - } else if (showConflicts() || !showArchives()) { - fill(*child, dir, path); } parentItem.add(std::move(child)); @@ -158,8 +251,6 @@ void FileTreeModel::fillFiles( FileTreeItem& parentItem, const std::wstring& path, const std::vector<FileEntry::Ptr>& files) { - const bool isDirectory = false; - for (auto&& file : files) { if (showConflicts() && (file->getAlternatives().size() == 0)) { continue; @@ -217,7 +308,8 @@ FileTreeItem* FileTreeModel::itemFromIndex(const QModelIndex& index) const return static_cast<FileTreeItem*>(data); } -QModelIndex FileTreeModel::index(int row, int col, const QModelIndex& parentIndex) const +QModelIndex FileTreeModel::index( + int row, int col, const QModelIndex& parentIndex) const { FileTreeItem* parent = nullptr; @@ -228,14 +320,25 @@ QModelIndex FileTreeModel::index(int row, int col, const QModelIndex& parentInde } if (!parent) { + log::error("FileTreeModel::index(): parent is null"); return {}; } + ensureLoaded(parent); + if (static_cast<std::size_t>(row) >= parent->children().size()) { + log::error( + "FileTreeModel::index(): row {} is out of range for {}", + row, parent->debugName()); + return {}; } if (col >= columnCount({})) { + log::error( + "FileTreeModel::index(): col {} is out of range for {}", + col, parent->debugName()); + return {}; } @@ -259,6 +362,8 @@ QModelIndex FileTreeModel::parent(const QModelIndex& index) const return {}; } + ensureLoaded(parent); + int row = 0; for (auto&& child : parent->children()) { if (child.get() == item) { @@ -268,20 +373,29 @@ QModelIndex FileTreeModel::parent(const QModelIndex& index) const ++row; } + log::error( + "FileTreeModel::parent(): item {} has no child {}", + parent->debugName(), item->debugName()); + return {}; } int FileTreeModel::rowCount(const QModelIndex& parent) const { + FileTreeItem* item = nullptr; + if (!parent.isValid()) { - return static_cast<int>(m_root.children().size()); + item = &m_root; } else { - if (auto* item=itemFromIndex(parent)) { - return static_cast<int>(item->children().size()); - } + item = itemFromIndex(parent); + } + + if (!item) { + return 0; } - return 0; + ensureLoaded(item); + return static_cast<int>(item->children().size()); } int FileTreeModel::columnCount(const QModelIndex&) const @@ -289,6 +403,23 @@ int FileTreeModel::columnCount(const QModelIndex&) const return 2; } +bool FileTreeModel::hasChildren(const QModelIndex& parent) const +{ + const FileTreeItem* item = nullptr; + + if (!parent.isValid()) { + item = &m_root; + } else { + item = itemFromIndex(parent); + } + + if (!item) { + return false; + } + + return item->hasChildren(); +} + QVariant FileTreeModel::data(const QModelIndex& index, int role) const { switch (role) @@ -394,3 +525,16 @@ QVariant FileTreeModel::headerData(int i, Qt::Orientation ori, int role) const return {}; } + +Qt::ItemFlags FileTreeModel::flags(const QModelIndex& index) const +{ + auto f = QAbstractItemModel::flags(index); + + if (auto* item=itemFromIndex(index)) { + if (!item->hasChildren()) { + f |= Qt::ItemNeverHasChildren; + } + } + + return f; +} diff --git a/src/filetree.h b/src/filetree.h index a9eac64e..aabdf61b 100644 --- a/src/filetree.h +++ b/src/filetree.h @@ -32,14 +32,27 @@ public: const std::vector<std::unique_ptr<FileTreeItem>>& children() const; FileTreeItem* parent(); + + const QString& virtualParentPath() const; + QString virtualPath() const; const QString& filename() const; const QString& mod() const; + + QString dataRelativeParentPath() const; + QString dataRelativeFilePath() const; + + QFileIconProvider::IconType icon() const; + + bool isDirectory() const; bool isFromArchive() const; + bool isConflicted() const; bool isHidden() const; - bool isConflicted() const;; - QFileIconProvider::IconType icon() const; + bool hasChildren() const; void setLoaded(bool b); + bool isLoaded() const; + + QString debugName() const; private: FileTreeItem* m_parent; @@ -76,8 +89,10 @@ public: QModelIndex parent(const QModelIndex& index) const override; int rowCount(const QModelIndex& parent={}) const override; int columnCount(const QModelIndex& parent={}) const override; + bool hasChildren(const QModelIndex& parent={}) const override; QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; QVariant headerData(int i, Qt::Orientation ori, int role=Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex& index) const override; private: using DirectoryIterator = std::vector<MOShared::DirectoryEntry*>::const_iterator; @@ -104,6 +119,7 @@ private: std::wstring makeModName(const MOShared::FileEntry& file, int originID) const; FileTreeItem* itemFromIndex(const QModelIndex& index) const; + void ensureLoaded(FileTreeItem* item) const; }; Q_DECLARE_OPERATORS_FOR_FLAGS(FileTreeModel::Flags); |
