summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-12-12 18:57:36 -0500
committerisanae <14251494+isanae@users.noreply.github.com>2020-02-04 03:33:17 -0500
commitc5f98f9756ed9ba5b2241fa11215d99c8bf52461 (patch)
tree3e88b4cd79f0a7b408df2337fbaf5569b685d591
parentd3e9abddaf1f927102002d9fb2721e858f6c3a3e (diff)
now prunes empty directories
handles archives and conflicts checkboxes
-rw-r--r--src/datatab.cpp22
-rw-r--r--src/datatab.h2
-rw-r--r--src/filetree.cpp124
-rw-r--r--src/filetree.h16
-rw-r--r--src/shared/directoryentry.h14
5 files changed, 134 insertions, 44 deletions
diff --git a/src/datatab.cpp b/src/datatab.cpp
index bc0ff455..b351923c 100644
--- a/src/datatab.cpp
+++ b/src/datatab.cpp
@@ -18,7 +18,7 @@ QString UnmanagedModName();
DataTab::DataTab(
OrganizerCore& core, PluginContainer& pc,
QWidget* parent, Ui::MainWindow* mwui) :
- m_core(core), m_pluginContainer(pc), m_archives(false), m_parent(parent),
+ m_core(core), m_pluginContainer(pc), m_parent(parent),
m_model(new FileTreeModel(core)),
ui{
mwui->btnRefreshData, mwui->dataTree,
@@ -150,7 +150,6 @@ void DataTab::onRefresh()
void DataTab::refreshDataTree()
{
m_model->refresh();
- ui.tree->expand(m_model->index(0, 0));
}
void DataTab::refreshDataTreeKeepExpandedNodes()
@@ -343,12 +342,27 @@ void DataTab::onContextMenu(const QPoint &pos)
void DataTab::onConflicts()
{
- refreshDataTreeKeepExpandedNodes();
+ updateOptions();
}
void DataTab::onArchives()
{
- m_archives = (m_core.getArchiveParsing() && ui.archives->isChecked());
+ updateOptions();
+}
+
+void DataTab::updateOptions()
+{
+ FileTreeModel::Flags flags = FileTreeModel::NoFlags;
+
+ if (ui.conflicts->isChecked()) {
+ flags |= FileTreeModel::Conflicts;
+ }
+
+ if (ui.archives->isChecked()) {
+ flags |= FileTreeModel::Archives;
+ }
+
+ m_model->setFlags(flags);
refreshDataTree();
}
diff --git a/src/datatab.h b/src/datatab.h
index 8754c12d..de38cc8f 100644
--- a/src/datatab.h
+++ b/src/datatab.h
@@ -44,7 +44,6 @@ private:
OrganizerCore& m_core;
PluginContainer& m_pluginContainer;
- bool m_archives;
QWidget* m_parent;
FileTreeModel* m_model;
DataTabUi ui;
@@ -56,6 +55,7 @@ private:
void onContextMenu(const QPoint &pos);
void onConflicts();
void onArchives();
+ void updateOptions();
void updateTo(
QTreeWidgetItem *subTree, const std::wstring &directorySoFar,
diff --git a/src/filetree.cpp b/src/filetree.cpp
index f43d07a2..cf40e01c 100644
--- a/src/filetree.cpp
+++ b/src/filetree.cpp
@@ -16,17 +16,16 @@ FileTreeItem::FileTreeItem()
FileTreeItem::FileTreeItem(
FileTreeItem* parent, int originID,
- std::wstring virtualParentPath, std::wstring realPath, Flags flags,
+ std::wstring dataRelativeParentPath, std::wstring realPath, Flags flags,
std::wstring file, std::wstring mod) :
m_parent(parent), m_originID(originID),
- m_virtualParentPath(QString::fromStdWString(virtualParentPath)),
+ m_virtualParentPath(QString::fromStdWString(dataRelativeParentPath)),
m_realPath(QString::fromStdWString(realPath)),
m_flags(flags),
m_file(QString::fromStdWString(file)),
m_mod(QString::fromStdWString(mod)),
m_loaded(false)
{
- Q_ASSERT(!m_mod.isEmpty());
}
void FileTreeItem::add(std::unique_ptr<FileTreeItem> child)
@@ -56,27 +55,20 @@ const QString& FileTreeItem::virtualParentPath() const
QString FileTreeItem::virtualPath() const
{
- if (m_virtualParentPath.isEmpty()) {
- return m_file;
- } else {
- return m_virtualParentPath + "\\" + m_file;
- }
-}
+ QString s = "Data\\";
-QString FileTreeItem::dataRelativeParentPath() const
-{
- if (m_virtualParentPath == "data") {
- return "";
+ if (!m_virtualParentPath.isEmpty()) {
+ s += m_virtualParentPath + "\\";
}
- static const QString prefix = "data\\";
+ s += m_file;
- auto path = m_virtualParentPath;
- if (path.startsWith(prefix)) {
- path = path.mid(prefix.size());
- }
+ return s;
+}
- return path;
+QString FileTreeItem::dataRelativeParentPath() const
+{
+ return m_virtualParentPath;
}
QString FileTreeItem::dataRelativeFilePath() const
@@ -396,13 +388,13 @@ bool FileTreeModel::showConflicts() const
bool FileTreeModel::showArchives() const
{
- return (m_flags & Archives);
+ return (m_flags & Archives) && m_core.getArchiveParsing();
}
void FileTreeModel::refresh()
{
beginResetModel();
- m_root = {nullptr, 0, L"", L"", FileTreeItem::Directory, L"Data", L""};
+ m_root = {nullptr, 0, L"", L"", FileTreeItem::Directory, L"Data", L"<root>"};
fill(m_root, *m_core.directoryStructure(), L"");
endResetModel();
}
@@ -437,27 +429,87 @@ void FileTreeModel::fill(
FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry,
const std::wstring& parentPath)
{
- const std::wstring path =
- parentPath +
- (parentPath.empty() ? L"" : L"\\") +
- parentEntry.getName();
+ std::wstring path = parentPath;
+
+ if (!parentEntry.isTopLevel()) {
+ if (!path.empty()) {
+ path += L"\\";
+ }
+
+ path += parentEntry.getName();
+ }
+
+ const auto flags = FillFlag::PruneDirectories;
std::vector<DirectoryEntry*>::const_iterator begin, end;
parentEntry.getSubDirectories(begin, end);
- fillDirectories(parentItem, path, begin, end);
+ fillDirectories(parentItem, path, begin, end, flags);
- fillFiles(parentItem, path, parentEntry.getFiles());
+ fillFiles(parentItem, path, parentEntry.getFiles(), flags);
parentItem.setLoaded(true);
}
+bool FileTreeModel::shouldShowFile(const FileEntry& file) const
+{
+ if (showConflicts() && (file.getAlternatives().size() == 0)) {
+ return false;
+ }
+
+ bool isArchive = false;
+ int originID = file.getOrigin(isArchive);
+ if (!showArchives() && isArchive) {
+ return false;
+ }
+
+ return true;
+}
+
+bool FileTreeModel::hasFilesAnywhere(const DirectoryEntry& dir) const
+{
+ bool foundFile = false;
+
+ dir.forEachFile([&](auto&& f) {
+ if (shouldShowFile(f)) {
+ foundFile = true;
+
+ // stop
+ return false;
+ }
+
+ // continue
+ return true;
+ });
+
+ if (foundFile) {
+ return true;
+ }
+
+ std::vector<DirectoryEntry*>::const_iterator begin, end;
+ dir.getSubDirectories(begin, end);
+
+ for (auto itor=begin; itor!=end; ++itor) {
+ if (hasFilesAnywhere(**itor)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void FileTreeModel::fillDirectories(
FileTreeItem& parentItem, const std::wstring& path,
- DirectoryIterator begin, DirectoryIterator end)
+ DirectoryIterator begin, DirectoryIterator end, FillFlags flags)
{
for (auto itor=begin; itor!=end; ++itor) {
const auto& dir = **itor;
+ if (flags & FillFlag::PruneDirectories) {
+ if (!hasFilesAnywhere(dir)) {
+ continue;
+ }
+ }
+
auto child = std::make_unique<FileTreeItem>(
&parentItem, 0, path, L"", FileTreeItem::Directory, dir.getName(), L"");
@@ -471,18 +523,15 @@ void FileTreeModel::fillDirectories(
void FileTreeModel::fillFiles(
FileTreeItem& parentItem, const std::wstring& path,
- const std::vector<FileEntry::Ptr>& files)
+ const std::vector<FileEntry::Ptr>& files, FillFlags)
{
for (auto&& file : files) {
- if (showConflicts() && (file->getAlternatives().size() == 0)) {
+ if (!shouldShowFile(*file)) {
continue;
}
bool isArchive = false;
int originID = file->getOrigin(isArchive);
- if (!showArchives() && isArchive) {
- continue;
- }
FileTreeItem::Flags flags = FileTreeItem::NoFlags;
@@ -549,9 +598,12 @@ QModelIndex FileTreeModel::index(
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());
+ // don't warn if the tree hasn't been refreshed yet
+ if (!m_root.children().empty()) {
+ log::error(
+ "FileTreeModel::index(): row {} is out of range for {}",
+ row, parent->debugName());
+ }
return {};
}
diff --git a/src/filetree.h b/src/filetree.h
index 13299bb3..4fbd5a2b 100644
--- a/src/filetree.h
+++ b/src/filetree.h
@@ -20,7 +20,7 @@ public:
FileTreeItem();
FileTreeItem(
FileTreeItem* parent, int originID,
- std::wstring virtualParentPath, std::wstring realPath, Flags flags,
+ std::wstring dataRelativeParentPath, std::wstring realPath, Flags flags,
std::wstring file, std::wstring mod);
FileTreeItem(const FileTreeItem&) = delete;
@@ -98,6 +98,14 @@ public:
Qt::ItemFlags flags(const QModelIndex& index) const override;
private:
+ enum class FillFlag
+ {
+ None = 0x00,
+ PruneDirectories = 0x01
+ };
+
+ Q_DECLARE_FLAGS(FillFlags, FillFlag);
+
class IconFetcher;
using DirectoryIterator = std::vector<MOShared::DirectoryEntry*>::const_iterator;
@@ -117,11 +125,11 @@ private:
void fillDirectories(
FileTreeItem& parentItem, const std::wstring& path,
- DirectoryIterator begin, DirectoryIterator end);
+ DirectoryIterator begin, DirectoryIterator end, FillFlags flags);
void fillFiles(
FileTreeItem& parentItem, const std::wstring& path,
- const std::vector<MOShared::FileEntry::Ptr>& files);
+ const std::vector<MOShared::FileEntry::Ptr>& files, FillFlags flags);
std::wstring makeModName(const MOShared::FileEntry& file, int originID) const;
@@ -129,6 +137,8 @@ private:
void ensureLoaded(FileTreeItem* item) const;
void updatePendingIcons();
+ bool shouldShowFile(const MOShared::FileEntry& file) const;
+ bool hasFilesAnywhere(const MOShared::DirectoryEntry& dir) const;
QString makeTooltip(const FileTreeItem& item) const;
QVariant makeIcon(const FileTreeItem& item, const QModelIndex& index) const;
};
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h
index 785c3ff6..0e6b20f0 100644
--- a/src/shared/directoryentry.h
+++ b/src/shared/directoryentry.h
@@ -217,8 +217,10 @@ public:
void clear();
bool isPopulated() const { return m_Populated; }
+ bool isTopLevel() const { return m_TopLevel; }
bool isEmpty() const { return m_Files.empty() && m_SubDirectories.empty(); }
+ bool hasFiles() const { return !m_Files.empty(); }
const DirectoryEntry *getParent() const { return m_Parent; }
@@ -247,6 +249,18 @@ public:
begin = m_SubDirectories.begin(); end = m_SubDirectories.end();
}
+ template <class F>
+ void forEachFile(F&& f) const
+ {
+ for (auto&& p : m_Files) {
+ if (auto file=m_FileRegister->getFile(p.second)) {
+ if (!f(*file)) {
+ break;
+ }
+ }
+ }
+ }
+
DirectoryEntry *findSubDirectory(const std::wstring &name) const;
DirectoryEntry *findSubDirectoryRecursive(const std::wstring &path);