summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-06-25 11:41:00 -0400
committerisanae <14251494+isanae@users.noreply.github.com>2019-07-02 10:10:18 -0400
commit139c33ccc4f529083b0288907caad2946a3f5a8f (patch)
treeac4d1ed9311cdfe1e59b6e825cba228a431bf649
parent86e4f65eb6a2e52d0513a8c2fe1e94cd1af9967d (diff)
various optimizations and caching
fixed conflict list not sorting when changing parameters switched from QDirIterator to std::filesystem, much faster FilterWidget precompiles the list
-rw-r--r--src/filterwidget.cpp19
-rw-r--r--src/filterwidget.h3
-rw-r--r--src/modinfodialog.cpp12
-rw-r--r--src/modinfodialogconflicts.cpp186
-rw-r--r--src/modinfodialogconflicts.h8
-rw-r--r--src/modinfodialogesps.cpp26
-rw-r--r--src/modinfodialogtextfiles.cpp15
7 files changed, 155 insertions, 114 deletions
diff --git a/src/filterwidget.cpp b/src/filterwidget.cpp
index 16a46b0e..82644658 100644
--- a/src/filterwidget.cpp
+++ b/src/filterwidget.cpp
@@ -30,21 +30,29 @@ void FilterWidget::clear()
m_edit->clear();
}
-bool FilterWidget::matches(std::function<bool (const QString& what)> pred) const
+void FilterWidget::compile()
{
+ m_compiled.clear();
+
const QStringList ORList = [&] {
QString filterCopy = QString(m_text);
filterCopy.replace("||", ";").replace("OR", ";").replace("|", ";");
return filterCopy.split(";", QString::SkipEmptyParts);
}();
- if (ORList.isEmpty() || !pred) {
+ // split in ORSegments that internally use AND logic
+ for (auto& ORSegment : ORList) {
+ m_compiled.push_back(ORSegment.split(" ", QString::SkipEmptyParts));
+ }
+}
+
+bool FilterWidget::matches(std::function<bool (const QString& what)> pred) const
+{
+ if (m_compiled.isEmpty() || !pred) {
return true;
}
- // split in ORSegments that internally use AND logic
- for (auto& ORSegment : ORList) {
- QStringList ANDKeywords = ORSegment.split(" ", QString::SkipEmptyParts);
+ for (auto& ANDKeywords : m_compiled) {
bool segmentGood = true;
// check each word in the segment for match, each word needs to be matched
@@ -115,6 +123,7 @@ void FilterWidget::onTextChanged()
if (text != m_text) {
m_text = text;
+ compile();
if (changed) {
changed();
diff --git a/src/filterwidget.h b/src/filterwidget.h
index 4fee5983..762d9b15 100644
--- a/src/filterwidget.h
+++ b/src/filterwidget.h
@@ -20,6 +20,7 @@ private:
EventFilter* m_eventFilter;
QToolButton* m_clear;
QString m_text;
+ QList<QList<QString>> m_compiled;
void unhook();
void createClear();
@@ -28,6 +29,8 @@ private:
void onTextChanged();
void onResized();
+
+ void compile();
};
#endif // FILTERWIDGET_H
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index a407e9b7..c6cdb961 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -29,6 +29,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "modinfodialogcategories.h"
#include "modinfodialognexus.h"
#include "modinfodialogfiletree.h"
+#include <filesystem>
using namespace MOBase;
using namespace MOShared;
@@ -310,12 +311,17 @@ void ModInfoDialog::updateTabs(bool becauseOriginChanged)
void ModInfoDialog::feedFiles(bool becauseOriginChanged)
{
+ namespace fs = std::filesystem;
const auto rootPath = m_mod->absolutePath();
if (rootPath.length() > 0) {
- QDirIterator dirIterator(rootPath, QDir::Files, QDirIterator::Subdirectories);
- while (dirIterator.hasNext()) {
- QString fileName = dirIterator.next();
+
+ for (const auto& entry : fs::recursive_directory_iterator(rootPath.toStdString())) {
+ if (!entry.is_regular_file()) {
+ continue;
+ }
+
+ const auto fileName = QString::fromWCharArray(entry.path().c_str());
for (auto& tabInfo : m_tabs) {
if (!tabInfo.isVisible()) {
diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp
index 03589030..52d25954 100644
--- a/src/modinfodialogconflicts.cpp
+++ b/src/modinfodialogconflicts.cpp
@@ -126,8 +126,9 @@ public:
const QString& (ConflictItem::*getText)() const;
};
- ConflictListModel(QTreeView* tree, std::vector<Column> columns)
- : m_tree(tree), m_columns(std::move(columns))
+ ConflictListModel(QTreeView* tree, std::vector<Column> columns) :
+ m_tree(tree), m_columns(std::move(columns)),
+ m_sortColumn(-1), m_sortOrder(Qt::AscendingOrder)
{
m_tree->setModel(this);
}
@@ -226,32 +227,10 @@ public:
void sort(int colIndex, Qt::SortOrder order=Qt::AscendingOrder)
{
- if (colIndex < 0) {
- return;
- }
-
- const auto c = static_cast<std::size_t>(colIndex);
- if (c >= m_columns.size()) {
- return;
- }
-
- const auto& col = m_columns[c];
-
- // avoids branching on sort order while sorting
- auto sortAsc = [&](const auto& a, const auto& b) {
- return (naturalCompare((a.*col.getText)(), (b.*col.getText)()) < 0);
- };
-
- auto sortDesc = [&](const auto& a, const auto& b) {
- return (naturalCompare((a.*col.getText)(), (b.*col.getText)()) > 0);
- };
-
- if (order == Qt::AscendingOrder) {
- std::sort(m_items.begin(), m_items.end(), sortAsc);
- } else {
- std::sort(m_items.begin(), m_items.end(), sortDesc);
- }
+ m_sortColumn = colIndex;
+ m_sortOrder = order;
+ doSort();
emit layoutChanged({}, QAbstractItemModel::VerticalSortHint);
}
@@ -263,6 +242,7 @@ public:
void finished()
{
endResetModel();
+ doSort();
}
const ConflictItem* getItem(std::size_t row) const
@@ -278,6 +258,37 @@ private:
QTreeView* m_tree;
std::vector<Column> m_columns;
std::vector<ConflictItem> m_items;
+ int m_sortColumn;
+ Qt::SortOrder m_sortOrder;
+
+ void doSort()
+ {
+ if (m_sortColumn < 0) {
+ return;
+ }
+
+ const auto c = static_cast<std::size_t>(m_sortColumn);
+ if (c >= m_columns.size()) {
+ return;
+ }
+
+ const auto& col = m_columns[c];
+
+ // avoids branching on sort order while sorting
+ auto sortAsc = [&](const auto& a, const auto& b) {
+ return (naturalCompare((a.*col.getText)(), (b.*col.getText)()) < 0);
+ };
+
+ auto sortDesc = [&](const auto& a, const auto& b) {
+ return (naturalCompare((a.*col.getText)(), (b.*col.getText)()) > 0);
+ };
+
+ if (m_sortOrder == Qt::AscendingOrder) {
+ std::sort(m_items.begin(), m_items.end(), sortAsc);
+ } else {
+ std::sort(m_items.begin(), m_items.end(), sortDesc);
+ }
+ }
};
@@ -841,8 +852,9 @@ bool GeneralConflictsTab::update()
const auto rootPath = m_tab->mod()->absolutePath();
for (const auto& file : m_tab->origin()->getFiles()) {
- const QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath()));
- const QString fileName = relativeName.mid(0).prepend(rootPath);
+ // careful: these two strings are moved into createXItem() below
+ QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath()));
+ QString fileName = rootPath + relativeName;
bool archive = false;
const int fileOrigin = file->getOrigin(archive);
@@ -851,28 +863,31 @@ bool GeneralConflictsTab::update()
if (fileOrigin == m_tab->origin()->getID()) {
if (!alternatives.empty()) {
m_overwriteModel->add(createOverwriteItem(
- file->getIndex(), archive, fileName, relativeName, alternatives));
+ file->getIndex(), archive,
+ std::move(fileName), std::move(relativeName), alternatives));
++numOverwrite;
} else {
// otherwise, put the file in the noconflict tree
m_noConflictModel->add(createNoConflictItem(
- file->getIndex(), archive, fileName, relativeName));
+ file->getIndex(), archive,
+ std::move(fileName), std::move(relativeName)));
++numNonConflicting;
}
} else {
m_overwrittenModel->add(createOverwrittenItem(
- file->getIndex(), fileOrigin, archive, fileName, relativeName));
+ file->getIndex(), fileOrigin, archive,
+ std::move(fileName), std::move(relativeName)));
++numOverwritten;
}
}
- }
- m_overwriteModel->finished();
- m_overwrittenModel->finished();
- m_noConflictModel->finished();
+ m_overwriteModel->finished();
+ m_overwrittenModel->finished();
+ m_noConflictModel->finished();
+ }
ui->overwriteCount->display(numOverwrite);
ui->overwrittenCount->display(numOverwritten);
@@ -882,43 +897,48 @@ bool GeneralConflictsTab::update()
}
ConflictItem GeneralConflictsTab::createOverwriteItem(
- FileEntry::Index index, bool archive,
- const QString& fileName, const QString& relativeName,
+ FileEntry::Index index, bool archive, QString fileName, QString relativeName,
const FileEntry::AlternativesVector& alternatives)
{
const auto& ds = *m_core.directoryStructure();
- QString altString;
+ std::wstring altString;
for (const auto& alt : alternatives) {
- if (!altString.isEmpty()) {
- altString += ", ";
+ if (!altString.empty()) {
+ altString += L", ";
}
- altString += ToQString(ds.getOriginByID(alt.first).getName());
+ altString += ds.getOriginByID(alt.first).getName();
}
- const auto origin = ToQString(ds.getOriginByID(alternatives.back().first).getName());
+ auto origin = ToQString(ds.getOriginByID(alternatives.back().first).getName());
- return {altString, relativeName, "", index, fileName, true, origin, archive};
+ return ConflictItem(
+ ToQString(altString), std::move(relativeName), QString::null, index,
+ std::move(fileName), true, std::move(origin), archive);
}
ConflictItem GeneralConflictsTab::createNoConflictItem(
- FileEntry::Index index, bool archive,
- const QString& fileName, const QString& relativeName)
+ FileEntry::Index index, bool archive, QString fileName, QString relativeName)
{
- return {"", relativeName, "", index, fileName, false, "", archive};
+ return ConflictItem(
+ QString::null, std::move(relativeName), QString::null, index,
+ std::move(fileName), false, QString::null, archive);
}
ConflictItem GeneralConflictsTab::createOverwrittenItem(
FileEntry::Index index, int fileOrigin, bool archive,
- const QString& fileName, const QString& relativeName)
+ QString fileName, QString relativeName)
{
const auto& ds = *m_core.directoryStructure();
- const FilesOrigin &realOrigin = ds.getOriginByID(fileOrigin);
+ const FilesOrigin& realOrigin = ds.getOriginByID(fileOrigin);
- return {
- "", relativeName, ToQString(realOrigin.getName()),
- index, fileName, true, ToQString(realOrigin.getName()), archive};
+ QString after = ToQString(realOrigin.getName());
+ QString altOrigin = after;
+
+ return ConflictItem(
+ QString::null, std::move(relativeName), std::move(after),
+ index, std::move(fileName), true, std::move(altOrigin), archive);
}
void GeneralConflictsTab::onOverwriteActivated(const QModelIndex& index)
@@ -1048,8 +1068,9 @@ void AdvancedConflictsTab::update()
m_model->reserve(files.size());
for (const auto& file : files) {
- const QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath()));
- const QString fileName = relativeName.mid(0).prepend(rootPath);
+ // careful: these two strings are moved into createItem() below
+ QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath()));
+ QString fileName = rootPath + relativeName;
bool archive = false;
const int fileOrigin = file->getOrigin(archive);
@@ -1057,7 +1078,7 @@ void AdvancedConflictsTab::update()
auto item = createItem(
file->getIndex(), fileOrigin, archive,
- fileName, relativeName, alternatives);
+ std::move(fileName), std::move(relativeName), alternatives);
if (item) {
m_model->add(std::move(*item));
@@ -1070,39 +1091,41 @@ void AdvancedConflictsTab::update()
std::optional<ConflictItem> AdvancedConflictsTab::createItem(
FileEntry::Index index, int fileOrigin, bool archive,
- const QString& fileName, const QString& relativeName,
+ QString fileName, QString relativeName,
const MOShared::FileEntry::AlternativesVector& alternatives)
{
const auto& ds = *m_core.directoryStructure();
- QString before, after;
+ std::wstring before, after;
if (!alternatives.empty()) {
+ const bool showAllAlts = ui->conflictsAdvancedShowAll->isChecked();
+
int beforePrio = 0;
int afterPrio = std::numeric_limits<int>::max();
for (const auto& alt : alternatives)
{
- const auto altOrigin = ds.getOriginByID(alt.first);
+ const auto& altOrigin = ds.getOriginByID(alt.first);
- if (ui->conflictsAdvancedShowAll->isChecked()) {
+ if (showAllAlts) {
// fills 'before' and 'after' with all the alternatives that come
// before and after this mod in terms of priority
if (altOrigin.getPriority() < m_tab->origin()->getPriority()) {
// add all the mods having a lower priority than this one
- if (!before.isEmpty()) {
- before += ", ";
+ if (!before.empty()) {
+ before += L", ";
}
- before += ToQString(altOrigin.getName());
+ before += altOrigin.getName();
} else if (altOrigin.getPriority() > m_tab->origin()->getPriority()) {
// add all the mods having a higher priority than this one
- if (!after.isEmpty()) {
- after += ", ";
+ if (!after.empty()) {
+ after += L", ";
}
- after += ToQString(altOrigin.getName());
+ after += altOrigin.getName();
}
} else {
// keep track of the nearest mods that come before and after this one
@@ -1114,7 +1137,7 @@ std::optional<ConflictItem> AdvancedConflictsTab::createItem(
if (altOrigin.getPriority() > beforePrio) {
// the alternative has a higher priority and therefore is closer
// to this mod, use it
- before = ToQString(altOrigin.getName());
+ before = altOrigin.getName();
beforePrio = altOrigin.getPriority();
}
}
@@ -1125,7 +1148,7 @@ std::optional<ConflictItem> AdvancedConflictsTab::createItem(
if (altOrigin.getPriority() < afterPrio) {
// the alternative has a lower priority and there is closer
// to this mod, use it
- after = ToQString(altOrigin.getName());
+ after = altOrigin.getName();
afterPrio = altOrigin.getPriority();
}
}
@@ -1140,41 +1163,46 @@ std::optional<ConflictItem> AdvancedConflictsTab::createItem(
// nearest mods, it's not worth checking for the primary origin because it
// will always have a higher priority than the alternatives (or it wouldn't
// be the primary)
- if (after.isEmpty() || ui->conflictsAdvancedShowAll->isChecked()) {
- FilesOrigin &realOrigin = ds.getOriginByID(fileOrigin);
+ if (after.empty() || showAllAlts) {
+ const FilesOrigin& realOrigin = ds.getOriginByID(fileOrigin);
// if no mods overwrite this file, the primary origin is the same as this
// mod, so ignore that
if (realOrigin.getID() != m_tab->origin()->getID()) {
- if (!after.isEmpty()) {
- after += ", ";
+ if (!after.empty()) {
+ after += L", ";
}
- after += ToQString(realOrigin.getName());
+ after += realOrigin.getName();
}
}
}
- bool hasAlts = !before.isEmpty() || !after.isEmpty();
+ const bool hasAlts = !before.empty() || !after.empty();
- if (!ui->conflictsAdvancedShowNoConflict->isChecked()) {
+ if (!hasAlts) {
// if both before and after are empty, it means this file has no conflicts
// at all, only display it if the user wants it
- if (!hasAlts) {
+ if (!ui->conflictsAdvancedShowNoConflict->isChecked()) {
return {};
}
}
- bool matched = m_filter.matches([&](auto&& what) {
+ auto beforeQS = QString::fromStdWString(before);
+ auto afterQS = QString::fromStdWString(after);
+
+ const bool matched = m_filter.matches([&](auto&& what) {
return
- before.contains(what, Qt::CaseInsensitive) ||
+ beforeQS.contains(what, Qt::CaseInsensitive) ||
relativeName.contains(what, Qt::CaseInsensitive) ||
- after.contains(what, Qt::CaseInsensitive);
+ afterQS.contains(what, Qt::CaseInsensitive);
});
if (!matched) {
return {};
}
- return ConflictItem{before, relativeName, after, index, fileName, hasAlts, "", archive};
+ return ConflictItem(
+ std::move(beforeQS), std::move(relativeName), std::move(afterQS),
+ index, std::move(fileName), hasAlts, QString::null, archive);
}
diff --git a/src/modinfodialogconflicts.h b/src/modinfodialogconflicts.h
index f0c0c589..fc7dd32a 100644
--- a/src/modinfodialogconflicts.h
+++ b/src/modinfodialogconflicts.h
@@ -47,16 +47,16 @@ private:
ConflictItem createOverwriteItem(
MOShared::FileEntry::Index index, bool archive,
- const QString& fileName, const QString& relativeName,
+ QString fileName, QString relativeName,
const MOShared::FileEntry::AlternativesVector& alternatives);
ConflictItem createNoConflictItem(
MOShared::FileEntry::Index index, bool archive,
- const QString& fileName, const QString& relativeName);
+ QString fileName, QString relativeName);
ConflictItem createOverwrittenItem(
MOShared::FileEntry::Index index, int fileOrigin, bool archive,
- const QString& fileName, const QString& relativeName);
+ QString fileName, QString relativeName);
void onOverwriteActivated(const QModelIndex& index);
void onOverwrittenActivated(const QModelIndex& index);
@@ -93,7 +93,7 @@ private:
std::optional<ConflictItem> createItem(
MOShared::FileEntry::Index index, int fileOrigin, bool archive,
- const QString& fileName, const QString& relativeName,
+ QString fileName, QString relativeName,
const MOShared::FileEntry::AlternativesVector& alternatives);
};
diff --git a/src/modinfodialogesps.cpp b/src/modinfodialogesps.cpp
index 3f742bae..ecb341e8 100644
--- a/src/modinfodialogesps.cpp
+++ b/src/modinfodialogesps.cpp
@@ -18,7 +18,7 @@ public:
m_active = true;
}
- updateFilename();
+ pathChanged();
}
const QString& rootPath() const
@@ -50,9 +50,9 @@ public:
return m_inactivePath;
}
- QFileInfo fileInfo() const
+ const QFileInfo& fileInfo() const
{
- return m_rootPath + QDir::separator() + relativePath();
+ return m_fileInfo;
}
bool isActive() const
@@ -73,7 +73,7 @@ public:
m_inactivePath = QFileInfo(m_inactivePath).path() + QDir::separator() + newName;
}
- updateFilename();
+ pathChanged();
return true;
}
@@ -88,7 +88,7 @@ public:
if (root.rename(m_activePath, newName)) {
m_active = false;
m_inactivePath = newName;
- updateFilename();
+ pathChanged();
return true;
}
@@ -100,11 +100,13 @@ private:
QString m_activePath;
QString m_inactivePath;
QString m_filename;
+ QFileInfo m_fileInfo;
bool m_active;
- void updateFilename()
+ void pathChanged()
{
- m_filename = fileInfo().fileName();
+ m_fileInfo.setFile(m_rootPath + QDir::separator() + relativePath());
+ m_filename = m_fileInfo.fileName();
}
};
@@ -246,15 +248,11 @@ void ESPsTab::clear()
bool ESPsTab::feedFile(const QString& rootPath, const QString& fullPath)
{
- static constexpr const char* extensions[] = {
- ".esp", ".esm", ".esl"
- };
+ static const QString extensions[] = {".esp", ".esm", ".esl"};
- for (const auto* e : extensions) {
+ for (const auto& e : extensions) {
if (fullPath.endsWith(e, Qt::CaseInsensitive)) {
- QString relativePath = fullPath.mid(rootPath.length() + 1);
-
- ESPItem esp(rootPath, relativePath);
+ ESPItem esp(rootPath, fullPath.mid(rootPath.length() + 1));
if (esp.isActive()) {
m_activeModel->add(std::move(esp));
diff --git a/src/modinfodialogtextfiles.cpp b/src/modinfodialogtextfiles.cpp
index 25d799b1..675a4c79 100644
--- a/src/modinfodialogtextfiles.cpp
+++ b/src/modinfodialogtextfiles.cpp
@@ -202,11 +202,9 @@ TextFilesTab::TextFilesTab(
bool TextFilesTab::wantsFile(const QString& rootPath, const QString& fullPath) const
{
- static constexpr const char* extensions[] = {
- ".txt"
- };
+ static const QString extensions[] = {".txt"};
- for (const auto* e : extensions) {
+ for (const auto& e : extensions) {
if (fullPath.endsWith(e, Qt::CaseInsensitive)) {
return true;
}
@@ -226,13 +224,12 @@ IniFilesTab::IniFilesTab(
bool IniFilesTab::wantsFile(const QString& rootPath, const QString& fullPath) const
{
- static constexpr const char* extensions[] = {
- ".ini", ".cfg"
- };
+ static const QString extensions[] = {".ini", ".cfg"};
+ static const QString meta("meta.ini");
- for (const auto* e : extensions) {
+ for (const auto& e : extensions) {
if (fullPath.endsWith(e, Qt::CaseInsensitive)) {
- if (!fullPath.endsWith("meta.ini")) {
+ if (!fullPath.endsWith(meta)) {
return true;
}
}