summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/datatab.cpp28
-rw-r--r--src/datatab.h2
-rw-r--r--src/filetree.cpp24
-rw-r--r--src/filetree.h3
-rw-r--r--src/filetreeitem.cpp20
-rw-r--r--src/filetreemodel.cpp71
-rw-r--r--src/filetreemodel.h3
-rw-r--r--src/mainwindow.cpp22
-rw-r--r--src/mainwindow.h2
-rw-r--r--src/mainwindow.ui13
-rw-r--r--src/modinfodialog.cpp12
11 files changed, 152 insertions, 48 deletions
diff --git a/src/datatab.cpp b/src/datatab.cpp
index 3923ba4e..74fa35ce 100644
--- a/src/datatab.cpp
+++ b/src/datatab.cpp
@@ -21,10 +21,21 @@ DataTab::DataTab(
QWidget* parent, Ui::MainWindow* mwui) :
m_core(core), m_pluginContainer(pc), m_parent(parent),
ui{
- mwui->btnRefreshData, mwui->dataTree,
- mwui->conflictsCheckBox, mwui->showArchiveDataCheckBox}
+ mwui->dataTabRefresh, mwui->dataTree,
+ mwui->dataTabShowOnlyConflicts, mwui->dataTabShowFromArchives}
{
m_filetree.reset(new FileTree(core, m_pluginContainer, ui.tree));
+ m_filter.setUseSourceSort(true);
+ m_filter.setEdit(mwui->dataTabFilter);
+ m_filter.setList(mwui->dataTree);
+
+ if (auto* m=m_filter.proxyModel()) {
+ m->setDynamicSortFilter(false);
+ }
+
+ connect(
+ &m_filter, &FilterWidget::aboutToChange,
+ [&]{ m_filetree->ensureFullyLoaded(); });
connect(
ui.refresh, &QPushButton::clicked,
@@ -54,6 +65,8 @@ DataTab::DataTab(
void DataTab::saveState(Settings& s) const
{
s.geometry().saveState(ui.tree->header());
+ s.widgets().saveChecked(ui.conflicts);
+ s.widgets().saveChecked(ui.archives);
}
void DataTab::restoreState(const Settings& s)
@@ -63,6 +76,9 @@ void DataTab::restoreState(const Settings& s)
// prior to 2.3, the list was not sortable, and this remembered in the
// widget state, for whatever reason
ui.tree->setSortingEnabled(true);
+
+ s.widgets().restoreChecked(ui.conflicts);
+ s.widgets().restoreChecked(ui.archives);
}
void DataTab::activated()
@@ -82,6 +98,14 @@ void DataTab::onRefresh()
void DataTab::updateTree()
{
m_filetree->refresh();
+
+ if (!m_filter.empty()) {
+ m_filetree->ensureFullyLoaded();
+
+ if (auto* m=m_filter.proxyModel()) {
+ m->invalidate();
+ }
+ }
}
void DataTab::onConflicts()
diff --git a/src/datatab.h b/src/datatab.h
index 4545dc5a..7e8eb2b9 100644
--- a/src/datatab.h
+++ b/src/datatab.h
@@ -1,5 +1,6 @@
#include "modinfodialogfwd.h"
#include "modinfo.h"
+#include <filterwidget.h>
#include <QPushButton>
#include <QTreeWidget>
#include <QCheckBox>
@@ -47,6 +48,7 @@ private:
DataTabUi ui;
std::unique_ptr<FileTree> m_filetree;
std::vector<QTreeWidgetItem*> m_removeLater;
+ MOBase::FilterWidget m_filter;
void onRefresh();
void onItemExpanded(QTreeWidgetItem* item);
diff --git a/src/filetree.cpp b/src/filetree.cpp
index bf3a9a7a..ae1fddfe 100644
--- a/src/filetree.cpp
+++ b/src/filetree.cpp
@@ -150,11 +150,16 @@ void FileTree::clear()
m_model->clear();
}
+void FileTree::ensureFullyLoaded()
+{
+ m_model->ensureFullyLoaded();
+}
+
FileTreeItem* FileTree::singleSelection()
{
const auto sel = m_tree->selectionModel()->selectedRows();
if (sel.size() == 1) {
- return m_model->itemFromIndex(sel[0]);
+ return m_model->itemFromIndex(proxiedIndex(sel[0]));
}
return nullptr;
@@ -357,7 +362,7 @@ void FileTree::dumpToFile() const
QString file = QFileDialog::getSaveFileName(m_tree->window());
if (file.isEmpty()) {
- log::debug("user cancelled");
+ log::debug("user canceled");
return;
}
@@ -432,7 +437,7 @@ void FileTree::dumpToFile(
void FileTree::onExpandedChanged(const QModelIndex& index, bool expanded)
{
- if (auto* item=m_model->itemFromIndex(index)) {
+ if (auto* item=m_model->itemFromIndex(proxiedIndex(index))) {
item->setExpanded(expanded);
}
}
@@ -494,7 +499,7 @@ bool FileTree::showShellMenu(QPoint pos)
bool warnOnEmpty = true;
for (auto&& index : m_tree->selectionModel()->selectedRows()) {
- auto* item = m_model->itemFromIndex(index);
+ auto* item = m_model->itemFromIndex(proxiedIndex(index));
if (!item) {
continue;
}
@@ -759,3 +764,14 @@ void FileTree::addCommonMenus(QMenu& menu)
.callback([&]{ m_tree->collapseAll(); })
.addTo(menu);
}
+
+QModelIndex FileTree::proxiedIndex(const QModelIndex& index)
+{
+ auto* model = m_tree->model();
+
+ if (auto* proxy=dynamic_cast<QSortFilterProxyModel*>(model)) {
+ return proxy->mapToSource(index);
+ } else {
+ return index;
+ }
+}
diff --git a/src/filetree.h b/src/filetree.h
index 80704f7b..855a1751 100644
--- a/src/filetree.h
+++ b/src/filetree.h
@@ -21,6 +21,7 @@ public:
FileTreeModel* model();
void refresh();
void clear();
+ void ensureFullyLoaded();
void open();
void openHooked();
@@ -60,6 +61,8 @@ private:
void toggleVisibility(bool b);
+ QModelIndex proxiedIndex(const QModelIndex& index);
+
void dumpToFile(
QFile& out, const QString& parentPath,
const MOShared::DirectoryEntry& entry) const;
diff --git a/src/filetreeitem.cpp b/src/filetreeitem.cpp
index bb07568a..3332fb7d 100644
--- a/src/filetreeitem.cpp
+++ b/src/filetreeitem.cpp
@@ -10,6 +10,8 @@ using namespace MOBase;
using namespace MOShared;
namespace fs = std::filesystem;
+constexpr bool AlwaysSortDirectoriesFirst = true;
+
const QString& directoryFileType()
{
static QString name;
@@ -179,9 +181,17 @@ void FileTreeItem::sort(int column, Qt::SortOrder order)
int r = 0;
if (a->isDirectory() && !b->isDirectory()) {
- r = -1;
+ if constexpr (AlwaysSortDirectoriesFirst) {
+ return true;
+ } else {
+ r = -1;
+ }
} else if (!a->isDirectory() && b->isDirectory()) {
- r = 1;
+ if constexpr (AlwaysSortDirectoriesFirst) {
+ return false;
+ } else {
+ r = 1;
+ }
} else {
r = FileTreeItem::Sorter::compare(column, a.get(), b.get());
}
@@ -192,6 +202,10 @@ void FileTreeItem::sort(int column, Qt::SortOrder order)
return (r > 0);
}
});
+
+ for (auto& child : m_children) {
+ child->sort(column, order);
+ }
}
QString FileTreeItem::virtualPath() const
@@ -232,7 +246,7 @@ QFont FileTreeItem::font() const
std::optional<uint64_t> FileTreeItem::fileSize() const
{
- if (m_fileSize.empty()) {
+ if (m_fileSize.empty() && !m_isDirectory) {
std::error_code ec;
const auto size = fs::file_size(fs::path(m_wsRealPath), ec);
diff --git a/src/filetreemodel.cpp b/src/filetreemodel.cpp
index aa87edbf..912e2007 100644
--- a/src/filetreemodel.cpp
+++ b/src/filetreemodel.cpp
@@ -87,31 +87,32 @@ public:
//
FileTreeItem::Children::const_iterator remove()
{
- if (m_first == -1) {
- // nothing to remove
- return m_parentItem.children().begin() + m_current + 1;
- }
+ if (m_first >= 0) {
+ const auto last = m_current - 1;
+ const auto parentIndex = m_model->indexFromItem(m_parentItem);
- const auto last = m_current - 1;
- const auto parentIndex = m_model->indexFromItem(m_parentItem);
+ trace(log::debug("Range::remove() {} to {}", m_first, last));
- trace(log::debug("Range::remove() {} to {}", m_first, last));
+ m_model->beginRemoveRows(parentIndex, m_first, last);
- m_model->beginRemoveRows(parentIndex, m_first, last);
+ m_parentItem.remove(
+ static_cast<std::size_t>(m_first),
+ static_cast<std::size_t>(last - m_first + 1));
- m_parentItem.remove(
- static_cast<std::size_t>(m_first),
- static_cast<std::size_t>(last - m_first + 1));
+ m_model->endRemoveRows();
- m_model->endRemoveRows();
+ m_model->removePendingIcons(parentIndex, m_first, last);
- m_model->removePendingIcons(parentIndex, m_first, last);
+ // adjust current row to account for those that were just removed
+ m_current -= (m_current - m_first);
- // adjust current row to account for those that were just removed
- m_current -= (m_current - m_first);
+ // reset
+ m_first = -1;
+ }
- // reset
- m_first = -1;
+ if (m_current >= m_parentItem.children().size()) {
+ return m_parentItem.children().end();
+ }
return m_parentItem.children().begin() + m_current + 1;
}
@@ -138,7 +139,7 @@ void* makeInternalPointer(FileTreeItem* item)
FileTreeModel::FileTreeModel(OrganizerCore& core, QObject* parent) :
QAbstractItemModel(parent), m_core(core),
m_root(FileTreeItem::createDirectory(nullptr, L"", L"")),
- m_flags(NoFlags)
+ m_flags(NoFlags), m_fullyLoaded(false)
{
m_root->setExpanded(true);
@@ -148,16 +149,40 @@ FileTreeModel::FileTreeModel(OrganizerCore& core, QObject* parent) :
void FileTreeModel::refresh()
{
TimeThis tt("FileTreeModel::refresh()");
+
+ m_fullyLoaded = false;
update(*m_root, *m_core.directoryStructure(), L"");
}
void FileTreeModel::clear()
{
+ m_fullyLoaded = false;
+
beginResetModel();
m_root->clear();
endResetModel();
}
+void FileTreeModel::recursiveFetchMore(const QModelIndex& m)
+{
+ if (canFetchMore(m)) {
+ fetchMore(m);
+ }
+
+ for (int i=0; i<rowCount(m); ++i) {
+ recursiveFetchMore(index(i, 0, m));
+ }
+}
+
+void FileTreeModel::ensureFullyLoaded()
+{
+ if (!m_fullyLoaded) {
+ TimeThis tt("FileTreeModel:: fully loading for search");
+ recursiveFetchMore(QModelIndex());
+ m_fullyLoaded = true;
+ }
+}
+
bool FileTreeModel::showArchives() const
{
return (m_flags.testFlag(Archives) && m_core.getArchiveParsing());
@@ -493,9 +518,12 @@ void FileTreeModel::removeDisappearingDirectories(
if (shouldShowFolder(*d, item.get())) {
// folder should be left in the list
if (!item->areChildrenVisible() && item->isLoaded()) {
- // the item is loaded (previously expanded but now collapsed), mark
- // it as unloaded so it updates when next expanded
- item->setLoaded(false);
+ if (!d->isEmpty()) {
+ // the item is loaded (previously expanded but now collapsed) and
+ // has children, mark it as unloaded so it updates when next
+ // expanded
+ item->setLoaded(false);
+ }
}
} else {
// item wouldn't have any children, prune it
@@ -694,6 +722,7 @@ bool FileTreeModel::addNewFiles(
} else {
// this is a new file, but it shouldn't be shown
trace(log::debug("new file {}, not shown", QString::fromStdWString(file->getName())));
+ return true;
}
}
diff --git a/src/filetreemodel.h b/src/filetreemodel.h
index ffd46fac..3e846a0f 100644
--- a/src/filetreemodel.h
+++ b/src/filetreemodel.h
@@ -43,6 +43,7 @@ public:
void refresh();
void clear();
+ void ensureFullyLoaded();
QModelIndex index(int row, int col, const QModelIndex& parent={}) const override;
QModelIndex parent(const QModelIndex& index) const override;
@@ -75,6 +76,7 @@ private:
mutable std::vector<QModelIndex> m_iconPending;
mutable QTimer m_iconPendingTimer;
Sort m_sort;
+ bool m_fullyLoaded;
bool showConflictsOnly() const
{
@@ -141,6 +143,7 @@ private:
QVariant makeIcon(const FileTreeItem& item, const QModelIndex& index) const;
QModelIndex indexFromItem(FileTreeItem& item, int col=0) const;
+ void recursiveFetchMore(const QModelIndex& m);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(FileTreeModel::Flags);
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index bf0dc61f..439775f8 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -455,15 +455,13 @@ MainWindow::MainWindow(Settings &settings
if (m_OrganizerCore.getArchiveParsing())
{
- ui->showArchiveDataCheckBox->setCheckState(Qt::Checked);
- ui->showArchiveDataCheckBox->setEnabled(true);
- m_showArchiveData = true;
+ ui->dataTabShowFromArchives->setCheckState(Qt::Checked);
+ ui->dataTabShowFromArchives->setEnabled(true);
}
else
{
- ui->showArchiveDataCheckBox->setCheckState(Qt::Unchecked);
- ui->showArchiveDataCheckBox->setEnabled(false);
- m_showArchiveData = false;
+ ui->dataTabShowFromArchives->setCheckState(Qt::Unchecked);
+ ui->dataTabShowFromArchives->setEnabled(false);
}
QApplication::instance()->installEventFilter(this);
@@ -1193,7 +1191,7 @@ void MainWindow::downloadFilterChanged(const QString &filter)
void MainWindow::expandModList(const QModelIndex &index)
{
QAbstractItemModel *model = ui->modList->model();
-#pragma message("why is this so complicated? mapping the index doesn't work, probably a bug in QtGroupingProxy?")
+
for (int i = 0; i < model->rowCount(); ++i) {
QModelIndex targetIdx = model->index(i, 0);
if (model->data(targetIdx).toString() == index.data().toString()) {
@@ -4949,15 +4947,13 @@ void MainWindow::on_actionSettings_triggered()
m_OrganizerCore.setArchiveParsing(state);
if (!state)
{
- ui->showArchiveDataCheckBox->setCheckState(Qt::Unchecked);
- ui->showArchiveDataCheckBox->setEnabled(false);
- m_showArchiveData = false;
+ ui->dataTabShowFromArchives->setCheckState(Qt::Unchecked);
+ ui->dataTabShowFromArchives->setEnabled(false);
}
else
{
- ui->showArchiveDataCheckBox->setCheckState(Qt::Checked);
- ui->showArchiveDataCheckBox->setEnabled(true);
- m_showArchiveData = true;
+ ui->dataTabShowFromArchives->setCheckState(Qt::Checked);
+ ui->dataTabShowFromArchives->setEnabled(true);
}
m_OrganizerCore.refreshModList();
m_OrganizerCore.refreshDirectoryStructure();
diff --git a/src/mainwindow.h b/src/mainwindow.h
index d50705e3..608bfa64 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -349,8 +349,6 @@ private:
bool m_DidUpdateMasterList;
- bool m_showArchiveData{ true };
-
MOBase::DelayedFileWriter m_ArchiveListWriter;
QAction* m_LinkToolbar;
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index f0887f56..8bd22ff1 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -1058,7 +1058,7 @@ p, li { white-space: pre-wrap; }
<item>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
- <widget class="QPushButton" name="btnRefreshData">
+ <widget class="QPushButton" name="dataTabRefresh">
<property name="toolTip">
<string>refresh data-directory overview</string>
</property>
@@ -1088,7 +1088,7 @@ p, li { white-space: pre-wrap; }
</spacer>
</item>
<item>
- <widget class="QCheckBox" name="conflictsCheckBox">
+ <widget class="QCheckBox" name="dataTabShowOnlyConflicts">
<property name="toolTip">
<string>Filters the above list so that only conflicts are displayed.</string>
</property>
@@ -1101,7 +1101,7 @@ p, li { white-space: pre-wrap; }
</widget>
</item>
<item>
- <widget class="QCheckBox" name="showArchiveDataCheckBox">
+ <widget class="QCheckBox" name="dataTabShowFromArchives">
<property name="toolTip">
<string>Filters the above list so that files from archives are not shown</string>
</property>
@@ -1147,6 +1147,13 @@ p, li { white-space: pre-wrap; }
</item>
</layout>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="dataTreeFilterBox">
+ <item>
+ <widget class="QLineEdit" name="dataTabFilter"/>
+ </item>
+ </layout>
+ </item>
</layout>
</widget>
<widget class="QWidget" name="savesTab">
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index b0a4248e..fb093529 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -47,6 +47,18 @@ int naturalCompare(const QString& a, const QString& b)
return c;
}();
+
+ // todo: remove this once the fix is released
+ // see https://bugreports.qt.io/projects/QTBUG/issues/QTBUG-81673
+ // and https://codereview.qt-project.org/c/qt/qtbase/+/287966/5/src/corelib/text/qcollator_win.cpp
+ if (!a.size()) {
+ return b.size() ? -1 : 0;
+ }
+ if (!b.size()) {
+ return +1;
+ }
+
+
return c.compare(a, b);
}