summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2020-01-22 05:45:08 -0500
committerisanae <14251494+isanae@users.noreply.github.com>2020-02-04 03:33:22 -0500
commitc6c01f86c64a3a9fa666dddec860e52d388e5e97 (patch)
tree7089d033f95630111e373d2ee173d03492fc8b5c /src
parent7c98635edc33d74ab24352e971bb6a127e7272e8 (diff)
sort
Diffstat (limited to 'src')
-rw-r--r--src/datatab.cpp4
-rw-r--r--src/filetreeitem.cpp67
-rw-r--r--src/filetreeitem.h4
-rw-r--r--src/filetreemodel.cpp80
-rw-r--r--src/filetreemodel.h20
-rw-r--r--src/mainwindow.ui3
6 files changed, 159 insertions, 19 deletions
diff --git a/src/datatab.cpp b/src/datatab.cpp
index 1b7baa82..af457b33 100644
--- a/src/datatab.cpp
+++ b/src/datatab.cpp
@@ -59,6 +59,10 @@ void DataTab::saveState(Settings& s) const
void DataTab::restoreState(const Settings& s)
{
s.geometry().restoreState(ui.tree->header());
+
+ // prior to 2.3, the list was not sortable, and this remembered in the
+ // widget state, for whatever reason
+ ui.tree->setSortingEnabled(true);
}
void DataTab::activated()
diff --git a/src/filetreeitem.cpp b/src/filetreeitem.cpp
index e7510279..a506f0f0 100644
--- a/src/filetreeitem.cpp
+++ b/src/filetreeitem.cpp
@@ -1,6 +1,8 @@
#include "filetreeitem.h"
+#include "filetreemodel.h"
#include "modinfo.h"
#include "util.h"
+#include "modinfodialogfwd.h"
#include <log.h>
using namespace MOBase;
@@ -63,6 +65,71 @@ void FileTreeItem::remove(std::size_t from, std::size_t n)
m_children.erase(begin, end);
}
+
+template <class T>
+int threeWayCompare(T&& a, T&& b)
+{
+ if (a < b) {
+ return -1;
+ }
+
+ if (a > b) {
+ return 1;
+ }
+
+ return 0;
+}
+
+class FileTreeItem::Sorter
+{
+public:
+ static int compare(int column, const FileTreeItem* a, const FileTreeItem* b)
+ {
+ switch (column)
+ {
+ case FileTreeModel::FileName:
+ return naturalCompare(a->m_file, b->m_file);
+
+ case FileTreeModel::ModName:
+ return naturalCompare(a->m_mod, b->m_mod);
+
+ case FileTreeModel::FileType:
+ return naturalCompare(a->meta().type, b->meta().type);
+
+ case FileTreeModel::FileSize:
+ return threeWayCompare(a->meta().size, b->meta().size);
+
+ case FileTreeModel::LastModified:
+ return threeWayCompare(a->meta().lastModified, b->meta().lastModified);
+
+ default:
+ return 0;
+ }
+ }
+};
+
+
+void FileTreeItem::sort(int column, Qt::SortOrder order)
+{
+ std::sort(m_children.begin(), m_children.end(), [&](auto&& a, auto&& b) {
+ int r = 0;
+
+ if (a->isDirectory() && !b->isDirectory()) {
+ r = -1;
+ } else if (!a->isDirectory() && b->isDirectory()) {
+ r = 1;
+ } else {
+ r = FileTreeItem::Sorter::compare(column, a.get(), b.get());
+ }
+
+ if (order == Qt::AscendingOrder) {
+ return (r < 0);
+ } else {
+ return (r > 0);
+ }
+ });
+}
+
QString FileTreeItem::virtualPath() const
{
QString s = "Data\\";
diff --git a/src/filetreeitem.h b/src/filetreeitem.h
index 01cd01a7..fc27b0c0 100644
--- a/src/filetreeitem.h
+++ b/src/filetreeitem.h
@@ -6,6 +6,8 @@
class FileTreeItem
{
+ class Sorter;
+
public:
using Children = std::vector<std::unique_ptr<FileTreeItem>>;
@@ -88,6 +90,8 @@ public:
return -1;
}
+ void sort(int column, Qt::SortOrder order);
+
FileTreeItem* parent()
{
return m_parent;
diff --git a/src/filetreemodel.cpp b/src/filetreemodel.cpp
index 5424d14b..aa053eeb 100644
--- a/src/filetreemodel.cpp
+++ b/src/filetreemodel.cpp
@@ -326,6 +326,39 @@ Qt::ItemFlags FileTreeModel::flags(const QModelIndex& index) const
return f;
}
+void FileTreeModel::sort(int column, Qt::SortOrder order)
+{
+ emit layoutAboutToBeChanged();
+
+ m_sort.column = column;
+ m_sort.order = order;
+
+ const auto oldList = persistentIndexList();
+ std::vector<std::pair<FileTreeItem*, int>> oldItems;
+
+ const auto itemCount = oldList.size();
+ oldItems.reserve(static_cast<std::size_t>(itemCount));
+
+ for (int i=0; i<itemCount; ++i) {
+ const QModelIndex& index = oldList[i];
+ oldItems.push_back({itemFromIndex(index), index.column()});
+ }
+
+ m_root.sort(column, order);
+
+ QModelIndexList newList;
+ newList.reserve(itemCount);
+
+ for (int i=0; i<itemCount; ++i) {
+ const auto& pair = oldItems[static_cast<std::size_t>(i)];
+ newList.append(indexFromItem(*pair.first, pair.second));
+ }
+
+ changePersistentIndexList(oldList, newList);
+
+ emit layoutChanged({}, QAbstractItemModel::VerticalSortHint);
+}
+
FileTreeItem* FileTreeModel::itemFromIndex(const QModelIndex& index) const
{
if (!index.isValid()) {
@@ -349,7 +382,7 @@ FileTreeItem* FileTreeModel::itemFromIndex(const QModelIndex& index) const
return parentItem->children()[index.row()].get();
}
-QModelIndex FileTreeModel::indexFromItem(FileTreeItem& item) const
+QModelIndex FileTreeModel::indexFromItem(FileTreeItem& item, int col) const
{
auto* parent = item.parent();
if (!parent) {
@@ -365,7 +398,7 @@ QModelIndex FileTreeModel::indexFromItem(FileTreeItem& item) const
return {};
}
- return createIndex(index, 0, parent);
+ return createIndex(index, col, parent);
}
void FileTreeModel::update(
@@ -383,13 +416,24 @@ void FileTreeModel::update(
path += parentEntry.getName();
}
- updateDirectories(parentItem, path, parentEntry, FillFlag::None);
- updateFiles(parentItem, path, parentEntry);
-
parentItem.setLoaded(true);
+
+ bool added = false;
+
+ if (updateDirectories(parentItem, path, parentEntry, FillFlag::None)) {
+ added = true;
+ }
+
+ if (updateFiles(parentItem, path, parentEntry)) {
+ added = true;
+ }
+
+ if (added) {
+ parentItem.sort(m_sort.column, m_sort.order);
+ }
}
-void FileTreeModel::updateDirectories(
+bool FileTreeModel::updateDirectories(
FileTreeItem& parentItem, const std::wstring& parentPath,
const MOShared::DirectoryEntry& parentEntry, FillFlags flags)
{
@@ -399,7 +443,7 @@ void FileTreeModel::updateDirectories(
std::unordered_set<std::wstring_view> seen;
removeDisappearingDirectories(parentItem, parentEntry, parentPath, seen);
- addNewDirectories(parentItem, parentEntry, parentPath, seen);
+ return addNewDirectories(parentItem, parentEntry, parentPath, seen);
}
void FileTreeModel::removeDisappearingDirectories(
@@ -453,7 +497,7 @@ void FileTreeModel::removeDisappearingDirectories(
range.remove();
}
-void FileTreeModel::addNewDirectories(
+bool FileTreeModel::addNewDirectories(
FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry,
const std::wstring& parentPath,
const std::unordered_set<std::wstring_view>& seen)
@@ -462,6 +506,7 @@ void FileTreeModel::addNewDirectories(
// avoid calling beginAddRows(), etc. for each item
Range range(this, parentItem);
std::vector<std::unique_ptr<FileTreeItem>> toAdd;
+ bool added = false;
// for each directory on the filesystem
for (auto&& d : parentEntry.getSubDirectories()) {
@@ -477,6 +522,8 @@ void FileTreeModel::addNewDirectories(
trace([&]{ log::debug("new dir {}", QString::fromStdWString(d->getName())); });
toAdd.push_back(createDirectoryItem(parentItem, parentPath, *d));
+ added = true;
+
range.includeCurrent();
}
@@ -485,9 +532,11 @@ void FileTreeModel::addNewDirectories(
// add the last directory range, if any
range.add(std::move(toAdd));
+
+ return added;
}
-void FileTreeModel::updateFiles(
+bool FileTreeModel::updateFiles(
FileTreeItem& parentItem, const std::wstring& parentPath,
const MOShared::DirectoryEntry& parentEntry)
{
@@ -499,7 +548,7 @@ void FileTreeModel::updateFiles(
int firstFileRow = 0;
removeDisappearingFiles(parentItem, parentEntry, firstFileRow, seen);
- addNewFiles(parentItem, parentEntry, parentPath, firstFileRow, seen);
+ return addNewFiles(parentItem, parentEntry, parentPath, firstFileRow, seen);
}
void FileTreeModel::removeDisappearingFiles(
@@ -557,7 +606,7 @@ void FileTreeModel::removeDisappearingFiles(
}
}
-void FileTreeModel::addNewFiles(
+bool FileTreeModel::addNewFiles(
FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry,
const std::wstring& parentPath, const int firstFileRow,
const std::unordered_set<FileEntry::Index>& seen)
@@ -566,6 +615,7 @@ void FileTreeModel::addNewFiles(
// avoid calling beginAddRows(), etc. for each item
std::vector<std::unique_ptr<FileTreeItem>> toAdd;
Range range(this, parentItem, firstFileRow);
+ bool added = false;
// for each directory on the filesystem
parentEntry.forEachFileIndex([&](auto&& fileIndex) {
@@ -591,6 +641,8 @@ void FileTreeModel::addNewFiles(
trace([&]{ log::debug("new file {}", QString::fromStdWString(file->getName())); });
toAdd.push_back(createFileItem(parentItem, parentPath, *file));
+ added = true;
+
range.includeCurrent();
}
@@ -601,6 +653,8 @@ void FileTreeModel::addNewFiles(
// add the last file range, if any
range.add(std::move(toAdd));
+
+ return added;
}
std::unique_ptr<FileTreeItem> FileTreeModel::createDirectoryItem(
@@ -650,7 +704,7 @@ QVariant FileTreeModel::displayData(const FileTreeItem* item, int column) const
{
switch (column)
{
- case Filename:
+ case FileName:
{
return item->filename();
}
@@ -681,7 +735,7 @@ QVariant FileTreeModel::displayData(const FileTreeItem* item, int column) const
default:
{
- break;
+ return {};
}
}
}
diff --git a/src/filetreemodel.h b/src/filetreemodel.h
index 96e9e5a7..38f611f9 100644
--- a/src/filetreemodel.h
+++ b/src/filetreemodel.h
@@ -22,7 +22,7 @@ public:
enum Columns
{
- Filename = 0,
+ FileName = 0,
ModName,
FileType,
FileSize,
@@ -53,6 +53,7 @@ public:
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;
+ void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override;
FileTreeItem* itemFromIndex(const QModelIndex& index) const;
@@ -63,6 +64,12 @@ private:
PruneDirectories = 0x01
};
+ struct Sort
+ {
+ int column = 0;
+ Qt::SortOrder order = Qt::AscendingOrder;
+ };
+
class Range;
Q_DECLARE_FLAGS(FillFlags, FillFlag);
@@ -75,6 +82,7 @@ private:
mutable std::vector<QModelIndex> m_iconPending;
mutable QTimer m_iconPendingTimer;
bool m_isRefreshing;
+ Sort m_sort;
bool showConflicts() const
{
@@ -89,7 +97,7 @@ private:
const std::wstring& parentPath);
- void updateDirectories(
+ bool updateDirectories(
FileTreeItem& parentItem, const std::wstring& path,
const MOShared::DirectoryEntry& parentEntry, FillFlags flags);
@@ -97,13 +105,13 @@ private:
FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry,
const std::wstring& parentPath, std::unordered_set<std::wstring_view>& seen);
- void addNewDirectories(
+ bool addNewDirectories(
FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry,
const std::wstring& parentPath,
const std::unordered_set<std::wstring_view>& seen);
- void updateFiles(
+ bool updateFiles(
FileTreeItem& parentItem, const std::wstring& path,
const MOShared::DirectoryEntry& parentEntry);
@@ -111,7 +119,7 @@ private:
FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry,
int& firstFileRow, std::unordered_set<MOShared::FileEntry::Index>& seen);
- void addNewFiles(
+ bool addNewFiles(
FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry,
const std::wstring& parentPath, int firstFileRow,
const std::unordered_set<MOShared::FileEntry::Index>& seen);
@@ -138,7 +146,7 @@ private:
QString makeTooltip(const FileTreeItem& item) const;
QVariant makeIcon(const FileTreeItem& item, const QModelIndex& index) const;
- QModelIndex indexFromItem(FileTreeItem& item) const;
+ QModelIndex indexFromItem(FileTreeItem& item, int col=0) const;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(FileTreeModel::Flags);
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index da9f949c..62425d8c 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -1091,6 +1091,9 @@ p, li { white-space: pre-wrap; }
<property name="uniformRowHeights">
<bool>true</bool>
</property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
<attribute name="headerMinimumSectionSize">
<number>400</number>
</attribute>