From 157168e73a7628522f81ddca77716024638b412f Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 14:31:49 -0400 Subject: split refreshLists() in two --- src/modinfodialog.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index b6a21705..d1ce7f65 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -596,6 +596,12 @@ QByteArray ModInfoDialog::saveConflictExpandersState() const } void ModInfoDialog::refreshLists() +{ + refreshConflictLists(); + refreshFiles(); +} + +void ModInfoDialog::refreshConflictLists() { int numNonConflicting = 0; int numOverwrite = 0; @@ -616,7 +622,7 @@ void ModInfoDialog::refreshLists() if (!alternatives.empty()) { std::wostringstream altString; for (std::vector>>::iterator altIter = alternatives.begin(); - altIter != alternatives.end(); ++altIter) { + altIter != alternatives.end(); ++altIter) { if (altIter != alternatives.begin()) { altString << ", "; } @@ -669,6 +675,13 @@ void ModInfoDialog::refreshLists() } } + ui->overwriteCount->display(numOverwrite); + ui->overwrittenCount->display(numOverwritten); + ui->noConflictCount->display(numNonConflicting); +} + +void ModInfoDialog::refreshFiles() +{ if (m_RootPath.length() > 0) { QDirIterator dirIterator(m_RootPath, QDir::Files, QDirIterator::Subdirectories); while (dirIterator.hasNext()) { @@ -677,7 +690,7 @@ void ModInfoDialog::refreshLists() if (fileName.endsWith(".txt", Qt::CaseInsensitive)) { ui->textFileList->addItem(fileName.mid(m_RootPath.length() + 1)); } else if ((fileName.endsWith(".ini", Qt::CaseInsensitive) || fileName.endsWith(".cfg", Qt::CaseInsensitive)) && - !fileName.endsWith("meta.ini")) { + !fileName.endsWith("meta.ini")) { QString namePart = fileName.mid(m_RootPath.length() + 1); if (namePart.startsWith("INI Tweaks", Qt::CaseInsensitive)) { QListWidgetItem *newItem = new QListWidgetItem(namePart.mid(11), ui->iniTweaksList); @@ -689,8 +702,8 @@ void ModInfoDialog::refreshLists() ui->iniFileList->addItem(namePart); } } else if (fileName.endsWith(".esp", Qt::CaseInsensitive) || - fileName.endsWith(".esm", Qt::CaseInsensitive) || - fileName.endsWith(".esl", Qt::CaseInsensitive)) { + fileName.endsWith(".esm", Qt::CaseInsensitive) || + fileName.endsWith(".esl", Qt::CaseInsensitive)) { QString relativePath = fileName.mid(m_RootPath.length() + 1); if (relativePath.contains('/')) { QFileInfo fileInfo(fileName); @@ -701,7 +714,7 @@ void ModInfoDialog::refreshLists() ui->activeESPList->addItem(relativePath); } } else if ((fileName.endsWith(".png", Qt::CaseInsensitive)) || - (fileName.endsWith(".jpg", Qt::CaseInsensitive))) { + (fileName.endsWith(".jpg", Qt::CaseInsensitive))) { QImage image = QImage(fileName); if (!image.isNull()) { if (static_cast(image.width()) / static_cast(image.height()) > 1.34) { @@ -719,13 +732,8 @@ void ModInfoDialog::refreshLists() } } } - - ui->overwriteCount->display(numOverwrite); - ui->overwrittenCount->display(numOverwritten); - ui->noConflictCount->display(numNonConflicting); } - void ModInfoDialog::addCategories(const CategoryFactory &factory, const std::set &enabledCategories, QTreeWidgetItem *root, int rootLevel) { for (int i = 0; i < static_cast(factory.numCategories()); ++i) { -- cgit v1.3.1 From 3666995ce1c02bcb3b7937dfc112c84e81c4fead Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 14:39:22 -0400 Subject: changed iterator loops to ranged for added some autos here and there added some whitespace --- src/modinfodialog.cpp | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index d1ce7f65..f330703a 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -613,62 +613,76 @@ void ModInfoDialog::refreshConflictLists() if (m_Origin != nullptr) { std::vector files = m_Origin->getFiles(); - for (auto iter = files.begin(); iter != files.end(); ++iter) { - QString relativeName = QDir::fromNativeSeparators(ToQString((*iter)->getRelativePath())); + + for (const auto& file : m_Origin->getFiles()) { + QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath())); QString fileName = relativeName.mid(0).prepend(m_RootPath); - bool archive; - if ((*iter)->getOrigin(archive) == m_Origin->getID()) { - std::vector>> alternatives = (*iter)->getAlternatives(); + bool archive = false; + + if (file->getOrigin(archive) == m_Origin->getID()) { + const auto& alternatives = file->getAlternatives(); + if (!alternatives.empty()) { - std::wostringstream altString; - for (std::vector>>::iterator altIter = alternatives.begin(); - altIter != alternatives.end(); ++altIter) { - if (altIter != alternatives.begin()) { - altString << ", "; + QString altString; + + for (const auto& alt : alternatives) { + if (!altString.isEmpty()) { + altString += ", "; } - altString << m_Directory->getOriginByID(altIter->first).getName(); + + altString += ToQString(m_Directory->getOriginByID(alt.first).getName()); } + QStringList fields(relativeName); - fields.append(ToQString(altString.str())); + fields.append(altString); QTreeWidgetItem *item = new QTreeWidgetItem(fields); item->setData(0, Qt::UserRole, fileName); item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives.back().first).getName())); item->setData(1, Qt::UserRole + 1, alternatives.back().first); item->setData(1, Qt::UserRole + 2, archive); + if (archive) { QFont font = item->font(0); font.setItalic(true); item->setFont(0, font); item->setFont(1, font); } + ui->overwriteTree->addTopLevelItem(item); ++numOverwrite; - } else {// otherwise, put the file in the nonconflict tree + } else { + // otherwise, put the file in the nonconflict tree QTreeWidgetItem *item = new QTreeWidgetItem(QStringList({relativeName})); item->setData(0, Qt::UserRole, fileName); + if (archive) { QFont font = item->font(0); font.setItalic(true); item->setFont(0, font); } + ui->noConflictTree->addTopLevelItem(item); ++numNonConflicting; } } else { - FilesOrigin &realOrigin = m_Directory->getOriginByID((*iter)->getOrigin(archive)); + const FilesOrigin &realOrigin = m_Directory->getOriginByID(file->getOrigin(archive)); + QStringList fields(relativeName); fields.append(ToQString(realOrigin.getName())); + QTreeWidgetItem *item = new QTreeWidgetItem(fields); item->setData(0, Qt::UserRole, fileName); item->setData(1, Qt::UserRole, ToQString(realOrigin.getName())); item->setData(1, Qt::UserRole + 2, archive); + if (archive) { QFont font = item->font(0); font.setItalic(true); item->setFont(0, font); item->setFont(1, font); } + ui->overwrittenTree->addTopLevelItem(item); ++numOverwritten; } -- cgit v1.3.1 From d168b5db084457a106c5bb155be6eca5013f77c0 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 14:55:01 -0400 Subject: added AlternativesVector typedef to FileEntry split item creation from refreshConflictLists() --- src/modinfodialog.cpp | 130 ++++++++++++++++++++++++++------------------ src/modinfodialog.h | 11 ++++ src/shared/directoryentry.h | 6 +- 3 files changed, 92 insertions(+), 55 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index f330703a..f5b6abc8 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -623,67 +623,21 @@ void ModInfoDialog::refreshConflictLists() const auto& alternatives = file->getAlternatives(); if (!alternatives.empty()) { - QString altString; + ui->overwriteTree->addTopLevelItem(createOverwriteItem( + archive, fileName, relativeName, alternatives)); - for (const auto& alt : alternatives) { - if (!altString.isEmpty()) { - altString += ", "; - } - - altString += ToQString(m_Directory->getOriginByID(alt.first).getName()); - } - - QStringList fields(relativeName); - fields.append(altString); - - QTreeWidgetItem *item = new QTreeWidgetItem(fields); - item->setData(0, Qt::UserRole, fileName); - item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives.back().first).getName())); - item->setData(1, Qt::UserRole + 1, alternatives.back().first); - item->setData(1, Qt::UserRole + 2, archive); - - if (archive) { - QFont font = item->font(0); - font.setItalic(true); - item->setFont(0, font); - item->setFont(1, font); - } - - ui->overwriteTree->addTopLevelItem(item); ++numOverwrite; } else { // otherwise, put the file in the nonconflict tree - QTreeWidgetItem *item = new QTreeWidgetItem(QStringList({relativeName})); - item->setData(0, Qt::UserRole, fileName); + ui->noConflictTree->addTopLevelItem(createNoConflictItem( + archive, fileName, relativeName)); - if (archive) { - QFont font = item->font(0); - font.setItalic(true); - item->setFont(0, font); - } - - ui->noConflictTree->addTopLevelItem(item); ++numNonConflicting; } } else { - const FilesOrigin &realOrigin = m_Directory->getOriginByID(file->getOrigin(archive)); - - QStringList fields(relativeName); - fields.append(ToQString(realOrigin.getName())); + ui->overwrittenTree->addTopLevelItem(createOverwrittenItem( + file, archive, fileName, relativeName)); - QTreeWidgetItem *item = new QTreeWidgetItem(fields); - item->setData(0, Qt::UserRole, fileName); - item->setData(1, Qt::UserRole, ToQString(realOrigin.getName())); - item->setData(1, Qt::UserRole + 2, archive); - - if (archive) { - QFont font = item->font(0); - font.setItalic(true); - item->setFont(0, font); - item->setFont(1, font); - } - - ui->overwrittenTree->addTopLevelItem(item); ++numOverwritten; } } @@ -694,6 +648,78 @@ void ModInfoDialog::refreshConflictLists() ui->noConflictCount->display(numNonConflicting); } +QTreeWidgetItem* ModInfoDialog::createOverwriteItem( + bool archive, const QString& fileName, const QString& relativeName, + const FileEntry::AlternativesVector& alternatives) +{ + QString altString; + + for (const auto& alt : alternatives) { + if (!altString.isEmpty()) { + altString += ", "; + } + + altString += ToQString(m_Directory->getOriginByID(alt.first).getName()); + } + + QStringList fields(relativeName); + fields.append(altString); + + QTreeWidgetItem *item = new QTreeWidgetItem(fields); + item->setData(0, Qt::UserRole, fileName); + item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives.back().first).getName())); + item->setData(1, Qt::UserRole + 1, alternatives.back().first); + item->setData(1, Qt::UserRole + 2, archive); + + if (archive) { + QFont font = item->font(0); + font.setItalic(true); + item->setFont(0, font); + item->setFont(1, font); + } + + return item; +} + +QTreeWidgetItem* ModInfoDialog::createNoConflictItem( + bool archive, const QString& fileName, const QString& relativeName) +{ + QTreeWidgetItem *item = new QTreeWidgetItem(QStringList({relativeName})); + item->setData(0, Qt::UserRole, fileName); + + if (archive) { + QFont font = item->font(0); + font.setItalic(true); + item->setFont(0, font); + } + + return item; +} + +QTreeWidgetItem* ModInfoDialog::createOverwrittenItem( + const MOShared::FileEntry::Ptr& file, + bool archive, const QString& fileName, const QString& relativeName) +{ + const FilesOrigin &realOrigin = m_Directory->getOriginByID(file->getOrigin(archive)); + + QStringList fields(relativeName); + fields.append(ToQString(realOrigin.getName())); + + QTreeWidgetItem *item = new QTreeWidgetItem(fields); + item->setData(0, Qt::UserRole, fileName); + item->setData(1, Qt::UserRole, ToQString(realOrigin.getName())); + item->setData(1, Qt::UserRole + 2, archive); + + if (archive) { + QFont font = item->font(0); + font.setItalic(true); + item->setFont(0, font); + item->setFont(1, font); + } + + return item; +} + void ModInfoDialog::refreshFiles() { if (m_RootPath.length() > 0) { diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 95b9db9c..3c193cd3 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -432,6 +432,17 @@ private: void refreshConflictLists(); void refreshFiles(); + QTreeWidgetItem* createOverwriteItem( + bool archive, const QString& fileName, const QString& relativeName, + const MOShared::FileEntry::AlternativesVector& alternatives); + + QTreeWidgetItem* createNoConflictItem( + bool archive, const QString& fileName, const QString& relativeName); + + QTreeWidgetItem* createOverwrittenItem( + const MOShared::FileEntry::Ptr& file, + bool archive, const QString& fileName, const QString& relativeName); + void restoreTabState(const QByteArray &state); void restoreConflictExpandersState(const QByteArray &state); diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index 12cef11d..e7af1ae7 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -49,8 +49,8 @@ class FileEntry { public: typedef unsigned int Index; - typedef boost::shared_ptr Ptr; + typedef std::vector>> AlternativesVector; public: @@ -72,7 +72,7 @@ public: // gets the list of alternative origins (origins with lower priority than the primary one). // if sortOrigins has been called, it is sorted by priority (ascending) - const std::vector>> &getAlternatives() const { return m_Alternatives; } + const AlternativesVector &getAlternatives() const { return m_Alternatives; } const std::wstring &getName() const { return m_Name; } int getOrigin() const { return m_Origin; } @@ -98,7 +98,7 @@ private: std::wstring m_Name; int m_Origin = -1; std::pair m_Archive; - std::vector>> m_Alternatives; + AlternativesVector m_Alternatives; DirectoryEntry *m_Parent; mutable FILETIME m_FileTime; -- cgit v1.3.1 From ab385347afc3317049d85a5ee4b011592d8b3dce Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 15:39:09 -0400 Subject: allow for refreshing individual conflict tabs advanced conflict list now has items --- src/modinfodialog.cpp | 132 +++++++++++++++++++++++++++++++++++++++----------- src/modinfodialog.h | 11 +++-- src/modinfodialog.ui | 3 ++ 3 files changed, 116 insertions(+), 30 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index f5b6abc8..2d2cc559 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -437,6 +437,10 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo m_overwriteExpander.set(ui->overwriteExpander, ui->overwriteTree, true); m_overwrittenExpander.set(ui->overwrittenExpander, ui->overwrittenTree, true); m_nonconflictExpander.set(ui->noConflictExpander, ui->noConflictTree); + + connect(ui->conflictsAdvancedShowNoConflict, &QCheckBox::clicked, [&] { + refreshConflictLists(false, true); + }); } @@ -597,55 +601,76 @@ QByteArray ModInfoDialog::saveConflictExpandersState() const void ModInfoDialog::refreshLists() { - refreshConflictLists(); + refreshConflictLists(true, true); refreshFiles(); } -void ModInfoDialog::refreshConflictLists() +void ModInfoDialog::refreshConflictLists( + bool refreshGeneral, bool refreshAdvanced) { int numNonConflicting = 0; int numOverwrite = 0; int numOverwritten = 0; - ui->overwriteTree->clear(); - ui->overwrittenTree->clear(); - ui->noConflictTree->clear(); + if (refreshGeneral) { + ui->overwriteTree->clear(); + ui->overwrittenTree->clear(); + ui->noConflictTree->clear(); + } + + if (refreshAdvanced) { + ui->conflictsAdvancedList->clear(); + } if (m_Origin != nullptr) { std::vector files = m_Origin->getFiles(); for (const auto& file : m_Origin->getFiles()) { - QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath())); - QString fileName = relativeName.mid(0).prepend(m_RootPath); + const QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath())); + const QString fileName = relativeName.mid(0).prepend(m_RootPath); + bool archive = false; + const int fileOrigin = file->getOrigin(archive); + const auto& alternatives = file->getAlternatives(); - if (file->getOrigin(archive) == m_Origin->getID()) { - const auto& alternatives = file->getAlternatives(); + if (refreshGeneral) { + if (fileOrigin == m_Origin->getID()) { + if (!alternatives.empty()) { + ui->overwriteTree->addTopLevelItem(createOverwriteItem( + archive, fileName, relativeName, alternatives)); - if (!alternatives.empty()) { - ui->overwriteTree->addTopLevelItem(createOverwriteItem( - archive, fileName, relativeName, alternatives)); + ++numOverwrite; + } else { + // otherwise, put the file in the noconflict tree + ui->noConflictTree->addTopLevelItem(createNoConflictItem( + archive, fileName, relativeName)); - ++numOverwrite; + ++numNonConflicting; + } } else { - // otherwise, put the file in the nonconflict tree - ui->noConflictTree->addTopLevelItem(createNoConflictItem( - archive, fileName, relativeName)); + ui->overwrittenTree->addTopLevelItem(createOverwrittenItem( + fileOrigin, archive, fileName, relativeName)); - ++numNonConflicting; + ++numOverwritten; } - } else { - ui->overwrittenTree->addTopLevelItem(createOverwrittenItem( - file, archive, fileName, relativeName)); + } + + if (refreshAdvanced) { + auto* advancedItem = createAdvancedConflictItem( + fileOrigin, archive, fileName, relativeName, alternatives); - ++numOverwritten; + if (advancedItem) { + ui->conflictsAdvancedList->addTopLevelItem(advancedItem); + } } } } - ui->overwriteCount->display(numOverwrite); - ui->overwrittenCount->display(numOverwritten); - ui->noConflictCount->display(numNonConflicting); + if (refreshGeneral) { + ui->overwriteCount->display(numOverwrite); + ui->overwrittenCount->display(numOverwritten); + ui->noConflictCount->display(numNonConflicting); + } } QTreeWidgetItem* ModInfoDialog::createOverwriteItem( @@ -697,10 +722,10 @@ QTreeWidgetItem* ModInfoDialog::createNoConflictItem( } QTreeWidgetItem* ModInfoDialog::createOverwrittenItem( - const MOShared::FileEntry::Ptr& file, - bool archive, const QString& fileName, const QString& relativeName) + int fileOrigin, bool archive, + const QString& fileName, const QString& relativeName) { - const FilesOrigin &realOrigin = m_Directory->getOriginByID(file->getOrigin(archive)); + const FilesOrigin &realOrigin = m_Directory->getOriginByID(fileOrigin); QStringList fields(relativeName); fields.append(ToQString(realOrigin.getName())); @@ -720,6 +745,59 @@ QTreeWidgetItem* ModInfoDialog::createOverwrittenItem( return item; } +QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( + int fileOrigin, bool archive, + const QString& fileName, const QString& relativeName, + const MOShared::FileEntry::AlternativesVector& alternatives) +{ + QString before, after; + + if (!alternatives.empty()) { + int beforePrio = 0; + int afterPrio = std::numeric_limits::max(); + + for (const auto& alt : alternatives) + { + auto altOrigin = m_Directory->getOriginByID(alt.first); + + if (altOrigin.getPriority() > beforePrio) { + if (altOrigin.getPriority() < m_Origin->getPriority()) { + before = ToQString(altOrigin.getName()); + beforePrio = altOrigin.getPriority(); + } + } + + if (altOrigin.getPriority() < afterPrio) { + if (altOrigin.getPriority() > m_Origin->getPriority()) { + after = ToQString(altOrigin.getName()); + afterPrio = altOrigin.getPriority(); + } + } + } + + if (after.isEmpty()) { + FilesOrigin &realOrigin = m_Directory->getOriginByID(fileOrigin); + + if (realOrigin.getID() != m_Origin->getID()) { + after = ToQString(realOrigin.getName()); + } + } + } + + if (!ui->conflictsAdvancedShowNoConflict->isChecked()) { + if (before.isEmpty() && after.isEmpty()) { + return nullptr; + } + } + + QTreeWidgetItem* item = new QTreeWidgetItem; + item->setText(0, before); + item->setText(1, relativeName); + item->setText(2, after); + + return item; +} + void ModInfoDialog::refreshFiles() { if (m_RootPath.length() > 0) { diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 3c193cd3..69b0069e 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -429,7 +429,7 @@ private: ExpanderWidget m_overwriteExpander, m_overwrittenExpander, m_nonconflictExpander; - void refreshConflictLists(); + void refreshConflictLists(bool refreshGeneral, bool refreshAdvanced); void refreshFiles(); QTreeWidgetItem* createOverwriteItem( @@ -440,8 +440,13 @@ private: bool archive, const QString& fileName, const QString& relativeName); QTreeWidgetItem* createOverwrittenItem( - const MOShared::FileEntry::Ptr& file, - bool archive, const QString& fileName, const QString& relativeName); + int fileOrigin, bool archive, + const QString& fileName, const QString& relativeName); + + QTreeWidgetItem* createAdvancedConflictItem( + int fileOrigin, bool archive, + const QString& fileName, const QString& relativeName, + const MOShared::FileEntry::AlternativesVector& alternatives); void restoreTabState(const QByteArray &state); void restoreConflictExpandersState(const QByteArray &state); diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 190f5b56..b31f49d3 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -744,6 +744,9 @@ text-align: left; Show files that have no conflicts + + true + -- cgit v1.3.1 From 260462fe6dd37899744b95f777cdff3c738fad2c Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 16:10:10 -0400 Subject: added show all/nearest mods radio buttons --- src/modinfodialog.cpp | 48 ++++++++++++++++++++++++++++++++++++++---------- src/modinfodialog.ui | 17 +++++++++++++++++ 2 files changed, 55 insertions(+), 10 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 2d2cc559..e35aa0e1 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -441,6 +441,14 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo connect(ui->conflictsAdvancedShowNoConflict, &QCheckBox::clicked, [&] { refreshConflictLists(false, true); }); + + connect(ui->conflictsAdvancedShowAll, &QRadioButton::clicked, [&] { + refreshConflictLists(false, true); + }); + + connect(ui->conflictsAdvancedShowNearest, &QRadioButton::clicked, [&] { + refreshConflictLists(false, true); + }); } @@ -760,26 +768,46 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( { auto altOrigin = m_Directory->getOriginByID(alt.first); - if (altOrigin.getPriority() > beforePrio) { + if (ui->conflictsAdvancedShowAll->isChecked()) { if (altOrigin.getPriority() < m_Origin->getPriority()) { - before = ToQString(altOrigin.getName()); - beforePrio = altOrigin.getPriority(); + if (!before.isEmpty()) { + before += ", "; + } + + before += ToQString(altOrigin.getName()); + } else if (altOrigin.getPriority() > m_Origin->getPriority()) { + if (!after.isEmpty()) { + after += ", "; + } + + after += ToQString(altOrigin.getName()); + } + } else { + if (altOrigin.getPriority() > beforePrio) { + if (altOrigin.getPriority() < m_Origin->getPriority()) { + before = ToQString(altOrigin.getName()); + beforePrio = altOrigin.getPriority(); + } } - } - if (altOrigin.getPriority() < afterPrio) { - if (altOrigin.getPriority() > m_Origin->getPriority()) { - after = ToQString(altOrigin.getName()); - afterPrio = altOrigin.getPriority(); + if (altOrigin.getPriority() < afterPrio) { + if (altOrigin.getPriority() > m_Origin->getPriority()) { + after = ToQString(altOrigin.getName()); + afterPrio = altOrigin.getPriority(); + } } } } - if (after.isEmpty()) { + if (after.isEmpty() || ui->conflictsAdvancedShowAll->isChecked()) { FilesOrigin &realOrigin = m_Directory->getOriginByID(fileOrigin); if (realOrigin.getID() != m_Origin->getID()) { - after = ToQString(realOrigin.getName()); + if (!after.isEmpty()) { + after += ", "; + } + + after += ToQString(realOrigin.getName()); } } } diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index b31f49d3..e391da46 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -749,6 +749,23 @@ text-align: left; + + + + Show all conflicting mods + + + true + + + + + + + Show nearest conflicting mod + + + -- cgit v1.3.1 From a202170aab35bc486114896e011239b1ef560aad Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 16:22:57 -0400 Subject: comments, switched some of the ifs for clarity --- src/modinfodialog.cpp | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index e35aa0e1..c936f150 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -766,16 +766,21 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( for (const auto& alt : alternatives) { - auto altOrigin = m_Directory->getOriginByID(alt.first); + const auto altOrigin = m_Directory->getOriginByID(alt.first); if (ui->conflictsAdvancedShowAll->isChecked()) { + // fills 'before' and 'after' with all the alternatives that come + // before and after this mod in terms of priority + if (altOrigin.getPriority() < m_Origin->getPriority()) { + // add all the mods having a lower priority than this one if (!before.isEmpty()) { before += ", "; } before += ToQString(altOrigin.getName()); } else if (altOrigin.getPriority() > m_Origin->getPriority()) { + // add all the mods having a higher priority than this one if (!after.isEmpty()) { after += ", "; } @@ -783,15 +788,26 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( after += ToQString(altOrigin.getName()); } } else { - if (altOrigin.getPriority() > beforePrio) { - if (altOrigin.getPriority() < m_Origin->getPriority()) { + // keep track of the nearest mods that come before and after this one + // in terms of priority + + if (altOrigin.getPriority() < m_Origin->getPriority()) { + // the alternative has a lower priority than this mod + + if (altOrigin.getPriority() > beforePrio) { + // the alternative has a higher priority and therefore is closer + // to this mod, use it before = ToQString(altOrigin.getName()); beforePrio = altOrigin.getPriority(); } } - if (altOrigin.getPriority() < afterPrio) { - if (altOrigin.getPriority() > m_Origin->getPriority()) { + if (altOrigin.getPriority() > m_Origin->getPriority()) { + // the alternative has a higher priority than this mod + + if (altOrigin.getPriority() < afterPrio) { + // the alternative has a lower priority and there is closer + // to this mod, use it after = ToQString(altOrigin.getName()); afterPrio = altOrigin.getPriority(); } @@ -799,9 +815,19 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( } } + // the primary origin is never in the list of alternatives, so it has to + // be handled separately + // + // if 'after' is not empty, it means at least one alternative with a higher + // priority than this mod was found; if the user only wants to see the + // 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 = m_Directory->getOriginByID(fileOrigin); + // if no mods overwrite this file, the primary origin is the same as this + // mod, so ignore that if (realOrigin.getID() != m_Origin->getID()) { if (!after.isEmpty()) { after += ", "; @@ -813,6 +839,8 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( } if (!ui->conflictsAdvancedShowNoConflict->isChecked()) { + // 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 (before.isEmpty() && after.isEmpty()) { return nullptr; } -- cgit v1.3.1 From 64604c966aaade7ceb9f5e547dfad8f51372434c Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 16:44:11 -0400 Subject: elide first two columns of the advanced list --- src/modinfodialog.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index c936f150..9db31da3 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -319,6 +319,20 @@ bool ExpanderWidget::opened() const } +class ElideLeftDelegate : public QStyledItemDelegate +{ +public: + using QStyledItemDelegate::QStyledItemDelegate; + +protected: + void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const + { + QStyledItemDelegate::initStyleOption(option, index); + option->textElideMode = Qt::ElideLeft; + } +}; + + ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directory, bool unmanaged, OrganizerCore *organizerCore, PluginContainer *pluginContainer, QWidget *parent) : TutorableDialog("ModInfoDialog", parent), ui(new Ui::ModInfoDialog), m_ModInfo(modInfo), m_ThumbnailMapper(this), m_RequestStarted(false), @@ -438,6 +452,17 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo m_overwrittenExpander.set(ui->overwrittenExpander, ui->overwrittenTree, true); m_nonconflictExpander.set(ui->noConflictExpander, ui->noConflictTree); + + // left-elide the overwrites column so that the nearest are visible + ui->conflictsAdvancedList->setItemDelegateForColumn( + 0, new ElideLeftDelegate(ui->conflictsAdvancedList)); + + // left-elide the file column to see filenames + ui->conflictsAdvancedList->setItemDelegateForColumn( + 1, new ElideLeftDelegate(ui->conflictsAdvancedList)); + + // don't elide the overwritten by column so that the nearest are visible + connect(ui->conflictsAdvancedShowNoConflict, &QCheckBox::clicked, [&] { refreshConflictLists(false, true); }); -- cgit v1.3.1 From 4d90e502266dfb886e1d089fb26780d19a38e5a7 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Wed, 29 May 2019 09:45:30 -0400 Subject: added new filterwidget, will eventually get the operators functionality from the mod/pluging lists --- src/CMakeLists.txt | 3 ++ src/filterwidget.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/filterwidget.h | 27 ++++++++++++++++ src/modinfodialog.cpp | 2 ++ src/modinfodialog.h | 3 ++ src/modinfodialog.ui | 7 +--- 6 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 src/filterwidget.cpp create mode 100644 src/filterwidget.h (limited to 'src/modinfodialog.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cae26334..93597d62 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,6 +115,7 @@ SET(organizer_SRCS lcdnumber.cpp forcedloaddialog.cpp forcedloaddialogwidget.cpp + filterwidget.cpp shared/windows_error.cpp shared/error_report.cpp @@ -211,6 +212,7 @@ SET(organizer_HDRS lcdnumber.h forcedloaddialog.h forcedloaddialogwidget.h + filterwidget.h shared/windows_error.h shared/error_report.h @@ -391,6 +393,7 @@ set(utilities set(widgets descriptionpage genericicondelegate + filterwidget icondelegate lcdnumber logbuffer diff --git a/src/filterwidget.cpp b/src/filterwidget.cpp new file mode 100644 index 00000000..39324bc6 --- /dev/null +++ b/src/filterwidget.cpp @@ -0,0 +1,88 @@ +#include "filterwidget.h" +#include "eventfilter.h" + +FilterWidget::FilterWidget() + : m_edit(nullptr), m_clear(nullptr), m_buddy(nullptr) +{ +} + +void FilterWidget::set(QLineEdit* edit) +{ + if (m_clear) { + delete m_clear; + m_clear = nullptr; + } + + m_edit = edit; + if (!m_edit) { + return; + } + + createClear(); + hookEvents(); +} + +void FilterWidget::clear() +{ + if (!m_edit) { + return; + } + + m_edit->clear(); +} + +void FilterWidget::createClear() +{ + m_clear = new QToolButton(m_edit); + + QPixmap pixmap(":/MO/gui/edit_clear"); + m_clear->setIcon(QIcon(pixmap)); + m_clear->setIconSize(pixmap.size()); + m_clear->setCursor(Qt::ArrowCursor); + m_clear->setStyleSheet("QToolButton { border: none; padding: 0px; }"); + m_clear->hide(); + + QObject::connect(m_clear, &QToolButton::clicked, [&]{ clear(); }); + QObject::connect(m_edit, &QLineEdit::textChanged, [&]{ onTextChanged(); }); + + repositionClearButton(); +} + +void FilterWidget::hookEvents() +{ + auto* f = new EventFilter(m_edit, [&](auto* w, auto* e) { + if (e->type() == QEvent::Resize) { + onResized(); + } + + return false; + }); + + m_edit->installEventFilter(f); +} + +void FilterWidget::onTextChanged() +{ + m_clear->setVisible(!m_edit->text().isEmpty()); +} + +void FilterWidget::onResized() +{ + repositionClearButton(); +} + +void FilterWidget::repositionClearButton() +{ + if (!m_clear) { + return; + } + + const QSize sz = m_clear->sizeHint(); + const int frame = m_edit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + const auto r = m_edit->rect(); + + const auto x = r.right() - frame - sz.width(); + const auto y = (r.bottom() + 1 - sz.height()) / 2; + + m_clear->move(x, y); +} diff --git a/src/filterwidget.h b/src/filterwidget.h new file mode 100644 index 00000000..07e216f1 --- /dev/null +++ b/src/filterwidget.h @@ -0,0 +1,27 @@ +#ifndef FILTERWIDGET_H +#define FILTERWIDGET_H + +class FilterWidget +{ +public: + FilterWidget(); + + void set(QLineEdit* edit); + void buddy(QWidget* w); + + void clear(); + +private: + QLineEdit* m_edit; + QToolButton* m_clear; + QWidget* m_buddy; + + void createClear(); + void hookEvents(); + void repositionClearButton(); + + void onTextChanged(); + void onResized(); +}; + +#endif // FILTERWIDGET_H diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 9db31da3..1e933a74 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -453,6 +453,8 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo m_nonconflictExpander.set(ui->noConflictExpander, ui->noConflictTree); + m_advancedConflictFilter.set(ui->conflictsAdvancedFilter); + // left-elide the overwrites column so that the nearest are visible ui->conflictsAdvancedList->setItemDelegateForColumn( 0, new ElideLeftDelegate(ui->conflictsAdvancedList)); diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 69b0069e..5169a993 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -25,6 +25,7 @@ along with Mod Organizer. If not, see . #include "tutorabledialog.h" #include "plugincontainer.h" #include "organizercore.h" +#include "filterwidget.h" #include #include @@ -427,6 +428,7 @@ private: std::map m_RealTabPos; ExpanderWidget m_overwriteExpander, m_overwrittenExpander, m_nonconflictExpander; + FilterWidget m_advancedConflictFilter; void refreshConflictLists(bool refreshGeneral, bool refreshAdvanced); @@ -448,6 +450,7 @@ private: const QString& fileName, const QString& relativeName, const MOShared::FileEntry::AlternativesVector& alternatives); + void restoreTabState(const QByteArray &state); void restoreConflictExpandersState(const QByteArray &state); diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index e391da46..b55c0f07 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -782,7 +782,7 @@ text-align: left; 0 - + Filter @@ -1201,11 +1201,6 @@ p, li { white-space: pre-wrap; } QLineEdit
modidlineedit.h
- - MOBase::LineEditClear - QLineEdit -
lineeditclear.h
-
-- cgit v1.3.1 From 98b3be3e9bbca73640842f6dadaa159dcec04f7b Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Wed, 29 May 2019 10:08:46 -0400 Subject: removed buddy from FilterWidget, the intention was to hook a ctrl+f shortcut to it, but that won't work as a general solution, it would need to be on tabs for the modinfo dialog added a simple matches() that just searches for the string FilterWidget can cleanly unhook itself --- src/filterwidget.cpp | 40 +++++++++++++++++++++++++++++++++------- src/filterwidget.h | 12 +++++++++--- src/modinfodialog.cpp | 7 +++++++ 3 files changed, 49 insertions(+), 10 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/filterwidget.cpp b/src/filterwidget.cpp index 39324bc6..7c47980e 100644 --- a/src/filterwidget.cpp +++ b/src/filterwidget.cpp @@ -2,24 +2,23 @@ #include "eventfilter.h" FilterWidget::FilterWidget() - : m_edit(nullptr), m_clear(nullptr), m_buddy(nullptr) + : m_edit(nullptr), m_eventFilter(nullptr), m_clear(nullptr) { } void FilterWidget::set(QLineEdit* edit) { - if (m_clear) { - delete m_clear; - m_clear = nullptr; - } + unhook(); m_edit = edit; + if (!m_edit) { return; } createClear(); hookEvents(); + clear(); } void FilterWidget::clear() @@ -31,6 +30,23 @@ void FilterWidget::clear() m_edit->clear(); } +bool FilterWidget::matches(const QString& s) const +{ + return s.contains(m_text); +} + +void FilterWidget::unhook() +{ + if (m_clear) { + delete m_clear; + m_clear = nullptr; + } + + if (m_edit) { + m_edit->removeEventFilter(m_eventFilter); + } +} + void FilterWidget::createClear() { m_clear = new QToolButton(m_edit); @@ -50,7 +66,7 @@ void FilterWidget::createClear() void FilterWidget::hookEvents() { - auto* f = new EventFilter(m_edit, [&](auto* w, auto* e) { + m_eventFilter = new EventFilter(m_edit, [&](auto* w, auto* e) { if (e->type() == QEvent::Resize) { onResized(); } @@ -58,12 +74,22 @@ void FilterWidget::hookEvents() return false; }); - m_edit->installEventFilter(f); + m_edit->installEventFilter(m_eventFilter); } void FilterWidget::onTextChanged() { m_clear->setVisible(!m_edit->text().isEmpty()); + + const auto text = m_edit->text(); + + if (text != m_text) { + m_text = text; + + if (changed) { + changed(); + } + } } void FilterWidget::onResized() diff --git a/src/filterwidget.h b/src/filterwidget.h index 07e216f1..ca731dc1 100644 --- a/src/filterwidget.h +++ b/src/filterwidget.h @@ -1,21 +1,27 @@ #ifndef FILTERWIDGET_H #define FILTERWIDGET_H +class EventFilter; + class FilterWidget { public: + std::function changed; + FilterWidget(); void set(QLineEdit* edit); - void buddy(QWidget* w); - void clear(); + bool matches(const QString& s) const; + private: QLineEdit* m_edit; + EventFilter* m_eventFilter; QToolButton* m_clear; - QWidget* m_buddy; + QString m_text; + void unhook(); void createClear(); void hookEvents(); void repositionClearButton(); diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 1e933a74..0f18033a 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -454,6 +454,7 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo m_advancedConflictFilter.set(ui->conflictsAdvancedFilter); + m_advancedConflictFilter.changed = [&]{ refreshConflictLists(false, true); }; // left-elide the overwrites column so that the nearest are visible ui->conflictsAdvancedList->setItemDelegateForColumn( @@ -873,6 +874,12 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( } } + if (!m_advancedConflictFilter.matches(before) && + !m_advancedConflictFilter.matches(relativeName) && + !m_advancedConflictFilter.matches(after)) { + return nullptr; + } + QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, before); item->setText(1, relativeName); -- cgit v1.3.1 From 8efab8bf129b6f9928f478a429e20cf018e5e373 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 May 2019 10:54:36 -0400 Subject: FilterWidget takes a predicate to match strings copied the logic from modlistsortproxy so the basic boolean syntax in filters works --- src/filterwidget.cpp | 34 ++++++++++++++++++++++++++++++++-- src/filterwidget.h | 2 +- src/modinfodialog.cpp | 13 +++++++++---- 3 files changed, 42 insertions(+), 7 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/filterwidget.cpp b/src/filterwidget.cpp index 7c47980e..16a46b0e 100644 --- a/src/filterwidget.cpp +++ b/src/filterwidget.cpp @@ -30,9 +30,39 @@ void FilterWidget::clear() m_edit->clear(); } -bool FilterWidget::matches(const QString& s) const +bool FilterWidget::matches(std::function pred) const { - return s.contains(m_text); + const QStringList ORList = [&] { + QString filterCopy = QString(m_text); + filterCopy.replace("||", ";").replace("OR", ";").replace("|", ";"); + return filterCopy.split(";", QString::SkipEmptyParts); + }(); + + if (ORList.isEmpty() || !pred) { + return true; + } + + // split in ORSegments that internally use AND logic + for (auto& ORSegment : ORList) { + QStringList ANDKeywords = ORSegment.split(" ", QString::SkipEmptyParts); + bool segmentGood = true; + + // check each word in the segment for match, each word needs to be matched + // but it doesn't matter where. + for (auto& currentKeyword : ANDKeywords) { + if (!pred(currentKeyword)) { + segmentGood = false; + } + } + + if (segmentGood) { + // the last AND loop didn't break so the ORSegments is true so mod + // matches filter + return true; + } + } + + return false; } void FilterWidget::unhook() diff --git a/src/filterwidget.h b/src/filterwidget.h index ca731dc1..4fee5983 100644 --- a/src/filterwidget.h +++ b/src/filterwidget.h @@ -13,7 +13,7 @@ public: void set(QLineEdit* edit); void clear(); - bool matches(const QString& s) const; + bool matches(std::function pred) const; private: QLineEdit* m_edit; diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 0f18033a..4852150f 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -874,10 +874,15 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( } } - if (!m_advancedConflictFilter.matches(before) && - !m_advancedConflictFilter.matches(relativeName) && - !m_advancedConflictFilter.matches(after)) { - return nullptr; + bool matched = m_advancedConflictFilter.matches([&](auto&& what) { + return + before.contains(what, Qt::CaseInsensitive) || + relativeName.contains(what, Qt::CaseInsensitive) || + after.contains(what, Qt::CaseInsensitive); + }); + + if (!matched) { + return nullptr; } QTreeWidgetItem* item = new QTreeWidgetItem; -- cgit v1.3.1 From b7580c5ad766ebf984641674fdc0f121d754c82e Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 May 2019 11:31:21 -0400 Subject: restore conflicts selected tab and checkboxes --- src/modinfodialog.cpp | 28 +++++++++++++++++++++++----- src/modinfodialog.h | 4 ++-- src/modinfodialog.ui | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 4852150f..1dd44112 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -553,13 +553,13 @@ int ModInfoDialog::tabIndex(const QString &tabId) void ModInfoDialog::saveState(Settings& s) const { s.directInterface().setValue("mod_info_tabs", saveTabState()); - s.directInterface().setValue("mod_info_conflict_expanders", saveConflictExpandersState()); + s.directInterface().setValue("mod_info_conflicts", saveConflictsState()); } void ModInfoDialog::restoreState(const Settings& s) { restoreTabState(s.directInterface().value("mod_info_tabs").toByteArray()); - restoreConflictExpandersState(s.directInterface().value("mod_info_conflict_expanders").toByteArray()); + restoreConflictsState(s.directInterface().value("mod_info_conflicts").toByteArray()); } void ModInfoDialog::restoreTabState(const QByteArray &state) @@ -593,7 +593,7 @@ void ModInfoDialog::restoreTabState(const QByteArray &state) ui->tabWidget->blockSignals(false); } -void ModInfoDialog::restoreConflictExpandersState(const QByteArray &state) +void ModInfoDialog::restoreConflictsState(const QByteArray &state) { QDataStream stream(state); @@ -608,6 +608,20 @@ void ModInfoDialog::restoreConflictExpandersState(const QByteArray &state) m_overwrittenExpander.toggle(overwrittenExpanded); m_nonconflictExpander.toggle(noConflictExpanded); } + + int index = 0; + bool noConflictChecked = false; + bool showAllChecked = false; + bool showNearestChecked = false; + + stream >> index >> noConflictChecked >> showAllChecked >> showNearestChecked; + + if (stream.status() == QDataStream::Ok) { + ui->tabConflictsTabs->setCurrentIndex(index); + ui->conflictsAdvancedShowNoConflict->setChecked(noConflictChecked); + ui->conflictsAdvancedShowAll->setChecked(showAllChecked); + ui->conflictsAdvancedShowNearest->setChecked(showNearestChecked); + } } QByteArray ModInfoDialog::saveTabState() const @@ -622,7 +636,7 @@ QByteArray ModInfoDialog::saveTabState() const return result; } -QByteArray ModInfoDialog::saveConflictExpandersState() const +QByteArray ModInfoDialog::saveConflictsState() const { QByteArray result; QDataStream stream(&result, QIODevice::WriteOnly); @@ -630,7 +644,11 @@ QByteArray ModInfoDialog::saveConflictExpandersState() const stream << m_overwriteExpander.opened() << m_overwrittenExpander.opened() - << m_nonconflictExpander.opened(); + << m_nonconflictExpander.opened() + << ui->tabConflictsTabs->currentIndex() + << ui->conflictsAdvancedShowNoConflict->isChecked() + << ui->conflictsAdvancedShowAll->isChecked() + << ui->conflictsAdvancedShowNearest->isChecked(); return result; } diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 5169a993..40e45eb4 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -452,10 +452,10 @@ private: void restoreTabState(const QByteArray &state); - void restoreConflictExpandersState(const QByteArray &state); + void restoreConflictsState(const QByteArray &state); QByteArray saveTabState() const; - QByteArray saveConflictExpandersState() const; + QByteArray saveConflictsState() const; bool canHideConflictItem(const QTreeWidgetItem* item) const; bool canUnhideConflictItem(const QTreeWidgetItem* item) const; diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index b55c0f07..6c1ed36d 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -402,7 +402,7 @@ Most mods do not have optional esps, so chances are good you are looking at an e - + 1 -- cgit v1.3.1 From 0f6f0c23943116ea668ab035055cb8b0e4a6574e Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 May 2019 12:49:25 -0400 Subject: replaced all the manual UserRole stuff with a few constants and helper functions setConflictItem() is now used by all conflict lists to setup the data (filename, archive, etc.) and visuals (italic for archives) merged openDataFile() and previewDataFile() into their caller as they weren't used anywhere else previewDataFile() used to do a fromNativeSeparators() before previewing, moved that to previewFileWithAlternatives() instead brought overwrittenTree double click in line with overwriteTree, there's no difference between apply() and close() because there's only a close button --- src/modinfodialog.cpp | 133 +++++++++++++++++++++++++++----------------------- src/modinfodialog.h | 10 +++- src/modinfodialog.ui | 9 ++++ src/organizercore.cpp | 2 + 4 files changed, 91 insertions(+), 63 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 1dd44112..e639dcc7 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -57,6 +57,10 @@ along with Mod Organizer. If not, see . using namespace MOBase; using namespace MOShared; +const auto FILENAME_USERROLE = Qt::UserRole + 1; +const auto ORIGIN_USERROLE = Qt::UserRole + 2; +const auto ARCHIVE_USERROLE = Qt::UserRole + 3; + class ModFileListWidget : public QListWidgetItem { friend bool operator<(const ModFileListWidget &LHS, const ModFileListWidget &RHS); @@ -744,18 +748,10 @@ QTreeWidgetItem* ModInfoDialog::createOverwriteItem( QStringList fields(relativeName); fields.append(altString); - QTreeWidgetItem *item = new QTreeWidgetItem(fields); - item->setData(0, Qt::UserRole, fileName); - item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives.back().first).getName())); - item->setData(1, Qt::UserRole + 1, alternatives.back().first); - item->setData(1, Qt::UserRole + 2, archive); + const auto origin = ToQString(m_Directory->getOriginByID(alternatives.back().first).getName()); - if (archive) { - QFont font = item->font(0); - font.setItalic(true); - item->setFont(0, font); - item->setFont(1, font); - } + QTreeWidgetItem *item = new QTreeWidgetItem(fields); + setConflictItem(item, fileName, origin, archive); return item; } @@ -764,13 +760,7 @@ QTreeWidgetItem* ModInfoDialog::createNoConflictItem( bool archive, const QString& fileName, const QString& relativeName) { QTreeWidgetItem *item = new QTreeWidgetItem(QStringList({relativeName})); - item->setData(0, Qt::UserRole, fileName); - - if (archive) { - QFont font = item->font(0); - font.setItalic(true); - item->setFont(0, font); - } + setConflictItem(item, fileName, "", archive); return item; } @@ -785,16 +775,7 @@ QTreeWidgetItem* ModInfoDialog::createOverwrittenItem( fields.append(ToQString(realOrigin.getName())); QTreeWidgetItem *item = new QTreeWidgetItem(fields); - item->setData(0, Qt::UserRole, fileName); - item->setData(1, Qt::UserRole, ToQString(realOrigin.getName())); - item->setData(1, Qt::UserRole + 2, archive); - - if (archive) { - QFont font = item->font(0); - font.setItalic(true); - item->setFont(0, font); - item->setFont(1, font); - } + setConflictItem(item, fileName, ToQString(realOrigin.getName()), archive); return item; } @@ -908,9 +889,44 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( item->setText(1, relativeName); item->setText(2, after); + setConflictItem(item, fileName, "", archive); + return item; } +void ModInfoDialog::setConflictItem( + QTreeWidgetItem* item, + const QString& fileName, const QString& origin, bool archive) const +{ + item->setData(0, FILENAME_USERROLE, fileName); + item->setData(0, ORIGIN_USERROLE, origin); + item->setData(0, ARCHIVE_USERROLE, archive); + + if (archive) { + QFont font = item->font(0); + font.setItalic(true); + + for (int i=0; icolumnCount(); ++i) { + item->setFont(i, font); + } + } +} + +QString ModInfoDialog::conflictFileName(const QTreeWidgetItem* conflictItem) const +{ + return conflictItem->data(0, FILENAME_USERROLE).toString(); +} + +QString ModInfoDialog::conflictOrigin(const QTreeWidgetItem* conflictItem) const +{ + return conflictItem->data(0, ORIGIN_USERROLE).toString(); +} + +bool ModInfoDialog::conflictIsArchive(const QTreeWidgetItem* conflictItem) const +{ + return conflictItem->data(0, ARCHIVE_USERROLE).toBool(); +} + void ModInfoDialog::refreshFiles() { if (m_RootPath.length() > 0) { @@ -1860,8 +1876,12 @@ void ModInfoDialog::on_primaryCategoryBox_currentIndexChanged(int index) void ModInfoDialog::on_overwriteTree_itemDoubleClicked(QTreeWidgetItem *item, int) { - this->close(); - emit modOpen(item->data(1, Qt::UserRole).toString(), TAB_CONFLICTS); + const auto origin = conflictOrigin(item); + + if (!origin.isEmpty()) { + close(); + emit modOpen(origin, TAB_CONFLICTS); + } } FileRenamer::RenameResults ModInfoDialog::hideFile(FileRenamer& renamer, const QString &oldName) @@ -1907,14 +1927,14 @@ void ModInfoDialog::changeConflictItemsVisibility( qDebug().nospace() << "cannot unhide " << item->text(0) << ", skipping"; continue; } - result = unhideFile(renamer, item->data(0, Qt::UserRole).toString()); + result = unhideFile(renamer, conflictFileName(item)); } else { if (!canHideConflictItem(item)) { qDebug().nospace() << "cannot hide " << item->text(0) << ", skipping"; continue; } - result = hideFile(renamer, item->data(0, Qt::UserRole).toString()); + result = hideFile(renamer, conflictFileName(item)); } switch (result) { @@ -1953,7 +1973,9 @@ void ModInfoDialog::openConflictItems(const QList& items) // the menu item is only shown for a single selection, but handle all of them // in case this changes for (auto* item : items) { - openDataFile(item); + if (item) { + m_OrganizerCore->executeFileVirtualized(this, conflictFileName(item)); + } } } @@ -1962,28 +1984,10 @@ void ModInfoDialog::previewConflictItems(const QList& items) // the menu item is only shown for a single selection, but handle all of them // in case this changes for (auto* item : items) { - previewDataFile(item); - } -} - -void ModInfoDialog::openDataFile(const QTreeWidgetItem* item) -{ - if (!item) { - return; - } - - QFileInfo targetInfo(item->data(0, Qt::UserRole).toString()); - m_OrganizerCore->executeFileVirtualized(this, targetInfo); -} - -void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item) -{ - if (!item) { - return; + if (item) { + m_OrganizerCore->previewFileWithAlternatives(this, conflictFileName(item)); + } } - - QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString()); - m_OrganizerCore->previewFileWithAlternatives(this, fileName); } bool ModInfoDialog::canPreviewFile(bool isArchive, const QString& filename) const @@ -2028,19 +2032,17 @@ bool ModInfoDialog::canUnhideFile(bool isArchive, const QString& filename) const bool ModInfoDialog::canHideConflictItem(const QTreeWidgetItem* item) const { - return canHideFile(item->data(1, Qt::UserRole + 2).toBool(), item->text(0)); + return canHideFile(conflictIsArchive(item), conflictFileName(item)); } bool ModInfoDialog::canUnhideConflictItem(const QTreeWidgetItem* item) const { - return canUnhideFile(item->data(1, Qt::UserRole + 2).toBool(), item->text(0)); + return canUnhideFile(conflictIsArchive(item), conflictFileName(item)); } bool ModInfoDialog::canPreviewConflictItem(const QTreeWidgetItem* item) const { - return canPreviewFile( - item->data(1, Qt::UserRole + 2).toBool(), - item->data(0, Qt::UserRole).toString()); + return canPreviewFile(conflictIsArchive(item), conflictFileName(item)); } void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &pos) @@ -2058,6 +2060,11 @@ void ModInfoDialog::on_noConflictTree_customContextMenuRequested(const QPoint &p showConflictMenu(pos, ui->noConflictTree); } +void ModInfoDialog::on_conflictsAdvancedList_customContextMenuRequested(const QPoint &pos) +{ + showConflictMenu(pos, ui->conflictsAdvancedList); +} + void ModInfoDialog::showConflictMenu(const QPoint &pos, QTreeWidget* tree) { auto actions = createConflictMenuActions(tree->selectedItems()); @@ -2181,8 +2188,12 @@ ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( void ModInfoDialog::on_overwrittenTree_itemDoubleClicked(QTreeWidgetItem *item, int) { - emit modOpen(item->data(1, Qt::UserRole).toString(), TAB_CONFLICTS); - this->accept(); + const auto origin = conflictOrigin(item); + + if (!origin.isEmpty()) { + close(); + emit modOpen(origin, TAB_CONFLICTS); + } } void ModInfoDialog::on_refreshButton_clicked() diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 40e45eb4..59912127 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -368,6 +368,7 @@ private slots: void on_overwriteTree_customContextMenuRequested(const QPoint &pos); void on_overwrittenTree_customContextMenuRequested(const QPoint &pos); void on_noConflictTree_customContextMenuRequested(const QPoint &pos); + void on_conflictsAdvancedList_customContextMenuRequested(const QPoint &pos); void on_fileTree_customContextMenuRequested(const QPoint &pos); void on_refreshButton_clicked(); @@ -450,6 +451,13 @@ private: const QString& fileName, const QString& relativeName, const MOShared::FileEntry::AlternativesVector& alternatives); + void setConflictItem( + QTreeWidgetItem* item, + const QString& fileName, const QString& origin, bool archive) const; + + QString conflictFileName(const QTreeWidgetItem* conflictItem) const; + QString conflictOrigin(const QTreeWidgetItem* conflictItem) const; + bool conflictIsArchive(const QTreeWidgetItem* conflictItem) const; void restoreTabState(const QByteArray &state); void restoreConflictsState(const QByteArray &state); @@ -461,8 +469,6 @@ private: bool canUnhideConflictItem(const QTreeWidgetItem* item) const; bool canPreviewConflictItem(const QTreeWidgetItem* item) const; - void openDataFile(const QTreeWidgetItem* item); - void previewDataFile(const QTreeWidgetItem* item); void changeFiletreeVisibility(bool visible); void openConflictItems(const QList& items); diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 8744b216..93291c02 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -707,6 +707,15 @@ text-align: left; + + Qt::CustomContextMenu + + + QAbstractItemView::ExtendedSelection + + + true + 3 diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 3ad4e586..892162f6 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1321,6 +1321,8 @@ bool OrganizerCore::executeFileVirtualized( bool OrganizerCore::previewFileWithAlternatives( QWidget* parent, QString fileName, int selectedOrigin) { + fileName = QDir::fromNativeSeparators(fileName); + // what we have is an absolute path to the file in its actual location (for the primary origin) // what we want is the path relative to the virtual data directory -- cgit v1.3.1 From 0da1c2591f0a67560b241515d996c39598da6735 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 May 2019 13:09:17 -0400 Subject: don't show open menu item if the files are from an archive --- src/modinfodialog.cpp | 13 ++++++++++++- src/modinfodialog.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index e639dcc7..97507777 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -2000,6 +2000,12 @@ bool ModInfoDialog::canPreviewFile(bool isArchive, const QString& filename) cons return m_PluginContainer->previewGenerator().previewSupported(ext); } +bool ModInfoDialog::canOpenFile(bool isArchive, const QString&) const +{ + // can open anything as long as it's not in an archive + return !isArchive; +} + bool ModInfoDialog::canHideFile(bool isArchive, const QString& filename) const { if (isArchive) { @@ -2040,6 +2046,11 @@ bool ModInfoDialog::canUnhideConflictItem(const QTreeWidgetItem* item) const return canUnhideFile(conflictIsArchive(item), conflictFileName(item)); } +bool ModInfoDialog::canOpenConflictItem(const QTreeWidgetItem* item) const +{ + return canOpenFile(conflictIsArchive(item), conflictFileName(item)); +} + bool ModInfoDialog::canPreviewConflictItem(const QTreeWidgetItem* item) const { return canPreviewFile(conflictIsArchive(item), conflictFileName(item)); @@ -2131,8 +2142,8 @@ ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( enableHide = canHideConflictItem(item); enableUnhide = canUnhideConflictItem(item); + enableOpen = canOpenConflictItem(item); enablePreview = canPreviewConflictItem(item); - // open is always enabled } else { // this is a multiple selection, don't show open/preview so users don't open diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 59912127..35f87820 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -467,6 +467,7 @@ private: bool canHideConflictItem(const QTreeWidgetItem* item) const; bool canUnhideConflictItem(const QTreeWidgetItem* item) const; + bool canOpenConflictItem(const QTreeWidgetItem* item) const; bool canPreviewConflictItem(const QTreeWidgetItem* item) const; void changeFiletreeVisibility(bool visible); @@ -477,6 +478,7 @@ private: const QList& items, bool visible); bool canPreviewFile(bool isArchive, const QString& filename) const; + bool canOpenFile(bool isArchive, const QString& filename) const; bool canHideFile(bool isArchive, const QString& filename) const; bool canUnhideFile(bool isArchive, const QString& filename) const; -- cgit v1.3.1 From 7421aaa33b37bc13a9c5a3f5df2f06b6bf0f09e5 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 May 2019 13:59:08 -0400 Subject: conflict lists - sorting on advanced list - save state of all four lists - call refreshLists() just before showing because the state has to be loaded first, which happens after the ctor --- src/modinfodialog.cpp | 36 ++++++++++++++++++++++++++++++++++-- src/modinfodialog.h | 2 ++ src/modinfodialog.ui | 3 +++ 3 files changed, 39 insertions(+), 2 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 97507777..b8a8ae69 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -397,8 +397,6 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo } } - refreshLists(); - if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR)) { ui->tabWidget->setTabEnabled(TAB_TEXTFILES, false); @@ -501,6 +499,12 @@ ModInfoDialog::~ModInfoDialog() } +int ModInfoDialog::exec() +{ + refreshLists(); + return TutorableDialog::exec(); +} + void ModInfoDialog::initINITweaks() { int numTweaks = m_Settings->beginReadArray("INI Tweaks"); @@ -558,12 +562,40 @@ void ModInfoDialog::saveState(Settings& s) const { s.directInterface().setValue("mod_info_tabs", saveTabState()); s.directInterface().setValue("mod_info_conflicts", saveConflictsState()); + + s.directInterface().setValue( + "mod_info_conflicts_overwrite", + ui->overwriteTree->header()->saveState()); + + s.directInterface().setValue( + "mod_info_conflicts_noconflict", + ui->noConflictTree->header()->saveState()); + + s.directInterface().setValue( + "mod_info_conflicts_overwritten", + ui->overwrittenTree->header()->saveState()); + + s.directInterface().setValue( + "mod_info_advanced_conflicts", + ui->conflictsAdvancedList->header()->saveState()); } void ModInfoDialog::restoreState(const Settings& s) { restoreTabState(s.directInterface().value("mod_info_tabs").toByteArray()); restoreConflictsState(s.directInterface().value("mod_info_conflicts").toByteArray()); + + ui->overwriteTree->header()->restoreState( + s.directInterface().value("mod_info_conflicts_overwrite").toByteArray()); + + ui->noConflictTree->header()->restoreState( + s.directInterface().value("mod_info_conflicts_noconflict").toByteArray()); + + ui->overwrittenTree->header()->restoreState( + s.directInterface().value("mod_info_conflicts_overwritten").toByteArray()); + + ui->conflictsAdvancedList->header()->restoreState( + s.directInterface().value("mod_info_advanced_conflicts").toByteArray()); } void ModInfoDialog::restoreTabState(const QByteArray &state) diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 35f87820..85505487 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -280,6 +280,8 @@ public: **/ void openTab(int tab); + int exec() override; + void saveState(Settings& s) const; void restoreState(const Settings& s); diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 93291c02..20437e58 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -716,6 +716,9 @@ text-align: left; true + + true + 3 -- cgit v1.3.1 From fa7e34e84a09ed7a2f453a35a48e71477c841e5b Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 May 2019 15:15:47 -0400 Subject: conflict lists: - the file index is now stored in the row data - the alternate origins are now added to the context menu in a "go to" submenu - context menu items are now visually disabled instead of omitted from the menu --- src/modinfodialog.cpp | 171 ++++++++++++++++++++++++++++++++---------- src/modinfodialog.h | 33 +++++--- src/shared/directoryentry.cpp | 5 ++ src/shared/directoryentry.h | 1 + 4 files changed, 160 insertions(+), 50 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index b8a8ae69..60cf7578 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -58,8 +58,10 @@ using namespace MOBase; using namespace MOShared; const auto FILENAME_USERROLE = Qt::UserRole + 1; -const auto ORIGIN_USERROLE = Qt::UserRole + 2; +const auto ALT_ORIGIN_USERROLE = Qt::UserRole + 2; const auto ARCHIVE_USERROLE = Qt::UserRole + 3; +const auto INDEX_USERROLE = Qt::UserRole + 4; +const auto HAS_ALTS_USERROLE = Qt::UserRole + 5; class ModFileListWidget : public QListWidgetItem { @@ -78,8 +80,8 @@ static bool operator<(const ModFileListWidget &LHS, const ModFileListWidget &RHS } // if there are more than 50 selected items in the conflict tree or filetree, -// don't bother checking whether they're visible, just show both menu items -const int max_scan_for_visibility = 50; +// don't bother checking whether menu items apply to them, just show all of them +const int max_scan_for_context_menu = 50; FileRenamer::FileRenamer(QWidget* parent, QFlags flags) @@ -727,19 +729,19 @@ void ModInfoDialog::refreshConflictLists( if (fileOrigin == m_Origin->getID()) { if (!alternatives.empty()) { ui->overwriteTree->addTopLevelItem(createOverwriteItem( - archive, fileName, relativeName, alternatives)); + file->getIndex(), archive, fileName, relativeName, alternatives)); ++numOverwrite; } else { // otherwise, put the file in the noconflict tree ui->noConflictTree->addTopLevelItem(createNoConflictItem( - archive, fileName, relativeName)); + file->getIndex(), archive, fileName, relativeName)); ++numNonConflicting; } } else { ui->overwrittenTree->addTopLevelItem(createOverwrittenItem( - fileOrigin, archive, fileName, relativeName)); + file->getIndex(), fileOrigin, archive, fileName, relativeName)); ++numOverwritten; } @@ -747,7 +749,8 @@ void ModInfoDialog::refreshConflictLists( if (refreshAdvanced) { auto* advancedItem = createAdvancedConflictItem( - fileOrigin, archive, fileName, relativeName, alternatives); + file->getIndex(), fileOrigin, archive, + fileName, relativeName, alternatives); if (advancedItem) { ui->conflictsAdvancedList->addTopLevelItem(advancedItem); @@ -764,7 +767,8 @@ void ModInfoDialog::refreshConflictLists( } QTreeWidgetItem* ModInfoDialog::createOverwriteItem( - bool archive, const QString& fileName, const QString& relativeName, + FileEntry::Index index, bool archive, + const QString& fileName, const QString& relativeName, const FileEntry::AlternativesVector& alternatives) { QString altString; @@ -783,22 +787,23 @@ QTreeWidgetItem* ModInfoDialog::createOverwriteItem( const auto origin = ToQString(m_Directory->getOriginByID(alternatives.back().first).getName()); QTreeWidgetItem *item = new QTreeWidgetItem(fields); - setConflictItem(item, fileName, origin, archive); + setConflictItem(item, index, fileName, true, origin, archive); return item; } QTreeWidgetItem* ModInfoDialog::createNoConflictItem( - bool archive, const QString& fileName, const QString& relativeName) + FileEntry::Index index, bool archive, + const QString& fileName, const QString& relativeName) { QTreeWidgetItem *item = new QTreeWidgetItem(QStringList({relativeName})); - setConflictItem(item, fileName, "", archive); + setConflictItem(item, index, fileName, false, "", archive); return item; } QTreeWidgetItem* ModInfoDialog::createOverwrittenItem( - int fileOrigin, bool archive, + FileEntry::Index index, int fileOrigin, bool archive, const QString& fileName, const QString& relativeName) { const FilesOrigin &realOrigin = m_Directory->getOriginByID(fileOrigin); @@ -807,13 +812,13 @@ QTreeWidgetItem* ModInfoDialog::createOverwrittenItem( fields.append(ToQString(realOrigin.getName())); QTreeWidgetItem *item = new QTreeWidgetItem(fields); - setConflictItem(item, fileName, ToQString(realOrigin.getName()), archive); + setConflictItem(item, index, fileName, true, ToQString(realOrigin.getName()), archive); return item; } QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( - int fileOrigin, bool archive, + FileEntry::Index index,int fileOrigin, bool archive, const QString& fileName, const QString& relativeName, const MOShared::FileEntry::AlternativesVector& alternatives) { @@ -897,10 +902,12 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( } } + bool hasAlts = !before.isEmpty() || !after.isEmpty(); + if (!ui->conflictsAdvancedShowNoConflict->isChecked()) { // 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 (before.isEmpty() && after.isEmpty()) { + if (!hasAlts) { return nullptr; } } @@ -921,18 +928,21 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( item->setText(1, relativeName); item->setText(2, after); - setConflictItem(item, fileName, "", archive); + setConflictItem(item, index, fileName, hasAlts, "", archive); return item; } void ModInfoDialog::setConflictItem( - QTreeWidgetItem* item, - const QString& fileName, const QString& origin, bool archive) const + QTreeWidgetItem* item, FileEntry::Index index, + const QString& fileName, bool hasAltOrigins, const QString& altOrigin, + bool archive) const { item->setData(0, FILENAME_USERROLE, fileName); - item->setData(0, ORIGIN_USERROLE, origin); + item->setData(0, ALT_ORIGIN_USERROLE, altOrigin); item->setData(0, ARCHIVE_USERROLE, archive); + item->setData(0, INDEX_USERROLE, index); + item->setData(0, HAS_ALTS_USERROLE, hasAltOrigins); if (archive) { QFont font = item->font(0); @@ -949,9 +959,14 @@ QString ModInfoDialog::conflictFileName(const QTreeWidgetItem* conflictItem) con return conflictItem->data(0, FILENAME_USERROLE).toString(); } -QString ModInfoDialog::conflictOrigin(const QTreeWidgetItem* conflictItem) const +QString ModInfoDialog::conflictAltOrigin(const QTreeWidgetItem* conflictItem) const +{ + return conflictItem->data(0, ALT_ORIGIN_USERROLE).toString(); +} + +bool ModInfoDialog::conflictHasAlts(const QTreeWidgetItem* conflictItem) const { - return conflictItem->data(0, ORIGIN_USERROLE).toString(); + return conflictItem->data(0, HAS_ALTS_USERROLE).toBool(); } bool ModInfoDialog::conflictIsArchive(const QTreeWidgetItem* conflictItem) const @@ -959,6 +974,12 @@ bool ModInfoDialog::conflictIsArchive(const QTreeWidgetItem* conflictItem) const return conflictItem->data(0, ARCHIVE_USERROLE).toBool(); } +FileEntry::Index ModInfoDialog::conflictFileIndex(const QTreeWidgetItem* conflictItem) const +{ + static_assert(std::is_same_v); + return conflictItem->data(0, INDEX_USERROLE).toUInt(); +} + void ModInfoDialog::refreshFiles() { if (m_RootPath.length() > 0) { @@ -1804,7 +1825,7 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) enablePreview = false; enableRename = false; - if (m_FileSelection.size() < max_scan_for_visibility) { + if (m_FileSelection.size() < max_scan_for_context_menu) { // if the number of selected items is low, checking them to accurately // show the menu items is worth it enableHide = false; @@ -1908,7 +1929,7 @@ void ModInfoDialog::on_primaryCategoryBox_currentIndexChanged(int index) void ModInfoDialog::on_overwriteTree_itemDoubleClicked(QTreeWidgetItem *item, int) { - const auto origin = conflictOrigin(item); + const auto origin = conflictAltOrigin(item); if (!origin.isEmpty()) { close(); @@ -2114,6 +2135,7 @@ void ModInfoDialog::showConflictMenu(const QPoint &pos, QTreeWidget* tree) QMenu menu; + // open if (actions.open) { connect(actions.open, &QAction::triggered, [&]{ openConflictItems(tree->selectedItems()); @@ -2122,6 +2144,7 @@ void ModInfoDialog::showConflictMenu(const QPoint &pos, QTreeWidget* tree) menu.addAction(actions.open); } + // preview if (actions.preview) { connect(actions.preview, &QAction::triggered, [&]{ previewConflictItems(tree->selectedItems()); @@ -2130,6 +2153,7 @@ void ModInfoDialog::showConflictMenu(const QPoint &pos, QTreeWidget* tree) menu.addAction(actions.preview); } + // hide if (actions.hide) { connect(actions.hide, &QAction::triggered, [&]{ changeConflictItemsVisibility(tree->selectedItems(), false); @@ -2138,6 +2162,7 @@ void ModInfoDialog::showConflictMenu(const QPoint &pos, QTreeWidget* tree) menu.addAction(actions.hide); } + // unhide if (actions.unhide) { connect(actions.unhide, &QAction::triggered, [&]{ changeConflictItemsVisibility(tree->selectedItems(), true); @@ -2146,15 +2171,27 @@ void ModInfoDialog::showConflictMenu(const QPoint &pos, QTreeWidget* tree) menu.addAction(actions.unhide); } - if (menu.isEmpty()) { - return; + // goto + if (actions.gotoMenu) { + menu.addMenu(actions.gotoMenu); + + for (auto* a : actions.gotoActions) { + connect(a, &QAction::triggered, [&, name=a->text()]{ + close(); + emit modOpen(name, TAB_CONFLICTS); + }); + + actions.gotoMenu->addAction(a); + } } - menu.exec(tree->viewport()->mapToGlobal(pos)); + if (!menu.isEmpty()) { + menu.exec(tree->viewport()->mapToGlobal(pos)); + } } ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( - const QList selection) + const QList& selection) { if (selection.empty()) { return {}; @@ -2164,6 +2201,7 @@ ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( bool enableUnhide = true; bool enableOpen = true; bool enablePreview = true; + bool enableGoto = true; if (selection.size() == 1) { // this is a single selection @@ -2176,6 +2214,7 @@ ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( enableUnhide = canUnhideConflictItem(item); enableOpen = canOpenConflictItem(item); enablePreview = canPreviewConflictItem(item); + enableGoto = conflictHasAlts(item); } else { // this is a multiple selection, don't show open/preview so users don't open @@ -2183,7 +2222,10 @@ ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( enableOpen = false; enablePreview = false; - if (selection.size() < max_scan_for_visibility) { + // don't bother with this on multiple selection, at least for now + enableGoto = false; + + if (selection.size() < max_scan_for_context_menu) { // if the number of selected items is low, checking them to accurately // show the menu items is worth it enableHide = false; @@ -2198,8 +2240,8 @@ ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( enableUnhide = true; } - if (enableHide && enableUnhide) { - // found both, no need to check more + if (enableHide && enableUnhide && enableGoto) { + // found all, no need to check more break; } } @@ -2208,22 +2250,71 @@ ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( ConflictActions actions; - if (enableHide) { - actions.hide = new QAction(tr("Hide")); - } + actions.hide = new QAction(tr("Hide"), this); + actions.hide->setEnabled(enableHide); // note that it is possible for hidden files to appear if they override other // hidden files from another mod - if (enableUnhide) { - actions.unhide = new QAction(tr("Unhide")); + actions.unhide = new QAction(tr("Unhide"), this); + actions.unhide->setEnabled(enableUnhide); + + actions.open = new QAction(tr("Open/Execute"), this); + actions.open->setEnabled(enableOpen); + + actions.preview = new QAction(tr("Preview"), this); + actions.preview->setEnabled(enablePreview); + + actions.gotoMenu = new QMenu(tr("Go to..."), this); + actions.gotoMenu->setEnabled(enableGoto); + + if (enableGoto) { + actions.gotoActions = createGotoActions(selection); } - if (enableOpen) { - actions.open = new QAction(tr("Open/Execute")); + return actions; +} + +std::vector ModInfoDialog::createGotoActions(const QList& selection) +{ + if (!m_Origin || selection.size() != 1) { + return {}; + } + + auto* item = selection[0]; + if (!item) { + return {}; + } + + auto file = m_Origin->findFile(conflictFileIndex(item)); + if (!file) { + return {}; } - if (enablePreview) { - actions.preview = new QAction(tr("Preview")); + + std::vector mods; + + // add all alternatives + for (const auto& alt : file->getAlternatives()) { + const auto& o = m_Directory->getOriginByID(alt.first); + if (o.getID() != m_Origin->getID()) { + mods.push_back(ToQString(o.getName())); + } + } + + // add the real origin if different from this mod + const FilesOrigin& realOrigin = m_Directory->getOriginByID(file->getOrigin()); + if (realOrigin.getID() != m_Origin->getID()) { + mods.push_back(ToQString(realOrigin.getName())); + } + + std::sort(mods.begin(), mods.end(), [](const auto& a, const auto& b) { + return (QString::localeAwareCompare(a, b) < 0); + }); + + std::vector actions; + + for (const auto& name : mods) { + actions.push_back(new QAction(name, this)); } return actions; @@ -2231,7 +2322,7 @@ ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( void ModInfoDialog::on_overwrittenTree_itemDoubleClicked(QTreeWidgetItem *item, int) { - const auto origin = conflictOrigin(item); + const auto origin = conflictAltOrigin(item); if (!origin.isEmpty()) { close(); diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 85505487..8510c96d 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -385,15 +385,20 @@ private slots: void createTweak(); private: + using FileEntry = MOShared::FileEntry; + struct ConflictActions { QAction* hide; QAction* unhide; QAction* open; QAction* preview; + QMenu* gotoMenu; + std::vector gotoActions; - ConflictActions() - : hide(nullptr), unhide(nullptr), open(nullptr), preview(nullptr) + ConflictActions() : + hide(nullptr), unhide(nullptr), open(nullptr), preview(nullptr), + gotoMenu(nullptr) { } }; @@ -438,28 +443,33 @@ private: void refreshFiles(); QTreeWidgetItem* createOverwriteItem( - bool archive, const QString& fileName, const QString& relativeName, + FileEntry::Index index, bool archive, + const QString& fileName, const QString& relativeName, const MOShared::FileEntry::AlternativesVector& alternatives); QTreeWidgetItem* createNoConflictItem( - bool archive, const QString& fileName, const QString& relativeName); + FileEntry::Index index, bool archive, + const QString& fileName, const QString& relativeName); QTreeWidgetItem* createOverwrittenItem( - int fileOrigin, bool archive, + FileEntry::Index index, int fileOrigin, bool archive, const QString& fileName, const QString& relativeName); QTreeWidgetItem* createAdvancedConflictItem( - int fileOrigin, bool archive, + FileEntry::Index index, int fileOrigin, bool archive, const QString& fileName, const QString& relativeName, const MOShared::FileEntry::AlternativesVector& alternatives); void setConflictItem( - QTreeWidgetItem* item, - const QString& fileName, const QString& origin, bool archive) const; + QTreeWidgetItem* item, FileEntry::Index index, + const QString& fileName, bool hasAltOrigins, const QString& altOrigin, + bool archive) const; QString conflictFileName(const QTreeWidgetItem* conflictItem) const; - QString conflictOrigin(const QTreeWidgetItem* conflictItem) const; + QString conflictAltOrigin(const QTreeWidgetItem* conflictItem) const; + bool conflictHasAlts(const QTreeWidgetItem* conflictItem) const; bool conflictIsArchive(const QTreeWidgetItem* conflictItem) const; + FileEntry::Index conflictFileIndex(const QTreeWidgetItem* conflictItem) const; void restoreTabState(const QByteArray &state); void restoreConflictsState(const QByteArray &state); @@ -487,7 +497,10 @@ private: void showConflictMenu(const QPoint &pos, QTreeWidget* tree); ConflictActions createConflictMenuActions( - const QList selection); + const QList& selection); + + std::vector createGotoActions( + const QList& selection); }; #endif // MODINFODIALOG_H diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 1179110a..bde515a9 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -220,6 +220,11 @@ std::vector FilesOrigin::getFiles() const return result; } +FileEntry::Ptr FilesOrigin::findFile(FileEntry::Index index) const +{ + return m_FileRegister.lock()->getFile(index); +} + bool FilesOrigin::containsArchive(std::wstring archiveName) { for (FileEntry::Index fileIdx : m_Files) diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index e7af1ae7..785c3ff6 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -135,6 +135,7 @@ public: const std::wstring &getPath() const { return m_Path; } std::vector getFiles() const; + FileEntry::Ptr findFile(FileEntry::Index index) const; void enable(bool enabled, time_t notAfter = LONG_MAX); bool isDisabled() const { return m_Disabled; } -- cgit v1.3.1 From d2eb890f2b9df13c402db6adeaafa7e3f4a7d736 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 May 2019 17:28:59 -0400 Subject: refresh files in the constructor because the ui is used to determine the tab states --- src/modinfodialog.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 60cf7578..5d2dd811 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -399,6 +399,12 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo } } + // refresh everything but the conflict lists, which are done in exec() because + // they depend on restoring the state to some widgets; this refresh has to be + // done here because some of the checks below depend on the ui to decide which + // tabs to enable + refreshFiles(); + if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR)) { ui->tabWidget->setTabEnabled(TAB_TEXTFILES, false); @@ -503,7 +509,8 @@ ModInfoDialog::~ModInfoDialog() int ModInfoDialog::exec() { - refreshLists(); + // no need to refresh the other stuff, that was done in the constructor + refreshConflictLists(true, true); return TutorableDialog::exec(); } -- cgit v1.3.1